Retry Logic for Dungeon Prizes
Will help make avoid seed failure for custom pool seeds. This won't help with a seed that has a layout that is not compatible with the item pool though.
This commit is contained in:
parent
405e157da8
commit
e19c0ada70
14
Fill.py
14
Fill.py
|
@ -1,6 +1,8 @@
|
|||
import random
|
||||
import logging
|
||||
|
||||
class FillError(RuntimeError):
|
||||
pass
|
||||
|
||||
def distribute_items_cutoff(world, cutoffrate=0.33):
|
||||
# get list of locations to fill in
|
||||
|
@ -53,7 +55,7 @@ def distribute_items_cutoff(world, cutoffrate=0.33):
|
|||
logging.getLogger('').warning('Not all locations reachable. Game beatable anyway.')
|
||||
progress_done = True
|
||||
continue
|
||||
raise RuntimeError('No more progress items left to place.')
|
||||
raise FillError('No more progress items left to place.')
|
||||
|
||||
spot_to_fill = None
|
||||
for location in fill_locations if placed_advancement_items / total_advancement_items < cutoffrate else reversed(fill_locations):
|
||||
|
@ -66,7 +68,7 @@ def distribute_items_cutoff(world, cutoffrate=0.33):
|
|||
if world.can_beat_game():
|
||||
logging.getLogger('').warning('Not all items placed. Game beatable anyway.')
|
||||
break
|
||||
raise RuntimeError('No more spots to place %s' % item_to_place)
|
||||
raise FillError('No more spots to place %s' % item_to_place)
|
||||
|
||||
world.push_item(spot_to_fill, item_to_place, True)
|
||||
itempool.remove(item_to_place)
|
||||
|
@ -121,7 +123,7 @@ def distribute_items_staleness(world):
|
|||
logging.getLogger('').warning('Not all locations reachable. Game beatable anyway.')
|
||||
progress_done = True
|
||||
continue
|
||||
raise RuntimeError('No more progress items left to place.')
|
||||
raise FillError('No more progress items left to place.')
|
||||
|
||||
spot_to_fill = None
|
||||
for location in fill_locations:
|
||||
|
@ -147,7 +149,7 @@ def distribute_items_staleness(world):
|
|||
if world.can_beat_game():
|
||||
logging.getLogger('').warning('Not all items placed. Game beatable anyway.')
|
||||
break
|
||||
raise RuntimeError('No more spots to place %s' % item_to_place)
|
||||
raise FillError('No more spots to place %s' % item_to_place)
|
||||
|
||||
world.push_item(spot_to_fill, item_to_place, True)
|
||||
itempool.remove(item_to_place)
|
||||
|
@ -185,7 +187,7 @@ def fill_restrictive(world, base_state, locations, itempool):
|
|||
if not world.check_beatable_only:
|
||||
logging.getLogger('').warning('Not all items placed. Game beatable anyway.')
|
||||
break
|
||||
raise RuntimeError('No more spots to place %s' % item_to_place)
|
||||
raise FillError('No more spots to place %s' % item_to_place)
|
||||
|
||||
world.push_item(spot_to_fill, item_to_place, False)
|
||||
locations.remove(spot_to_fill)
|
||||
|
@ -281,7 +283,7 @@ def flood_items(world):
|
|||
if candidate_item_to_place is not None:
|
||||
item_to_place = candidate_item_to_place
|
||||
else:
|
||||
raise RuntimeError('No more progress items left to place.')
|
||||
raise FillError('No more progress items left to place.')
|
||||
|
||||
# find item to replace with progress item
|
||||
location_list = world.get_reachable_locations()
|
||||
|
|
29
ItemList.py
29
ItemList.py
|
@ -1,8 +1,9 @@
|
|||
from collections import namedtuple
|
||||
import logging
|
||||
import random
|
||||
|
||||
from Items import ItemFactory
|
||||
from Fill import fill_restrictive
|
||||
from Fill import FillError, fill_restrictive
|
||||
from Dungeons import get_dungeon_item_pool
|
||||
|
||||
#This file sets the item pools for various modes. Timed modes and triforce hunt are enforced first, and then extra items are specified per mode to fill in the remaining space.
|
||||
|
@ -248,14 +249,36 @@ def generate_itempool(world):
|
|||
world.required_medallions = (mm_medallion, tr_medallion)
|
||||
|
||||
# distribute crystals
|
||||
fill_prizes(world)
|
||||
|
||||
def fill_prizes(world, attempts=15):
|
||||
crystals = ItemFactory(['Red Pendant', 'Blue Pendant', 'Green Pendant', 'Crystal 1', 'Crystal 2', 'Crystal 3', 'Crystal 4', 'Crystal 7', 'Crystal 5', 'Crystal 6'])
|
||||
crystal_locations = [world.get_location('Turtle Rock - Prize'), world.get_location('Eastern Palace - Prize'), world.get_location('Desert Palace - Prize'), world.get_location('Tower of Hera - Prize'), world.get_location('Palace of Darkness - Prize'),
|
||||
world.get_location('Thieves Town - Prize'), world.get_location('Skull Woods - Prize'), world.get_location('Swamp Palace - Prize'), world.get_location('Ice Palace - Prize'),
|
||||
world.get_location('Misery Mire - Prize')]
|
||||
placed_prizes = [loc.item.name for loc in crystal_locations if loc.item is not None]
|
||||
unplaced_prizes = [crystal for crystal in crystals if crystal.name not in placed_prizes]
|
||||
empty_crystal_locations = [loc for loc in crystal_locations if loc.item is None]
|
||||
|
||||
while attempts:
|
||||
attempts -= 1
|
||||
try:
|
||||
prizepool = list(unplaced_prizes)
|
||||
prize_locs = list(empty_crystal_locations)
|
||||
random.shuffle(prizepool)
|
||||
random.shuffle(prize_locs)
|
||||
fill_restrictive(world, world.get_all_state(keys=True), prize_locs, prizepool)
|
||||
except FillError:
|
||||
logging.getLogger('').info("Failed to place dungeon prizes. Will retry %s more times", attempts)
|
||||
for location in empty_crystal_locations:
|
||||
location.item = None
|
||||
continue
|
||||
break
|
||||
else:
|
||||
raise FillError('Unable to place dungeon prizes')
|
||||
|
||||
|
||||
random.shuffle(crystal_locations)
|
||||
|
||||
fill_restrictive(world, world.get_all_state(keys=True), crystal_locations, crystals)
|
||||
|
||||
def get_pool_core(progressive, shuffle, difficulty, timer, goal, mode):
|
||||
pool = []
|
||||
|
|
Loading…
Reference in New Issue