Merge remote-tracking branch 'Espeon/minecraft' into Archipelago_Main
This commit is contained in:
commit
8030db03ad
|
@ -894,13 +894,15 @@ class CollectionState(object):
|
||||||
return self.fortress_loot(player) and normal_kill
|
return self.fortress_loot(player) and normal_kill
|
||||||
|
|
||||||
def can_kill_ender_dragon(self, player: int):
|
def can_kill_ender_dragon(self, player: int):
|
||||||
|
# Since it is possible to kill the dragon without getting any of the advancements related to it, we need to require that it can be respawned.
|
||||||
|
respawn_dragon = self.can_reach('The Nether', 'Region', player) and self.has('Ingot Crafting', player)
|
||||||
if self.combat_difficulty(player) == 'easy':
|
if self.combat_difficulty(player) == 'easy':
|
||||||
return self.has("Progressive Weapons", player, 3) and self.has("Progressive Armor", player, 2) and self.has('Archery', player) and \
|
return respawn_dragon and self.has("Progressive Weapons", player, 3) and self.has("Progressive Armor", player, 2) and \
|
||||||
self.can_brew_potions(player) and self.can_enchant(player)
|
self.has('Archery', player) and self.can_brew_potions(player) and self.can_enchant(player)
|
||||||
if self.combat_difficulty(player) == 'hard':
|
if self.combat_difficulty(player) == 'hard':
|
||||||
return (self.has('Progressive Weapons', player, 2) and self.has('Progressive Armor', player)) or \
|
return respawn_dragon and ((self.has('Progressive Weapons', player, 2) and self.has('Progressive Armor', player)) or \
|
||||||
(self.has('Progressive Weapons', player, 1) and self.has('Bed', player))
|
(self.has('Progressive Weapons', player, 1) and self.has('Bed', player)))
|
||||||
return self.has('Progressive Weapons', player, 2) and self.has('Progressive Armor', player) and self.has('Archery', player)
|
return respawn_dragon and self.has('Progressive Weapons', player, 2) and self.has('Progressive Armor', player) and self.has('Archery', player)
|
||||||
|
|
||||||
|
|
||||||
def collect(self, item: Item, event: bool = False, location: Location = None) -> bool:
|
def collect(self, item: Item, event: bool = False, location: Location = None) -> bool:
|
||||||
|
|
12
Main.py
12
Main.py
|
@ -21,8 +21,6 @@ from Fill import distribute_items_restrictive, flood_items, balance_multiworld_p
|
||||||
from worlds.alttp.Shops import create_shops, ShopSlotFill, SHOP_ID_START, total_shop_slots, FillDisabledShopSlots
|
from worlds.alttp.Shops import create_shops, ShopSlotFill, SHOP_ID_START, total_shop_slots, FillDisabledShopSlots
|
||||||
from worlds.alttp.ItemPool import generate_itempool, difficulties, fill_prizes
|
from worlds.alttp.ItemPool import generate_itempool, difficulties, fill_prizes
|
||||||
from Utils import output_path, parse_player_names, get_options, __version__, version_tuple
|
from Utils import output_path, parse_player_names, get_options, __version__, version_tuple
|
||||||
from worlds.minecraft import gen_minecraft, fill_minecraft_slot_data, generate_mc_data
|
|
||||||
from worlds.minecraft.Regions import minecraft_create_regions
|
|
||||||
from worlds.generic.Rules import locality_rules
|
from worlds.generic.Rules import locality_rules
|
||||||
from worlds import Games, lookup_any_item_name_to_id, AutoWorld
|
from worlds import Games, lookup_any_item_name_to_id, AutoWorld
|
||||||
import Patch
|
import Patch
|
||||||
|
@ -196,9 +194,6 @@ def main(args, seed=None):
|
||||||
|
|
||||||
AutoWorld.call_all(world, "create_regions")
|
AutoWorld.call_all(world, "create_regions")
|
||||||
|
|
||||||
for player in world.minecraft_player_ids:
|
|
||||||
minecraft_create_regions(world, player)
|
|
||||||
|
|
||||||
for player in world.alttp_player_ids:
|
for player in world.alttp_player_ids:
|
||||||
if world.open_pyramid[player] == 'goal':
|
if world.open_pyramid[player] == 'goal':
|
||||||
world.open_pyramid[player] = world.goal[player] in {'crystals', 'ganontriforcehunt',
|
world.open_pyramid[player] = world.goal[player] in {'crystals', 'ganontriforcehunt',
|
||||||
|
@ -260,9 +255,6 @@ def main(args, seed=None):
|
||||||
|
|
||||||
AutoWorld.call_all(world, "generate_basic")
|
AutoWorld.call_all(world, "generate_basic")
|
||||||
|
|
||||||
for player in world.minecraft_player_ids:
|
|
||||||
gen_minecraft(world, player)
|
|
||||||
|
|
||||||
logger.info("Running Item Plando")
|
logger.info("Running Item Plando")
|
||||||
|
|
||||||
for item in world.itempool:
|
for item in world.itempool:
|
||||||
|
@ -511,7 +503,7 @@ def main(args, seed=None):
|
||||||
for slot in world.hk_player_ids:
|
for slot in world.hk_player_ids:
|
||||||
slot_data[slot] = AutoWorld.call_single(world, "fill_slot_data", slot)
|
slot_data[slot] = AutoWorld.call_single(world, "fill_slot_data", slot)
|
||||||
for slot in world.minecraft_player_ids:
|
for slot in world.minecraft_player_ids:
|
||||||
slot_data[slot] = fill_minecraft_slot_data(world, slot)
|
slot_data[slot] = AutoWorld.call_single(world, "fill_slot_data", slot)
|
||||||
|
|
||||||
locations_data: Dict[int, Dict[int, Tuple[int, int]]] = {player: {} for player in world.player_ids}
|
locations_data: Dict[int, Dict[int, Tuple[int, int]]] = {player: {} for player in world.player_ids}
|
||||||
for location in world.get_filled_locations():
|
for location in world.get_filled_locations():
|
||||||
|
@ -563,8 +555,6 @@ def main(args, seed=None):
|
||||||
if multidata_task:
|
if multidata_task:
|
||||||
multidata_task.result() # retrieve exception if one exists
|
multidata_task.result() # retrieve exception if one exists
|
||||||
pool.shutdown() # wait for all queued tasks to complete
|
pool.shutdown() # wait for all queued tasks to complete
|
||||||
for player in world.minecraft_player_ids: # Doing this after shutdown prevents the .apmc from being generated if there's an error
|
|
||||||
generate_mc_data(world, player)
|
|
||||||
if not args.skip_playthrough:
|
if not args.skip_playthrough:
|
||||||
logger.info('Calculating playthrough.')
|
logger.info('Calculating playthrough.')
|
||||||
create_playthrough(world)
|
create_playthrough(world)
|
||||||
|
|
|
@ -175,6 +175,9 @@ class Range(Option, int):
|
||||||
return cls(data)
|
return cls(data)
|
||||||
return cls.from_text(str(data))
|
return cls.from_text(str(data))
|
||||||
|
|
||||||
|
def get_option_name(self):
|
||||||
|
return str(self.value)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.value)
|
return str(self.value)
|
||||||
|
|
||||||
|
|
|
@ -102,10 +102,7 @@ Factorio:
|
||||||
burner-mining-drill: 19
|
burner-mining-drill: 19
|
||||||
stone-furnace: 19
|
stone-furnace: 19
|
||||||
Minecraft:
|
Minecraft:
|
||||||
advancement_goal: # Number of advancements required (out of 92 total) to spawn the Ender Dragon and complete the game.
|
advancement_goal: 50 # Number of advancements required (out of 92 total) to spawn the Ender Dragon and complete the game.
|
||||||
few: 0 # 30 advancements
|
|
||||||
normal: 1 # 50
|
|
||||||
many: 0 # 70
|
|
||||||
combat_difficulty: # Modifies the level of items logically required for exploring dangerous areas and fighting bosses.
|
combat_difficulty: # Modifies the level of items logically required for exploring dangerous areas and fighting bosses.
|
||||||
easy: 0
|
easy: 0
|
||||||
normal: 1
|
normal: 1
|
||||||
|
@ -119,7 +116,7 @@ Minecraft:
|
||||||
include_postgame_advancements: # Some advancements require defeating the Ender Dragon; this will junk-fill them so you won't have to finish to send some items.
|
include_postgame_advancements: # Some advancements require defeating the Ender Dragon; this will junk-fill them so you won't have to finish to send some items.
|
||||||
on: 0
|
on: 0
|
||||||
off: 1
|
off: 1
|
||||||
shuffle_structures: # CURRENTLY DISABLED; enables shuffling of villages, outposts, fortresses, bastions, and end cities.
|
shuffle_structures: # Enables shuffling of villages, outposts, fortresses, bastions, and end cities.
|
||||||
on: 0
|
on: 0
|
||||||
off: 1
|
off: 1
|
||||||
A Link to the Past:
|
A Link to the Past:
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import worlds.minecraft.Options
|
import worlds.minecraft.Options
|
||||||
from test.TestBase import TestBase
|
from test.TestBase import TestBase
|
||||||
from BaseClasses import MultiWorld
|
from BaseClasses import MultiWorld
|
||||||
from worlds.minecraft import minecraft_gen_item_pool
|
from worlds import AutoWorld
|
||||||
from worlds.minecraft.Regions import minecraft_create_regions, link_minecraft_structures
|
from worlds.minecraft import MinecraftWorld
|
||||||
from worlds.minecraft.Rules import set_rules
|
|
||||||
from worlds.minecraft.Items import MinecraftItem, item_table
|
from worlds.minecraft.Items import MinecraftItem, item_table
|
||||||
import Options
|
from worlds.minecraft.Options import AdvancementGoal, CombatDifficulty
|
||||||
|
|
||||||
# Converts the name of an item into an item object
|
# Converts the name of an item into an item object
|
||||||
def MCItemFactory(items, player: int):
|
def MCItemFactory(items, player: int):
|
||||||
|
@ -29,16 +28,16 @@ class TestMinecraft(TestBase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.world = MultiWorld(1)
|
self.world = MultiWorld(1)
|
||||||
self.world.game[1] = "Minecraft"
|
self.world.game[1] = "Minecraft"
|
||||||
|
self.world.worlds[1] = MinecraftWorld(self.world, 1)
|
||||||
exclusion_pools = ['hard', 'insane', 'postgame']
|
exclusion_pools = ['hard', 'insane', 'postgame']
|
||||||
for pool in exclusion_pools:
|
for pool in exclusion_pools:
|
||||||
setattr(self.world, f"include_{pool}_advancements", [False, False])
|
setattr(self.world, f"include_{pool}_advancements", [False, False])
|
||||||
setattr(self.world, "advancement_goal", [0, worlds.minecraft.Options.AdvancementGoal(value=0)])
|
setattr(self.world, "advancement_goal", {1: AdvancementGoal(30)})
|
||||||
setattr(self.world, "shuffle_structures", [False, False])
|
setattr(self.world, "shuffle_structures", {1: False})
|
||||||
setattr(self.world, "combat_difficulty", [0, worlds.minecraft.Options.CombatDifficulty(value=1)])
|
setattr(self.world, "combat_difficulty", {1: CombatDifficulty(1)}) # normal
|
||||||
minecraft_create_regions(self.world, 1)
|
AutoWorld.call_single(self.world, "create_regions", 1)
|
||||||
link_minecraft_structures(self.world, 1)
|
AutoWorld.call_single(self.world, "generate_basic", 1)
|
||||||
minecraft_gen_item_pool(self.world, 1)
|
AutoWorld.call_single(self.world, "set_rules", 1)
|
||||||
set_rules(self.world, 1)
|
|
||||||
|
|
||||||
def _get_items(self, item_pool, all_except):
|
def _get_items(self, item_pool, all_except):
|
||||||
if all_except and len(all_except) > 0:
|
if all_except and len(all_except) > 0:
|
||||||
|
|
|
@ -32,7 +32,7 @@ assert len(lookup_any_location_name_to_id) == len(lookup_any_location_id_to_name
|
||||||
|
|
||||||
network_data_package = {"lookup_any_location_id_to_name": lookup_any_location_id_to_name,
|
network_data_package = {"lookup_any_location_id_to_name": lookup_any_location_id_to_name,
|
||||||
"lookup_any_item_id_to_name": lookup_any_item_id_to_name,
|
"lookup_any_item_id_to_name": lookup_any_item_id_to_name,
|
||||||
"version": 6}
|
"version": 7}
|
||||||
|
|
||||||
|
|
||||||
@enum.unique
|
@enum.unique
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from BaseClasses import Region, Entrance, Location, MultiWorld, Item
|
from BaseClasses import Item
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
class ItemData(typing.NamedTuple):
|
class ItemData(typing.NamedTuple):
|
||||||
|
@ -46,6 +46,7 @@ item_table = {
|
||||||
"8 Gold Ore": ItemData(45032, False),
|
"8 Gold Ore": ItemData(45032, False),
|
||||||
"Rotten Flesh": ItemData(45033, False),
|
"Rotten Flesh": ItemData(45033, False),
|
||||||
"Single Arrow": ItemData(45034, False),
|
"Single Arrow": ItemData(45034, False),
|
||||||
|
"Bee Trap (Minecraft)": ItemData(45100, False),
|
||||||
|
|
||||||
"Victory": ItemData(0, True)
|
"Victory": ItemData(0, True)
|
||||||
}
|
}
|
||||||
|
@ -67,8 +68,9 @@ item_frequencies = {
|
||||||
"4 Lapis Lazuli": 2,
|
"4 Lapis Lazuli": 2,
|
||||||
"16 Porkchops": 8,
|
"16 Porkchops": 8,
|
||||||
"8 Gold Ore": 4,
|
"8 Gold Ore": 4,
|
||||||
"Rotten Flesh": 4,
|
"Rotten Flesh": 2,
|
||||||
"Single Arrow": 0
|
"Single Arrow": 0,
|
||||||
|
"Bee Trap (Minecraft)": 2
|
||||||
}
|
}
|
||||||
|
|
||||||
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in item_table.items() if data.code}
|
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in item_table.items() if data.code}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from BaseClasses import Region, Entrance, Location, MultiWorld, Item
|
from BaseClasses import Location
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
class AdvData(typing.NamedTuple):
|
class AdvData(typing.NamedTuple):
|
||||||
|
@ -114,6 +114,7 @@ exclusion_table = {
|
||||||
"Two by Two": "100 XP",
|
"Two by Two": "100 XP",
|
||||||
"Two Birds, One Arrow": "50 XP",
|
"Two Birds, One Arrow": "50 XP",
|
||||||
"Arbalistic": "100 XP",
|
"Arbalistic": "100 XP",
|
||||||
|
"Monsters Hunted": "100 XP",
|
||||||
"Beaconator": "50 XP",
|
"Beaconator": "50 XP",
|
||||||
"A Balanced Diet": "100 XP",
|
"A Balanced Diet": "100 XP",
|
||||||
"Uneasy Alliance": "100 XP",
|
"Uneasy Alliance": "100 XP",
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
import typing
|
import typing
|
||||||
|
from Options import Choice, Option, Toggle, Range
|
||||||
from Options import Choice, Option, Toggle
|
|
||||||
|
|
||||||
|
|
||||||
class AdvancementGoal(Choice):
|
class AdvancementGoal(Range):
|
||||||
option_few = 0
|
range_start = 0
|
||||||
option_normal = 1
|
range_end = 87
|
||||||
option_many = 2
|
default = 50
|
||||||
default = 1
|
|
||||||
|
|
||||||
|
|
||||||
class CombatDifficulty(Choice):
|
class CombatDifficulty(Choice):
|
||||||
|
|
|
@ -1,73 +1,44 @@
|
||||||
from .Locations import MinecraftAdvancement, advancement_table
|
|
||||||
|
|
||||||
from BaseClasses import Region, Entrance, Location, MultiWorld, Item
|
def link_minecraft_structures(world, player):
|
||||||
|
|
||||||
def minecraft_create_regions(world: MultiWorld, player: int):
|
|
||||||
|
|
||||||
def MCRegion(region_name: str, exits=[]):
|
|
||||||
ret = Region(region_name, None, region_name, player)
|
|
||||||
ret.world = world
|
|
||||||
ret.locations = [ MinecraftAdvancement(player, loc_name, loc_data.id, ret)
|
|
||||||
for loc_name, loc_data in advancement_table.items()
|
|
||||||
if loc_data.region == region_name ]
|
|
||||||
for exit in exits:
|
|
||||||
ret.exits.append(Entrance(player, exit, ret))
|
|
||||||
return ret
|
|
||||||
|
|
||||||
world.regions += [MCRegion(*r) for r in mc_regions]
|
|
||||||
|
|
||||||
|
# Link mandatory connections first
|
||||||
for (exit, region) in mandatory_connections:
|
for (exit, region) in mandatory_connections:
|
||||||
world.get_entrance(exit, player).connect(world.get_region(region, player))
|
world.get_entrance(exit, player).connect(world.get_region(region, player))
|
||||||
|
|
||||||
def link_minecraft_structures(world: MultiWorld, player: int):
|
|
||||||
|
|
||||||
# Get all unpaired exits and all regions without entrances (except the Menu)
|
# Get all unpaired exits and all regions without entrances (except the Menu)
|
||||||
# This function is destructive on these lists.
|
# This function is destructive on these lists.
|
||||||
exits = [exit.name for r in world.regions if r.player == player for exit in r.exits if exit.connected_region == None]
|
exits = [exit.name for r in world.regions if r.player == player for exit in r.exits if exit.connected_region == None]
|
||||||
structs = [r.name for r in world.regions if r.player == player and r.entrances == [] and r.name != 'Menu']
|
structs = [r.name for r in world.regions if r.player == player and r.entrances == [] and r.name != 'Menu']
|
||||||
|
exits_spoiler = exits[:] # copy the original order for the spoiler log
|
||||||
try:
|
try:
|
||||||
assert len(exits) == len(structs)
|
assert len(exits) == len(structs)
|
||||||
except AssertionError as e: # this should never happen
|
except AssertionError as e: # this should never happen
|
||||||
raise Exception(f"Could not obtain equal numbers of Minecraft exits and structures for player {player}") from e
|
raise Exception(f"Could not obtain equal numbers of Minecraft exits and structures for player {player} ({world.player_names[player]})")
|
||||||
num_regions = len(exits)
|
num_regions = len(exits)
|
||||||
pairs = {}
|
pairs = {}
|
||||||
|
|
||||||
def check_valid_connection(exit, struct):
|
|
||||||
if (exit in exits) and (struct in structs) and (exit not in pairs):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def set_pair(exit, struct):
|
def set_pair(exit, struct):
|
||||||
try:
|
if (exit in exits) and (struct in structs) and (exit not in illegal_connections.get(struct, [])):
|
||||||
assert exit in exits
|
pairs[exit] = struct
|
||||||
assert struct in structs
|
exits.remove(exit)
|
||||||
except AssertionError as e:
|
structs.remove(struct)
|
||||||
raise Exception(f"Invalid connection: {exit} => {struct} for player {player}")
|
else:
|
||||||
pairs[exit] = struct
|
raise Exception(f"Invalid connection: {exit} => {struct} for player {player} ({world.player_names[player]})")
|
||||||
exits.remove(exit)
|
|
||||||
structs.remove(struct)
|
|
||||||
|
|
||||||
# Plando stuff. Remove any utilized exits/structs from the lists.
|
# Connect plando structures first
|
||||||
# Raise error if trying to put Nether Fortress in the End.
|
|
||||||
if world.plando_connections[player]:
|
if world.plando_connections[player]:
|
||||||
for connection in world.plando_connections[player]:
|
for conn in world.plando_connections[player]:
|
||||||
try:
|
set_pair(conn.entrance, conn.exit)
|
||||||
if connection.entrance == 'The End Structure' and connection.exit == 'Nether Fortress':
|
|
||||||
raise Exception(f"Cannot place Nether Fortress in the End for player {player}")
|
|
||||||
set_pair(connection.entrance, connection.exit)
|
|
||||||
except Exception as e:
|
|
||||||
raise Exception(f"Could not connect using {connection}") from e
|
|
||||||
|
|
||||||
|
# The algorithm tries to place the most restrictive structures first. This algorithm always works on the
|
||||||
|
# relatively small set of restrictions here, but does not work on all possible inputs with valid configurations.
|
||||||
if world.shuffle_structures[player]:
|
if world.shuffle_structures[player]:
|
||||||
# Can't put Nether Fortress in the End
|
structs.sort(reverse=True, key=lambda s: len(illegal_connections.get(s, [])))
|
||||||
if 'The End Structure' in exits and 'Nether Fortress' in structs:
|
for struct in structs[:]:
|
||||||
try:
|
try:
|
||||||
end_struct = world.random.choice([s for s in structs if s != 'Nether Fortress'])
|
exit = world.random.choice([e for e in exits if e not in illegal_connections.get(struct, [])])
|
||||||
set_pair('The End Structure', end_struct)
|
except IndexError:
|
||||||
except IndexError as e: # should only happen if structs is emptied by plando
|
raise Exception(f"No valid structure placements remaining for player {player} ({world.player_names[player]})")
|
||||||
raise Exception(f"Plando forced Nether Fortress in the End for player {player}") from e
|
|
||||||
world.random.shuffle(structs)
|
|
||||||
for exit, struct in zip(exits[:], structs[:]):
|
|
||||||
set_pair(exit, struct)
|
set_pair(exit, struct)
|
||||||
else: # write remaining default connections
|
else: # write remaining default connections
|
||||||
for (exit, struct) in default_connections:
|
for (exit, struct) in default_connections:
|
||||||
|
@ -77,13 +48,15 @@ def link_minecraft_structures(world: MultiWorld, player: int):
|
||||||
# Make sure we actually paired everything; might fail if plando
|
# Make sure we actually paired everything; might fail if plando
|
||||||
try:
|
try:
|
||||||
assert len(exits) == len(structs) == 0
|
assert len(exits) == len(structs) == 0
|
||||||
except AssertionError as e:
|
except AssertionError:
|
||||||
raise Exception(f"Failed to connect all Minecraft structures for player {player}; check plando settings in yaml") from e
|
raise Exception(f"Failed to connect all Minecraft structures for player {player} ({world.player_names[player]})")
|
||||||
|
|
||||||
|
for exit in exits_spoiler:
|
||||||
|
world.get_entrance(exit, player).connect(world.get_region(pairs[exit], player))
|
||||||
|
if world.shuffle_structures[player] or world.plando_connections[player]:
|
||||||
|
world.spoiler.set_entrance(exit, pairs[exit], 'entrance', player)
|
||||||
|
|
||||||
|
|
||||||
for exit, struct in pairs.items():
|
|
||||||
world.get_entrance(exit, player).connect(world.get_region(struct, player))
|
|
||||||
if world.shuffle_structures[player]:
|
|
||||||
world.spoiler.set_entrance(exit, struct, 'entrance', player)
|
|
||||||
|
|
||||||
# (Region name, list of exits)
|
# (Region name, list of exits)
|
||||||
mc_regions = [
|
mc_regions = [
|
||||||
|
@ -112,3 +85,9 @@ default_connections = {
|
||||||
('Nether Structure 2', 'Bastion Remnant'),
|
('Nether Structure 2', 'Bastion Remnant'),
|
||||||
('The End Structure', 'End City')
|
('The End Structure', 'End City')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Structure: illegal locations
|
||||||
|
illegal_connections = {
|
||||||
|
'Nether Fortress': ['The End Structure']
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,26 +14,19 @@ def set_rules(world: MultiWorld, player: int):
|
||||||
(location.name not in postgame_advancements) and
|
(location.name not in postgame_advancements) and
|
||||||
location.can_reach(state)]
|
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.
|
# 92 total advancements. Goal is to complete X advancements and then Free the End.
|
||||||
goal_map = {
|
# There are 5 advancements which cannot be included for dragon spawning (4 postgame, Free the End)
|
||||||
'few': 30,
|
# Hence the true maximum is (92 - 5) = 87
|
||||||
'normal': 50,
|
goal = int(world.advancement_goal[player].value)
|
||||||
'many': 70
|
can_complete = lambda state: len(reachable_locations(state)) >= goal and state.can_reach('The End', 'Region', player) and state.can_kill_ender_dragon(player)
|
||||||
}
|
|
||||||
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':
|
if world.logic[player] != 'nologic':
|
||||||
world.completion_condition[player] = lambda state: state.has('Victory', player)
|
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
|
set_rule(world.get_entrance("Nether Portal", player), lambda state: state.has('Flint and Steel', player) and
|
||||||
(state.has('Bucket', player) or state.has(
|
(state.has('Bucket', player) or state.has('Progressive Tools', player, 3)) and
|
||||||
'Progressive Tools', player, 3)) and
|
state.has_iron_ingots(player))
|
||||||
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 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("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 1", player), lambda state: state.can_adventure(player))
|
||||||
|
@ -44,158 +37,98 @@ 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("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("Oh Shiny", player), lambda state: state.can_piglin_trade(player))
|
||||||
set_rule(world.get_location("Suit Up", player),
|
set_rule(world.get_location("Suit Up", player), lambda state: state.has("Progressive Armor", player) and state.has_iron_ingots(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 \
|
||||||
set_rule(world.get_location("Very Very Frightening", player),
|
((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
|
||||||
lambda state: state.has("Channeling Book", player) and state.can_use_anvil(player) and state.can_enchant(
|
set_rule(world.get_location("Hot Stuff", player), lambda state: state.has("Bucket", player) and state.has_iron_ingots(player))
|
||||||
player) and \
|
set_rule(world.get_location("Free the End", player), lambda state: can_complete(state))
|
||||||
((world.get_region('Village', player).entrances[
|
set_rule(world.get_location("A Furious Cocktail", player), lambda state: state.can_brew_potions(player) and
|
||||||
0].parent_region.name != 'The End' and state.can_reach('Village', 'Region',
|
state.has("Fishing Rod", player) and # Water Breathing
|
||||||
player)) or state.can_reach(
|
state.can_reach('The Nether', 'Region', player) and # Regeneration, Fire Resistance, gold nuggets
|
||||||
'Zombie Doctor', 'Location',
|
state.can_reach('Village', 'Region', player) and # Night Vision, Invisibility
|
||||||
player))) # need villager into the overworld for lightning strike
|
state.can_reach('Bring Home the Beacon', 'Location', player)) # Resistance
|
||||||
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("Best Friends Forever", player), lambda state: True)
|
||||||
set_rule(world.get_location("Bring Home the Beacon", player),
|
set_rule(world.get_location("Bring Home the Beacon", player), lambda state: state.can_kill_wither(player) and
|
||||||
lambda state: state.can_kill_wither(player) and state.has_diamond_pickaxe(player) and
|
state.has_diamond_pickaxe(player) and state.has("Ingot Crafting", player) and state.has("Resource Blocks", player))
|
||||||
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("Not Today, Thank You", 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))
|
||||||
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("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("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("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("Hot Tourist Destinations", player), lambda state: True)
|
||||||
set_rule(world.get_location("This Boat Has Legs", 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))
|
||||||
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("Sniper Duel", player), lambda state: state.has("Archery", player))
|
||||||
set_rule(world.get_location("Nether", player), lambda state: True)
|
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("Great View From Up Here", player), lambda state: state.basic_combat(player))
|
||||||
set_rule(world.get_location("How Did We Get Here?", player),
|
set_rule(world.get_location("How Did We Get Here?", player), lambda state: state.can_brew_potions(player) and
|
||||||
lambda state: state.can_brew_potions(player) and state.has_gold_ingots(
|
state.has_gold_ingots(player) and # Absorption
|
||||||
player) and # most effects; Absorption
|
state.can_reach('End City', 'Region', player) and # Levitation
|
||||||
state.can_reach('End City', 'Region', player) and state.can_reach('The Nether', 'Region',
|
state.can_reach('The Nether', 'Region', player) and # potion ingredients
|
||||||
player) and # Levitation; potion ingredients
|
state.has("Fishing Rod", player) and state.has("Archery",player) and # Pufferfish, Nautilus Shells; spectral arrows
|
||||||
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("Bring Home the Beacon", "Location", player) and # Haste
|
||||||
state.can_reach("Hero of the Village", "Location", player)) # Bad Omen, Hero of the Village
|
state.can_reach("Hero of the Village", "Location", player)) # Bad Omen, Hero of the Village
|
||||||
set_rule(world.get_location("Bullseye", player),
|
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))
|
||||||
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("Spooky Scary Skeleton", player), lambda state: state.basic_combat(player))
|
||||||
set_rule(world.get_location("Two by Two", 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
|
||||||
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("Stone Age", player), lambda state: True)
|
||||||
set_rule(world.get_location("Two Birds, One Arrow", player),
|
set_rule(world.get_location("Two Birds, One Arrow", player), lambda state: state.craft_crossbow(player) and state.can_enchant(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("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("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("Getting an Upgrade", player), lambda state: state.has("Progressive Tools", player))
|
||||||
set_rule(world.get_location("Tactical Fishing", player),
|
set_rule(world.get_location("Tactical Fishing", player), lambda state: state.has("Bucket", player) and state.has_iron_ingots(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("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("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("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("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("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("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("Take Aim", player), lambda state: state.has("Archery", player))
|
||||||
set_rule(world.get_location("Total Beelocation", 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))
|
||||||
lambda state: state.has("Silk Touch Book", player) and state.can_use_anvil(player) and state.can_enchant(
|
set_rule(world.get_location("Arbalistic", player), lambda state: state.craft_crossbow(player) and state.has("Piercing IV Book", player) and
|
||||||
player))
|
state.can_use_anvil(player) and state.can_enchant(player))
|
||||||
set_rule(world.get_location("Arbalistic", player),
|
set_rule(world.get_location("The End... Again...", player), lambda state: can_complete(state))
|
||||||
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("Acquire Hardware", player), lambda state: state.has_iron_ingots(player))
|
||||||
set_rule(world.get_location("Not Quite \"Nine\" Lives", player),
|
set_rule(world.get_location("Not Quite \"Nine\" Lives", player), lambda state: state.can_piglin_trade(player) and state.has("Resource Blocks", 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("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("Sky's the Limit", player), lambda state: state.basic_combat(player))
|
||||||
set_rule(world.get_location("Hired Help", player),
|
set_rule(world.get_location("Hired Help", player), lambda state: state.has("Resource Blocks", player) and state.has_iron_ingots(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("Return to Sender", player), lambda state: True)
|
||||||
set_rule(world.get_location("Sweet Dreams", player),
|
set_rule(world.get_location("Sweet Dreams", player), lambda state: state.has("Bed", player) or state.can_reach('Village', 'Region', 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("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("Adventure", player), lambda state: True)
|
||||||
set_rule(world.get_location("Monsters Hunted", player),
|
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
|
||||||
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("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("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("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("The End", player), lambda state: True)
|
||||||
set_rule(world.get_location("Serious Dedication", 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))
|
||||||
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("Postmortal", player), lambda state: state.complete_raid(player))
|
||||||
set_rule(world.get_location("Monster Hunter", player), lambda state: True)
|
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("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("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("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("Hero of the Village", player), lambda state: state.complete_raid(player))
|
||||||
set_rule(world.get_location("Hidden in the Depths", 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 :)
|
||||||
lambda state: state.can_brew_potions(player) and state.has("Bed", player) and state.has_diamond_pickaxe(
|
set_rule(world.get_location("Beaconator", player), lambda state: state.can_kill_wither(player) and state.has_diamond_pickaxe(player) and
|
||||||
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))
|
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("Withering Heights", player), lambda state: state.can_kill_wither(player))
|
||||||
set_rule(world.get_location("A Balanced Diet", 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
|
||||||
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
|
||||||
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("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("Husbandry", player), lambda state: True)
|
||||||
set_rule(world.get_location("Country Lode, Take Me Home", 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))
|
||||||
lambda state: state.can_reach("Hidden in the Depths", "Location", player) and state.has_gold_ingots(
|
set_rule(world.get_location("Bee Our Guest", player), lambda state: state.has("Campfire", player) and state.has_bottle_mc(player))
|
||||||
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("What a Deal!", player), lambda state: True)
|
||||||
set_rule(world.get_location("Uneasy Alliance", player),
|
set_rule(world.get_location("Uneasy Alliance", player), lambda state: state.has_diamond_pickaxe(player) and state.has('Fishing Rod', 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("Diamonds!", player),
|
set_rule(world.get_location("A Terrible Fortress", player), lambda state: True) # since you don't have to fight anything
|
||||||
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("A Throwaway Joke", player), lambda state: True) # kill drowned
|
||||||
set_rule(world.get_location("Minecraft", player), lambda state: True)
|
set_rule(world.get_location("Minecraft", player), lambda state: True)
|
||||||
set_rule(world.get_location("Sticky Situation", player),
|
set_rule(world.get_location("Sticky Situation", player), lambda state: state.has("Campfire", player) and state.has_bottle_mc(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("Ol' Betsy", player), lambda state: state.craft_crossbow(player))
|
||||||
set_rule(world.get_location("Cover Me in Debris", player),
|
set_rule(world.get_location("Cover Me in Debris", player), lambda state: state.has("Progressive Armor", player, 2) and
|
||||||
lambda state: state.has("Progressive Armor", player, 2) and
|
|
||||||
state.has("8 Netherite Scrap", player, 2) and state.has("Ingot Crafting", player) 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",
|
state.can_reach("Diamonds!", "Location", player) and state.can_reach("Hidden in the Depths", "Location", player))
|
||||||
"Location", player))
|
|
||||||
set_rule(world.get_location("The End?", player), lambda state: True)
|
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("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
|
||||||
|
@ -203,19 +136,13 @@ def set_rules(world: MultiWorld, player: int):
|
||||||
set_rule(world.get_location("Time to Mine!", 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("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("Bake Bread", player), lambda state: True)
|
||||||
set_rule(world.get_location("The Lie", player),
|
set_rule(world.get_location("The Lie", player), lambda state: state.has_iron_ingots(player) and state.has("Bucket", 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("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("Time to Strike!", player), lambda state: True)
|
||||||
set_rule(world.get_location("Cow Tipper", player), lambda state: True)
|
set_rule(world.get_location("Cow Tipper", player), lambda state: True)
|
||||||
set_rule(world.get_location("When Pigs Fly", player),
|
set_rule(world.get_location("When Pigs Fly", player), lambda state: (state.fortress_loot(player) or state.complete_raid(player)) and
|
||||||
lambda state: (state.fortress_loot(player) or state.complete_raid(player)) and state.has("Fishing Rod",
|
state.has("Fishing Rod", player) and state.can_adventure(player))
|
||||||
player) and state.can_adventure(
|
set_rule(world.get_location("Overkill", player), lambda state: state.can_brew_potions(player) and
|
||||||
player))
|
(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("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("Librarian", player), lambda state: state.has("Enchanting", player))
|
||||||
set_rule(world.get_location("Overpowered", player),
|
set_rule(world.get_location("Overpowered", player), lambda state: state.has("Resource Blocks", player) and state.has_gold_ingots(player))
|
||||||
lambda state: state.has("Resource Blocks", player) and state.has_gold_ingots(player))
|
|
||||||
|
|
|
@ -1,81 +1,92 @@
|
||||||
from .Items import MinecraftItem, item_table, item_frequencies
|
from .Items import MinecraftItem, item_table, item_frequencies
|
||||||
from .Locations import exclusion_table, events_table
|
from .Locations import MinecraftAdvancement, advancement_table, exclusion_table, events_table
|
||||||
from .Regions import link_minecraft_structures
|
from .Regions import mc_regions, link_minecraft_structures
|
||||||
from .Rules import set_rules
|
from .Rules import set_rules
|
||||||
|
|
||||||
from BaseClasses import MultiWorld
|
from BaseClasses import Region, Entrance
|
||||||
from .Options import minecraft_options
|
from .Options import minecraft_options
|
||||||
from ..AutoWorld import World
|
from ..AutoWorld import World
|
||||||
|
|
||||||
|
client_version = (0, 4)
|
||||||
|
|
||||||
class MinecraftWorld(World):
|
class MinecraftWorld(World):
|
||||||
game: str = "Minecraft"
|
game: str = "Minecraft"
|
||||||
options = minecraft_options
|
options = minecraft_options
|
||||||
|
|
||||||
|
|
||||||
client_version = (0, 3)
|
def _get_mc_data(self):
|
||||||
|
exits = ["Overworld Structure 1", "Overworld Structure 2", "Nether Structure 1", "Nether Structure 2",
|
||||||
|
"The End Structure"]
|
||||||
|
return {
|
||||||
|
'world_seed': self.world.slot_seeds[self.player].getrandbits(32),
|
||||||
|
# consistent and doesn't interfere with other generation
|
||||||
|
'seed_name': self.world.seed_name,
|
||||||
|
'player_name': self.world.get_player_names(self.player),
|
||||||
|
'player_id': self.player,
|
||||||
|
'client_version': client_version,
|
||||||
|
'structures': {exit: self.world.get_entrance(exit, self.player).connected_region.name for exit in exits}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_mc_data(world: MultiWorld, player: int):
|
def generate_basic(self):
|
||||||
exits = ["Overworld Structure 1", "Overworld Structure 2", "Nether Structure 1", "Nether Structure 2",
|
link_minecraft_structures(self.world, self.player)
|
||||||
"The End Structure"]
|
|
||||||
return {
|
pool = []
|
||||||
'world_seed': world.slot_seeds[player].getrandbits(32),
|
for item_name, item_data in item_table.items():
|
||||||
# consistent and doesn't interfere with other generation
|
for count in range(item_frequencies.get(item_name, 1)):
|
||||||
'seed_name': world.seed_name,
|
pool.append(MinecraftItem(item_name, item_data.progression, item_data.code, self.player))
|
||||||
'player_name': world.get_player_names(player),
|
|
||||||
'player_id': player,
|
prefill_pool = {}
|
||||||
'client_version': client_version,
|
prefill_pool.update(events_table)
|
||||||
'structures': {exit: world.get_entrance(exit, player).connected_region.name for exit in exits}
|
exclusion_pools = ['hard', 'insane', 'postgame']
|
||||||
}
|
for key in exclusion_pools:
|
||||||
|
if not getattr(self.world, f"include_{key}_advancements")[self.player]:
|
||||||
|
prefill_pool.update(exclusion_table[key])
|
||||||
|
|
||||||
|
for loc_name, item_name in prefill_pool.items():
|
||||||
|
item_data = item_table[item_name]
|
||||||
|
location = self.world.get_location(loc_name, self.player)
|
||||||
|
item = MinecraftItem(item_name, item_data.progression, item_data.code, self.player)
|
||||||
|
self.world.push_item(location, item, collect=False)
|
||||||
|
pool.remove(item)
|
||||||
|
location.event = item_data.progression
|
||||||
|
location.locked = True
|
||||||
|
|
||||||
|
self.world.itempool += pool
|
||||||
|
|
||||||
|
|
||||||
def generate_mc_data(world: MultiWorld, player: int):
|
def set_rules(self):
|
||||||
import base64, json
|
set_rules(self.world, self.player)
|
||||||
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):
|
def create_regions(self):
|
||||||
slot_data = get_mc_data(world, player)
|
def MCRegion(region_name: str, exits=[]):
|
||||||
for option_name in minecraft_options:
|
ret = Region(region_name, None, region_name, self.player)
|
||||||
option = getattr(world, option_name)[player]
|
ret.world = self.world
|
||||||
slot_data[option_name] = int(option.value)
|
ret.locations = [ MinecraftAdvancement(self.player, loc_name, loc_data.id, ret)
|
||||||
return slot_data
|
for loc_name, loc_data in advancement_table.items()
|
||||||
|
if loc_data.region == region_name ]
|
||||||
|
for exit in exits:
|
||||||
|
ret.exits.append(Entrance(self.player, exit, ret))
|
||||||
|
return ret
|
||||||
|
|
||||||
|
self.world.regions += [MCRegion(*r) for r in mc_regions]
|
||||||
|
|
||||||
|
|
||||||
# Generates the item pool given the table and frequencies in Items.py.
|
def generate_output(self):
|
||||||
def minecraft_gen_item_pool(world: MultiWorld, player: int):
|
import json
|
||||||
pool = []
|
from base64 import b64encode
|
||||||
for item_name, item_data in item_table.items():
|
from Utils import output_path
|
||||||
for count in range(item_frequencies.get(item_name, 1)):
|
|
||||||
pool.append(MinecraftItem(item_name, item_data.progression, item_data.code, player))
|
|
||||||
|
|
||||||
prefill_pool = {}
|
data = self._get_mc_data()
|
||||||
prefill_pool.update(events_table)
|
filename = f"AP_{self.world.seed_name}_P{self.player}_{self.world.get_player_names(self.player)}.apmc"
|
||||||
exclusion_pools = ['hard', 'insane', 'postgame']
|
with open(output_path(filename), 'wb') as f:
|
||||||
for key in exclusion_pools:
|
f.write(b64encode(bytes(json.dumps(data), 'utf-8')))
|
||||||
if not getattr(world, f"include_{key}_advancements")[player]:
|
|
||||||
prefill_pool.update(exclusion_table[key])
|
|
||||||
|
|
||||||
for loc_name, item_name in prefill_pool.items():
|
|
||||||
item_data = item_table[item_name]
|
|
||||||
location = world.get_location(loc_name, player)
|
|
||||||
item = MinecraftItem(item_name, item_data.progression, item_data.code, player)
|
|
||||||
world.push_item(location, item, collect=False)
|
|
||||||
pool.remove(item)
|
|
||||||
location.event = item_data.progression
|
|
||||||
location.locked = True
|
|
||||||
|
|
||||||
world.itempool += pool
|
|
||||||
|
|
||||||
|
|
||||||
# Generate Minecraft world.
|
def fill_slot_data(self):
|
||||||
def gen_minecraft(world: MultiWorld, player: int):
|
slot_data = self._get_mc_data()
|
||||||
link_minecraft_structures(world, player)
|
for option_name in minecraft_options:
|
||||||
minecraft_gen_item_pool(world, player)
|
option = getattr(self.world, option_name)[self.player]
|
||||||
set_rules(world, player)
|
slot_data[option_name] = int(option.value)
|
||||||
|
return slot_data
|
||||||
|
|
Loading…
Reference in New Issue