updated to match DoorDev
Hint for TT Attic
This commit is contained in:
@@ -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]):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
2
Main.py
2
Main.py
@@ -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):
|
||||||
|
|||||||
@@ -740,10 +740,11 @@ 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))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def mark_light_world_regions(world, player):
|
def mark_light_world_regions(world, player):
|
||||||
|
|||||||
2
Rom.py
2
Rom.py
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user