Fix for last ditch problems
Special bk adjustments Exception for self locking key doors in key lock checker
This commit is contained in:
@@ -432,7 +432,7 @@ class World(object):
|
||||
else:
|
||||
return all((self.has_beaten_game(state, p) for p in range(1, self.players + 1)))
|
||||
|
||||
def can_beat_game(self, starting_state=None):
|
||||
def can_beat_game(self, starting_state=None, log_error=False):
|
||||
if starting_state:
|
||||
if self.has_beaten_game(starting_state):
|
||||
return True
|
||||
@@ -456,6 +456,9 @@ class World(object):
|
||||
|
||||
if not sphere:
|
||||
# ran out of places and did not finish yet, quit
|
||||
if log_error:
|
||||
missing_locations = ", ".join([x.name for x in prog_locations])
|
||||
logging.getLogger('').error(f'Cannot reach the following locations: {missing_locations}')
|
||||
return False
|
||||
|
||||
for location in sphere:
|
||||
|
||||
8
Fill.py
8
Fill.py
@@ -295,12 +295,14 @@ def last_ditch_placement(item_to_place, locations, world, state, base_state, ite
|
||||
if swap_spot:
|
||||
logging.getLogger('').debug(f'Swapping {old_item} for {item_to_place}')
|
||||
world.push_item(swap_spot, old_item, False)
|
||||
swap_spot.event = True
|
||||
locations.remove(swap_spot)
|
||||
locations.append(new_spot)
|
||||
return new_spot
|
||||
else:
|
||||
new_spot.item = restore_item
|
||||
|
||||
else:
|
||||
location.item = old_item
|
||||
return None
|
||||
|
||||
|
||||
@@ -315,10 +317,12 @@ def find_spot_for_item(item_to_place, locations, world, base_state, pool,
|
||||
for location in locations:
|
||||
maximum_exploration_state = sweep_from_pool()
|
||||
perform_access_check = True
|
||||
old_item = None
|
||||
if world.accessibility[item_to_place.player] == 'none':
|
||||
perform_access_check = not world.has_beaten_game(maximum_exploration_state, item_to_place.player) if single_player_placement else not world.has_beaten_game(maximum_exploration_state)
|
||||
|
||||
if item_to_place.smallkey or item_to_place.bigkey: # a better test to see if a key can go there
|
||||
old_item = location.item
|
||||
location.item = item_to_place
|
||||
test_state = maximum_exploration_state.copy()
|
||||
test_state.stale[item_to_place.player] = True
|
||||
@@ -329,7 +333,7 @@ def find_spot_for_item(item_to_place, locations, world, base_state, pool,
|
||||
and valid_key_placement(item_to_place, location, pool if (keys_in_itempool and keys_in_itempool[item_to_place.player]) else world.itempool, world):
|
||||
return location
|
||||
if item_to_place.smallkey or item_to_place.bigkey:
|
||||
location.item = None
|
||||
location.item = old_item
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@@ -116,6 +116,7 @@ class PlacementRule(object):
|
||||
self.needed_keys_w_bk = None
|
||||
self.needed_keys_wo_bk = None
|
||||
self.check_locations_w_bk = None
|
||||
self.special_bk_avail = False
|
||||
self.check_locations_wo_bk = None
|
||||
self.bk_relevant = True
|
||||
self.key_reduced = False
|
||||
@@ -164,7 +165,10 @@ class PlacementRule(object):
|
||||
def loc_has_bk(l):
|
||||
return (big_key_loc is not None and big_key_loc == l) or (l.item and l.item.bigkey)
|
||||
|
||||
bk_found = any(loc for loc in self.check_locations_w_bk if loc_has_bk(loc))
|
||||
# todo: sometimes the bk avail rule doesn't mean the bk must be avail or this rule is invalid
|
||||
# but sometimes it certainly does
|
||||
# check threshold vs len(check_loc) maybe to determine bk isn't relevant?
|
||||
bk_found = self.special_bk_avail or any(loc for loc in self.check_locations_w_bk if loc_has_bk(loc))
|
||||
if not bk_found:
|
||||
return True
|
||||
check_locations = self.check_locations_wo_bk if bk_blocked else self.check_locations_w_bk
|
||||
@@ -258,6 +262,8 @@ def analyze_dungeon(key_layout, world, player):
|
||||
return
|
||||
|
||||
original_key_counter = find_counter({}, False, key_layout, False)
|
||||
if key_layout.big_key_special and forced_big_key_avail(original_key_counter.other_locations) is not None:
|
||||
original_key_counter = find_counter({}, True, key_layout, False)
|
||||
queue = deque([(None, original_key_counter)])
|
||||
doors_completed = set()
|
||||
visited_cid = set()
|
||||
@@ -340,6 +346,8 @@ def create_exhaustive_placement_rules(key_layout, world, player):
|
||||
else:
|
||||
placement_self_lock_adjustment(rule, max_ctr, blocked_loc, key_counter, world, player)
|
||||
rule.check_locations_w_bk = accessible_loc
|
||||
if key_layout.big_key_special:
|
||||
rule.special_bk_avail = forced_big_key_avail(key_counter.important_locations) is not None
|
||||
# check_sm_restriction_needed(key_layout, max_ctr, rule, blocked_loc)
|
||||
else:
|
||||
if big_key_progress(key_counter) and only_sm_doors(key_counter):
|
||||
@@ -1359,6 +1367,13 @@ def check_bk_special(regions, world, player):
|
||||
return False
|
||||
|
||||
|
||||
def forced_big_key_avail(locations):
|
||||
for loc in locations:
|
||||
if loc.forced_big_key():
|
||||
return loc
|
||||
return None
|
||||
|
||||
|
||||
# Soft lock stuff
|
||||
def validate_key_layout(key_layout, world, player):
|
||||
# retro is all good - except for hyrule castle in standard mode
|
||||
@@ -1962,6 +1977,7 @@ def validate_key_placement(key_layout, world, player):
|
||||
found_prize = False
|
||||
can_progress = (not counter.big_key_opened and big_found and any(d.bigKey for d in counter.child_doors)) or \
|
||||
found_keys > counter.used_keys and any(not d.bigKey for d in counter.child_doors) or \
|
||||
self_locked_child_door(key_layout, counter) or \
|
||||
(key_layout.prize_relevant and not counter.prize_doors_opened and found_prize)
|
||||
if not can_progress:
|
||||
missing_locations = set(max_counter.free_locations.keys()).difference(found_locations)
|
||||
@@ -1976,3 +1992,11 @@ def validate_key_placement(key_layout, world, player):
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def self_locked_child_door(key_layout, counter):
|
||||
if len(counter.child_doors) == 1:
|
||||
door = next(iter(counter.child_doors.keys()))
|
||||
return door.smallKey and key_layout.key_logic.door_rules[door.name].allow_small
|
||||
return False
|
||||
|
||||
|
||||
|
||||
2
Main.py
2
Main.py
@@ -244,7 +244,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):
|
||||
|
||||
Reference in New Issue
Block a user