Merged in DR v1.2.0.8
This commit is contained in:
@@ -5,7 +5,7 @@ from collections import defaultdict, deque
|
||||
from BaseClasses import DoorType, dungeon_keys, KeyRuleType, RegionType
|
||||
from Regions import dungeon_events
|
||||
from Dungeons import dungeon_keys, dungeon_bigs, dungeon_table
|
||||
from DungeonGenerator import ExplorationState, special_big_key_doors, count_locations_exclude_big_chest, prize_or_event
|
||||
from DungeonGenerator import ExplorationState, get_special_big_key_doors, count_locations_exclude_big_chest, prize_or_event
|
||||
from DungeonGenerator import reserved_location, blind_boss_unavail
|
||||
|
||||
|
||||
@@ -59,13 +59,16 @@ class KeyLogic(object):
|
||||
self.placement_rules = []
|
||||
self.location_rules = {}
|
||||
self.outside_keys = 0
|
||||
self.outside_keys_locations = set()
|
||||
self.dungeon = dungeon_name
|
||||
self.sm_doors = {}
|
||||
self.prize_location = None
|
||||
|
||||
def check_placement(self, unplaced_keys, wild_keys, big_key_loc=None, prize_loc=None, cr_count=7):
|
||||
def check_placement(self, unplaced_keys, wild_keys, reached_keys, self_locking_keys,
|
||||
big_key_loc=None, prize_loc=None, cr_count=7):
|
||||
for rule in self.placement_rules:
|
||||
if not rule.is_satisfiable(self.outside_keys, wild_keys, unplaced_keys, big_key_loc, prize_loc, cr_count):
|
||||
if not rule.is_satisfiable(self.outside_keys_locations, wild_keys, reached_keys, self_locking_keys,
|
||||
unplaced_keys, big_key_loc, prize_loc, cr_count):
|
||||
return False
|
||||
if big_key_loc:
|
||||
for rule_a, rule_b in itertools.combinations(self.placement_rules, 2):
|
||||
@@ -159,7 +162,8 @@ class PlacementRule(object):
|
||||
left -= rule_needed
|
||||
return False
|
||||
|
||||
def is_satisfiable(self, outside_keys, wild_keys, unplaced_keys, big_key_loc, prize_location, cr_count):
|
||||
def is_satisfiable(self, outside_keys_locations, wild_keys, reached_keys, self_locking_keys, unplaced_keys,
|
||||
big_key_loc, prize_location, cr_count):
|
||||
if self.prize_relevance and prize_location:
|
||||
if self.prize_relevance == 'BigBomb':
|
||||
if prize_location.item.name not in ['Crystal 5', 'Crystal 6']:
|
||||
@@ -186,10 +190,11 @@ class PlacementRule(object):
|
||||
check_locations = self.check_locations_wo_bk if bk_blocked else self.check_locations_w_bk
|
||||
if not bk_blocked and check_locations is None:
|
||||
return True
|
||||
available_keys = outside_keys
|
||||
available_keys = len(outside_keys_locations)
|
||||
# todo: sometimes we need an extra empty chest to accomodate the big key too
|
||||
# dungeon bias seed 563518200 for example
|
||||
threshold = self.needed_keys_wo_bk if bk_blocked else self.needed_keys_w_bk
|
||||
threshold -= self_locking_keys
|
||||
if not wild_keys:
|
||||
empty_chests = 0
|
||||
for loc in check_locations:
|
||||
@@ -200,7 +205,8 @@ class PlacementRule(object):
|
||||
place_able_keys = min(empty_chests, unplaced_keys)
|
||||
available_keys += place_able_keys
|
||||
else:
|
||||
available_keys += unplaced_keys
|
||||
available_keys += len(reached_keys.difference(outside_keys_locations)) # already placed small keys
|
||||
available_keys += unplaced_keys # small keys not yet placed
|
||||
return available_keys >= threshold
|
||||
|
||||
|
||||
@@ -1002,7 +1008,7 @@ def find_worst_counter_wo_bk(small_key_num, accessible_set, door, odd_ctr, key_c
|
||||
|
||||
|
||||
def open_a_door(door, child_state, flat_proposal, world, player):
|
||||
if door.bigKey or door.name in special_big_key_doors:
|
||||
if door.bigKey or door.name in get_special_big_key_doors(world, player):
|
||||
child_state.big_key_opened = True
|
||||
child_state.avail_doors.extend(child_state.big_doors)
|
||||
child_state.opened_doors.extend(set([d.door for d in child_state.big_doors]))
|
||||
@@ -1485,7 +1491,8 @@ def validate_key_layout_sub_loop(key_layout, state, checked_states, flat_proposa
|
||||
else:
|
||||
ttl_locations = count_locations_exclude_big_chest(state.found_locations, world, player)
|
||||
ttl_small_key_only = count_small_key_only_locations(state)
|
||||
available_small_locations = cnt_avail_small_locations(ttl_locations, ttl_small_key_only, state, world, player)
|
||||
available_small_locations = cnt_avail_small_locations(ttl_locations, ttl_small_key_only, state,
|
||||
key_layout, world, player)
|
||||
available_big_locations = cnt_avail_big_locations(ttl_locations, state, world, player)
|
||||
if invalid_self_locking_key(key_layout, state, prev_state, prev_avail, world, player):
|
||||
return False
|
||||
@@ -1615,18 +1622,24 @@ def determine_prize_lock(key_layout, world, player):
|
||||
key_layout.prize_can_lock = True
|
||||
|
||||
|
||||
def cnt_avail_small_locations(free_locations, key_only, state, world, player):
|
||||
if world.keyshuffle[player] == 'none':
|
||||
def cnt_avail_small_locations(free_locations, key_only, state, key_layout, world, player):
|
||||
std_flag = world.mode[player] == 'standard' and key_layout.sector.name == 'Hyrule Castle'
|
||||
if world.keyshuffle[player] == 'none' or std_flag:
|
||||
bk_adj = 1 if state.big_key_opened and not state.big_key_special else 0
|
||||
avail_chest_keys = min(free_locations - bk_adj, state.key_locations - key_only)
|
||||
# this is the secret passage, could expand to Uncle/Links House with appropriate logic
|
||||
std_adj = 1 if std_flag and world.keyshuffle[player] != 'none' else 0
|
||||
avail_chest_keys = min(free_locations + std_adj - bk_adj, state.key_locations - key_only)
|
||||
return max(0, avail_chest_keys + key_only - state.used_smalls)
|
||||
return state.key_locations - state.used_smalls
|
||||
|
||||
|
||||
def cnt_avail_small_locations_by_ctr(free_locations, counter, layout, world, player):
|
||||
if world.keyshuffle[player] == 'none':
|
||||
std_flag = world.mode[player] == 'standard' and layout.sector.name == 'Hyrule Castle'
|
||||
if world.keyshuffle[player] == 'none' or std_flag:
|
||||
bk_adj = 1 if counter.big_key_opened and not layout.big_key_special else 0
|
||||
avail_chest_keys = min(free_locations - bk_adj, layout.max_chests)
|
||||
# this is the secret passage, could expand to Uncle/Links House with appropriate logic
|
||||
std_adj = 1 if std_flag and world.keyshuffle[player] != 'none' else 0
|
||||
avail_chest_keys = min(free_locations + std_adj - bk_adj, layout.max_chests)
|
||||
return max(0, avail_chest_keys + len(counter.key_only_locations) - counter.used_keys)
|
||||
return layout.max_chests + len(counter.key_only_locations) - counter.used_keys
|
||||
|
||||
@@ -1683,10 +1696,10 @@ def create_key_counters(key_layout, world, player):
|
||||
if door.dest in flat_proposal and door.type != DoorType.SpiralStairs:
|
||||
key_layout.found_doors.add(door.dest)
|
||||
child_state = parent_state.copy()
|
||||
if door.bigKey or door.name in special_big_key_doors:
|
||||
if door.bigKey or door.name in get_special_big_key_doors(world, player):
|
||||
key_layout.key_logic.bk_doors.add(door)
|
||||
# open the door, if possible
|
||||
if can_open_door(door, child_state, world, player):
|
||||
if can_open_door(door, child_state, key_layout, world, player):
|
||||
open_a_door(door, child_state, flat_proposal, world, player)
|
||||
expand_key_state(child_state, flat_proposal, world, player)
|
||||
code = state_id(child_state, key_layout.flat_prop)
|
||||
@@ -1707,14 +1720,15 @@ def find_outside_connection(region):
|
||||
return None, None
|
||||
|
||||
|
||||
def can_open_door(door, state, world, player):
|
||||
def can_open_door(door, state, key_layout, world, player):
|
||||
if state.big_key_opened:
|
||||
ttl_locations = count_free_locations(state, world, player)
|
||||
else:
|
||||
ttl_locations = count_locations_exclude_big_chest(state.found_locations, world, player)
|
||||
if door.smallKey:
|
||||
ttl_small_key_only = count_small_key_only_locations(state)
|
||||
available_small_locations = cnt_avail_small_locations(ttl_locations, ttl_small_key_only, state, world, player)
|
||||
available_small_locations = cnt_avail_small_locations(ttl_locations, ttl_small_key_only, state,
|
||||
key_layout, world, player)
|
||||
return available_small_locations > 0
|
||||
elif door.bigKey:
|
||||
available_big_locations = cnt_avail_big_locations(ttl_locations, state, world, player)
|
||||
|
||||
Reference in New Issue
Block a user