updated to match DoorDev

Hint for TT Attic
This commit is contained in:
aerinon
2020-02-05 15:24:36 -07:00
6 changed files with 53 additions and 10 deletions

View File

@@ -287,6 +287,9 @@ class World(object):
def find_items(self, item, player): def find_items(self, item, player):
return [location for location in self.get_locations() if location.item is not None and location.item.name == item and location.item.player == player] return [location for location in self.get_locations() if location.item is not None and location.item.name == item and location.item.player == player]
def find_items_not_key_only(self, item, player):
return [location for location in self.get_locations() if location.item is not None and location.item.name == item and location.item.player == player and location.forced_item is None]
def push_precollected(self, item): def push_precollected(self, item):
item.world = self item.world = self
if (item.smallkey and self.keyshuffle[item.player]) or (item.bigkey and self.bigkeyshuffle[item.player]): if (item.smallkey and self.keyshuffle[item.player]) or (item.bigkey and self.bigkeyshuffle[item.player]):

View File

@@ -815,10 +815,10 @@ def validate_key_layout(key_layout, world, player):
for region in key_layout.start_regions: for region in key_layout.start_regions:
state.visit_region(region, key_checks=True) state.visit_region(region, key_checks=True)
state.add_all_doors_check_keys(region, flat_proposal, world, player) state.add_all_doors_check_keys(region, flat_proposal, world, player)
return validate_key_layout_sub_loop(key_layout, state, {}, flat_proposal, world, player) return validate_key_layout_sub_loop(key_layout, state, {}, flat_proposal, None, None, world, player)
def validate_key_layout_sub_loop(key_layout, state, checked_states, flat_proposal, world, player): def validate_key_layout_sub_loop(key_layout, state, checked_states, flat_proposal, prev_state, prev_avail, world, player):
expand_key_state(state, flat_proposal, world, player) expand_key_state(state, flat_proposal, world, player)
smalls_avail = len(state.small_doors) > 0 # de-dup crystal repeats smalls_avail = len(state.small_doors) > 0 # de-dup crystal repeats
num_bigs = 1 if len(state.big_doors) > 0 else 0 # all or nothing num_bigs = 1 if len(state.big_doors) > 0 else 0 # all or nothing
@@ -829,7 +829,9 @@ def validate_key_layout_sub_loop(key_layout, state, checked_states, flat_proposa
ttl_key_only = count_key_only_locations(state) ttl_key_only = count_key_only_locations(state)
available_small_locations = cnt_avail_small_locations(ttl_locations, ttl_key_only, state, world, player) available_small_locations = cnt_avail_small_locations(ttl_locations, ttl_key_only, state, world, player)
available_big_locations = cnt_avail_big_locations(ttl_locations, state, world, player) available_big_locations = cnt_avail_big_locations(ttl_locations, state, world, player)
if (not smalls_avail or available_small_locations == 0) and (state.big_key_opened or num_bigs == 0 or available_big_locations == 0): if invalid_self_locking_key(state, prev_state, prev_avail, world, player):
return False
if (not smalls_avail or not enough_small_locations(state, available_small_locations)) and (state.big_key_opened or num_bigs == 0 or available_big_locations == 0):
return False return False
else: else:
if smalls_avail and available_small_locations > 0: if smalls_avail and available_small_locations > 0:
@@ -841,7 +843,8 @@ def validate_key_layout_sub_loop(key_layout, state, checked_states, flat_proposa
state_copy.used_locations += 1 state_copy.used_locations += 1
code = state_id(state_copy, flat_proposal) code = state_id(state_copy, flat_proposal)
if code not in checked_states.keys(): if code not in checked_states.keys():
valid = validate_key_layout_sub_loop(key_layout, state_copy, checked_states, flat_proposal, world, player) valid = validate_key_layout_sub_loop(key_layout, state_copy, checked_states, flat_proposal,
state, available_small_locations, world, player)
checked_states[code] = valid checked_states[code] = valid
else: else:
valid = checked_states[code] valid = checked_states[code]
@@ -853,7 +856,8 @@ def validate_key_layout_sub_loop(key_layout, state, checked_states, flat_proposa
state_copy.used_locations += 1 state_copy.used_locations += 1
code = state_id(state_copy, flat_proposal) code = state_id(state_copy, flat_proposal)
if code not in checked_states.keys(): if code not in checked_states.keys():
valid = validate_key_layout_sub_loop(key_layout, state_copy, checked_states, flat_proposal, world, player) valid = validate_key_layout_sub_loop(key_layout, state_copy, checked_states, flat_proposal,
state, available_small_locations, world, player)
checked_states[code] = valid checked_states[code] = valid
else: else:
valid = checked_states[code] valid = checked_states[code]
@@ -862,6 +866,40 @@ def validate_key_layout_sub_loop(key_layout, state, checked_states, flat_proposa
return True return True
def invalid_self_locking_key(state, prev_state, prev_avail, world, player):
if prev_state is None or state.used_smalls == prev_state.used_smalls:
return False
new_locations = set(state.found_locations).difference(set(prev_state.found_locations))
important_found = False
for loc in new_locations:
important_found |= important_location(loc, world, player)
if not important_found:
return False
new_small_doors = set(state.small_doors).difference(set(prev_state.small_doors))
new_bk_doors = set(state.big_doors).difference(set(prev_state.big_doors))
if len(new_small_doors) > 0 or len(new_bk_doors) > 0:
return False
return prev_avail - 1 == 0
# does not allow dest doors
def count_unique_sm_doors(doors):
unique_d_set = set()
for d in doors:
if d not in unique_d_set and d.dest not in unique_d_set and not d.bigKey:
unique_d_set.add(d)
return len(unique_d_set)
def enough_small_locations(state, avail_small_loc):
unique_d_set = set()
for exp_door in state.small_doors:
door = exp_door.door
if door not in unique_d_set and door.dest not in unique_d_set:
unique_d_set.add(door)
return avail_small_loc >= len(unique_d_set)
def cnt_avail_small_locations(free_locations, key_only, state, world, player): def cnt_avail_small_locations(free_locations, key_only, state, world, player):
if not world.keyshuffle[player] and not world.retro[player]: if not world.keyshuffle[player] and not world.retro[player]:
bk_adj = 1 if state.big_key_opened and not state.big_key_special else 0 bk_adj = 1 if state.big_key_opened and not state.big_key_special else 0

View File

@@ -23,7 +23,7 @@ from Fill import distribute_items_cutoff, distribute_items_staleness, distribute
from ItemList import generate_itempool, difficulties, fill_prizes from ItemList import generate_itempool, difficulties, fill_prizes
from Utils import output_path, parse_player_names from Utils import output_path, parse_player_names
__version__ = '0.0.b-pre' __version__ = '0.0.c-pre'
def main(args, seed=None): def main(args, seed=None):

View File

@@ -740,7 +740,8 @@ def _create_region(player, name, type, hint='Hyrule', locations=None, exits=None
ret.exits.append(Entrance(player, exit, ret)) ret.exits.append(Entrance(player, exit, ret))
for location in locations: for location in locations:
if location in key_only_locations: if location in key_only_locations:
ret.locations.append(Location(player, location, None, False, None, ret, key_only_locations[location])) ko_hint = 'in a pot' if 'Pot' in location else 'with an enemy'
ret.locations.append(Location(player, location, None, False, ko_hint, ret, key_only_locations[location]))
else: else:
address, player_address, crystal, hint_text = location_table[location] address, player_address, crystal, hint_text = location_table[location]
ret.locations.append(Location(player, location, address, crystal, hint_text, ret, None, player_address)) ret.locations.append(Location(player, location, address, crystal, hint_text, ret, None, player_address))

2
Rom.py
View File

@@ -1725,7 +1725,7 @@ def write_strings(rom, world, player, team):
hint_count = 5 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 8 hint_count = 5 if world.shuffle[player] not in ['vanilla', 'dungeonssimple', 'dungeonsfull'] else 8
while hint_count > 0: while hint_count > 0:
this_item = items_to_hint.pop(0) this_item = items_to_hint.pop(0)
this_location = world.find_items(this_item, player) this_location = world.find_items_not_key_only(this_item, player)
random.shuffle(this_location) random.shuffle(this_location)
#This looks dumb but prevents hints for Skull Woods Pinball Room's key safely with any item pool. #This looks dumb but prevents hints for Skull Woods Pinball Room's key safely with any item pool.
if this_location: if this_location:

View File

@@ -279,6 +279,7 @@ class Room(object):
def delete(self, list_idx): def delete(self, list_idx):
self.doorList[list_idx] = (Position.FF, DoorKind.FF) self.doorList[list_idx] = (Position.FF, DoorKind.FF)
self.modified = True
def address(self): def address(self):
return self.doorListAddress return self.doorListAddress