Merged in DR v0.5.1.0
This commit is contained in:
33
Main.py
33
Main.py
@@ -29,7 +29,7 @@ from Fill import sell_potions, sell_keys, balance_multiworld_progression, balanc
|
||||
from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops
|
||||
from Utils import output_path, parse_player_names
|
||||
|
||||
__version__ = '0.5.0.3-u'
|
||||
__version__ = '0.5.1.0-u'
|
||||
|
||||
from source.classes.BabelFish import BabelFish
|
||||
|
||||
@@ -255,7 +255,7 @@ def main(args, seed=None, fish=None):
|
||||
balance_multiworld_progression(world)
|
||||
|
||||
# if we only check for beatable, we can do this sanity check first before creating the rom
|
||||
if not world.can_beat_game():
|
||||
if not world.can_beat_game(log_error=True):
|
||||
raise RuntimeError(world.fish.translate("cli","cli","cannot.beat.game"))
|
||||
|
||||
for player in range(1, world.players+1):
|
||||
@@ -421,6 +421,8 @@ def copy_world(world):
|
||||
ret.owflutespots = world.owflutespots.copy()
|
||||
ret.prizes = world.prizes.copy()
|
||||
|
||||
ret.exp_cache = world.exp_cache.copy()
|
||||
|
||||
for player in range(1, world.players + 1):
|
||||
create_regions(ret, player)
|
||||
update_world_regions(ret, player)
|
||||
@@ -479,6 +481,7 @@ def copy_world(world):
|
||||
# these need to be modified properly by set_rules
|
||||
new_location.access_rule = lambda state: True
|
||||
new_location.item_rule = lambda state: True
|
||||
new_location.forced_item = location.forced_item
|
||||
|
||||
# copy remaining itempool. No item in itempool should have an assigned location
|
||||
for item in world.itempool:
|
||||
@@ -561,11 +564,11 @@ def create_playthrough(world):
|
||||
while sphere_candidates:
|
||||
state.sweep_for_events(key_only=True)
|
||||
|
||||
sphere = []
|
||||
sphere = set()
|
||||
# build up spheres of collection radius. Everything in each sphere is independent from each other in dependencies and only depends on lower spheres
|
||||
for location in sphere_candidates:
|
||||
if state.can_reach(location) and state.not_flooding_a_key(world, location):
|
||||
sphere.append(location)
|
||||
sphere.add(location)
|
||||
|
||||
for location in sphere:
|
||||
sphere_candidates.remove(location)
|
||||
@@ -586,21 +589,24 @@ def create_playthrough(world):
|
||||
|
||||
# in the second phase, we cull each sphere such that the game is still beatable, reducing each range of influence to the bare minimum required inside it
|
||||
for num, sphere in reversed(list(enumerate(collection_spheres))):
|
||||
to_delete = []
|
||||
to_delete = set()
|
||||
for location in sphere:
|
||||
# we remove the item at location and check if game is still beatable
|
||||
logging.getLogger('').debug('Checking if %s (Player %d) is required to beat the game.', location.item.name, location.item.player)
|
||||
old_item = location.item
|
||||
location.item = None
|
||||
# todo: this is not very efficient, but I'm not sure how else to do it for this backwards logic
|
||||
# world.clear_exp_cache()
|
||||
if world.can_beat_game(state_cache[num]):
|
||||
to_delete.append(location)
|
||||
# logging.getLogger('').debug(f'{old_item.name} (Player {old_item.player}) is not required')
|
||||
to_delete.add(location)
|
||||
else:
|
||||
# still required, got to keep it around
|
||||
# logging.getLogger('').debug(f'{old_item.name} (Player {old_item.player}) is required')
|
||||
location.item = old_item
|
||||
|
||||
# cull entries in spheres for spoiler walkthrough at end
|
||||
for location in to_delete:
|
||||
sphere.remove(location)
|
||||
sphere -= to_delete
|
||||
|
||||
# second phase, sphere 0
|
||||
for item in [i for i in world.precollected_items if i.advancement]:
|
||||
@@ -616,7 +622,7 @@ def create_playthrough(world):
|
||||
# used to access it was deemed not required.) So we need to do one final sphere collection pass
|
||||
# to build up the correct spheres
|
||||
|
||||
required_locations = [item for sphere in collection_spheres for item in sphere]
|
||||
required_locations = {item for sphere in collection_spheres for item in sphere}
|
||||
state = CollectionState(world)
|
||||
collection_spheres = []
|
||||
while required_locations:
|
||||
@@ -632,7 +638,10 @@ def create_playthrough(world):
|
||||
|
||||
logging.getLogger('').debug(world.fish.translate("cli","cli","building.final.spheres"), len(collection_spheres), len(sphere), len(required_locations))
|
||||
if not sphere:
|
||||
raise RuntimeError(world.fish.translate("cli","cli","cannot.reach.required"))
|
||||
if world.has_beaten_game(state):
|
||||
required_locations.clear()
|
||||
else:
|
||||
raise RuntimeError(world.fish.translate("cli","cli","cannot.reach.required"))
|
||||
|
||||
# store the required locations for statistical analysis
|
||||
old_world.required_locations = [(location.name, location.player) for sphere in collection_spheres for location in sphere]
|
||||
@@ -653,11 +662,11 @@ def create_playthrough(world):
|
||||
old_world.spoiler.paths = dict()
|
||||
for player in range(1, world.players + 1):
|
||||
old_world.spoiler.paths.update({location.gen_name(): get_path(state, location.parent_region) for sphere in collection_spheres for location in sphere if location.player == player})
|
||||
for _, path in dict(old_world.spoiler.paths).items():
|
||||
for path in dict(old_world.spoiler.paths).values():
|
||||
if any(exit == 'Pyramid Fairy' for (_, exit) in path):
|
||||
old_world.spoiler.paths[str(world.get_region('Big Bomb Shop', player))] = get_path(state, world.get_region('Big Bomb Shop', player))
|
||||
|
||||
# we can finally output our playthrough
|
||||
old_world.spoiler.playthrough = OrderedDict([("0", [str(item) for item in world.precollected_items if item.advancement])])
|
||||
old_world.spoiler.playthrough = {"0": [str(item) for item in world.precollected_items if item.advancement]}
|
||||
for i, sphere in enumerate(collection_spheres):
|
||||
old_world.spoiler.playthrough[str(i + 1)] = {location.gen_name(): str(location.item) for location in sphere}
|
||||
|
||||
Reference in New Issue
Block a user