Various refinements and fixes to key logic and generation
This commit is contained in:
@@ -1823,6 +1823,10 @@ def find_inaccessible_regions(world, player):
|
|||||||
if connect.type is not RegionType.Dungeon or connect.name.endswith(' Portal'):
|
if connect.type is not RegionType.Dungeon or connect.name.endswith(' Portal'):
|
||||||
queue.append(connect)
|
queue.append(connect)
|
||||||
world.inaccessible_regions[player].extend([r.name for r in all_regions.difference(visited_regions) if valid_inaccessible_region(r)])
|
world.inaccessible_regions[player].extend([r.name for r in all_regions.difference(visited_regions) if valid_inaccessible_region(r)])
|
||||||
|
if world.mode[player] == 'inverted':
|
||||||
|
ledge = world.get_region('Hyrule Castle Ledge', 1)
|
||||||
|
if any(x for x in ledge.exits if x.connected_region.name == 'Agahnims Tower Portal'):
|
||||||
|
world.inaccessible_regions[player].append('Hyrule Castle Ledge')
|
||||||
logger = logging.getLogger('')
|
logger = logging.getLogger('')
|
||||||
logger.debug('Inaccessible Regions:')
|
logger.debug('Inaccessible Regions:')
|
||||||
for r in world.inaccessible_regions[player]:
|
for r in world.inaccessible_regions[player]:
|
||||||
|
|||||||
@@ -1113,9 +1113,9 @@ def valid_region_to_explore_in_regions(region, all_regions, world, player):
|
|||||||
def valid_region_to_explore(region, name, world, player):
|
def valid_region_to_explore(region, name, world, player):
|
||||||
if region is None:
|
if region is None:
|
||||||
return False
|
return False
|
||||||
return (region.type == RegionType.Dungeon and region.dungeon.name in name)\
|
return ((region.type == RegionType.Dungeon and region.dungeon and region.dungeon.name in name)
|
||||||
or region.name in world.inaccessible_regions[player]\
|
or region.name in world.inaccessible_regions[player]
|
||||||
or (region.name == 'Hyrule Castle Ledge' and world.mode[player] == 'standard')
|
or (region.name == 'Hyrule Castle Ledge' and world.mode[player] == 'standard'))
|
||||||
|
|
||||||
|
|
||||||
def get_doors(world, region, player):
|
def get_doors(world, region, player):
|
||||||
|
|||||||
@@ -393,11 +393,9 @@ dungeon_bigs = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dungeon_prize = {
|
dungeon_prize = {
|
||||||
'Hyrule Castle': None,
|
|
||||||
'Eastern Palace': 'Eastern Palace - Prize',
|
'Eastern Palace': 'Eastern Palace - Prize',
|
||||||
'Desert Palace': 'Desert Palace - Prize',
|
'Desert Palace': 'Desert Palace - Prize',
|
||||||
'Tower of Hera': 'Tower of Hera - Prize',
|
'Tower of Hera': 'Tower of Hera - Prize',
|
||||||
'Agahnims Tower': None,
|
|
||||||
'Palace of Darkness': 'Palace of Darkness - Prize',
|
'Palace of Darkness': 'Palace of Darkness - Prize',
|
||||||
'Swamp Palace': 'Swamp Palace - Prize',
|
'Swamp Palace': 'Swamp Palace - Prize',
|
||||||
'Skull Woods': 'Skull Woods - Prize',
|
'Skull Woods': 'Skull Woods - Prize',
|
||||||
@@ -405,7 +403,6 @@ dungeon_prize = {
|
|||||||
'Ice Palace': 'Ice Palace - Prize',
|
'Ice Palace': 'Ice Palace - Prize',
|
||||||
'Misery Mire': 'Misery Mire - Prize',
|
'Misery Mire': 'Misery Mire - Prize',
|
||||||
'Turtle Rock': 'Turtle Rock - Prize',
|
'Turtle Rock': 'Turtle Rock - Prize',
|
||||||
'Ganons Tower': None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dungeon_hints = {
|
dungeon_hints = {
|
||||||
|
|||||||
4
Fill.py
4
Fill.py
@@ -722,7 +722,7 @@ def balance_money_progression(world):
|
|||||||
if room not in rooms_visited[player] and world.get_region(room, player) in state.reachable_regions[player]:
|
if room not in rooms_visited[player] and world.get_region(room, player) in state.reachable_regions[player]:
|
||||||
wallet[player] += income
|
wallet[player] += income
|
||||||
rooms_visited[player].add(room)
|
rooms_visited[player].add(room)
|
||||||
if checked_locations:
|
if checked_locations or len(unchecked_locations) == 0:
|
||||||
if world.has_beaten_game(state):
|
if world.has_beaten_game(state):
|
||||||
done = True
|
done = True
|
||||||
continue
|
continue
|
||||||
@@ -732,7 +732,7 @@ def balance_money_progression(world):
|
|||||||
solvent = set()
|
solvent = set()
|
||||||
insolvent = set()
|
insolvent = set()
|
||||||
for player in range(1, world.players+1):
|
for player in range(1, world.players+1):
|
||||||
if wallet[player] >= sphere_costs[player] > 0:
|
if wallet[player] >= sphere_costs[player] >= 0:
|
||||||
solvent.add(player)
|
solvent.add(player)
|
||||||
if sphere_costs[player] > 0 and sphere_costs[player] > wallet[player]:
|
if sphere_costs[player] > 0 and sphere_costs[player] > wallet[player]:
|
||||||
insolvent.add(player)
|
insolvent.add(player)
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ def create_exhaustive_placement_rules(key_layout, world, player):
|
|||||||
key_logic = key_layout.key_logic
|
key_logic = key_layout.key_logic
|
||||||
max_ctr = find_max_counter(key_layout)
|
max_ctr = find_max_counter(key_layout)
|
||||||
for code, key_counter in key_layout.key_counters.items():
|
for code, key_counter in key_layout.key_counters.items():
|
||||||
if key_counter.prize_received and not key_counter.prize_doors_opened:
|
if skip_key_counter_due_to_prize(key_layout, key_counter):
|
||||||
continue # we have the prize, we are not concerned about this case
|
continue # we have the prize, we are not concerned about this case
|
||||||
accessible_loc = set()
|
accessible_loc = set()
|
||||||
accessible_loc.update(key_counter.free_locations)
|
accessible_loc.update(key_counter.free_locations)
|
||||||
@@ -343,6 +343,10 @@ def create_exhaustive_placement_rules(key_layout, world, player):
|
|||||||
refine_location_rules(key_layout)
|
refine_location_rules(key_layout)
|
||||||
|
|
||||||
|
|
||||||
|
def skip_key_counter_due_to_prize(key_layout, key_counter):
|
||||||
|
return key_layout.prize_relevant and key_counter.prize_received and not key_counter.prize_doors_opened
|
||||||
|
|
||||||
|
|
||||||
def placement_self_lock_adjustment(rule, max_ctr, blocked_loc, ctr, world, player):
|
def placement_self_lock_adjustment(rule, max_ctr, blocked_loc, ctr, world, player):
|
||||||
if len(blocked_loc) == 1 and world.accessibility[player] != 'locations':
|
if len(blocked_loc) == 1 and world.accessibility[player] != 'locations':
|
||||||
blocked_others = set(max_ctr.other_locations).difference(set(ctr.other_locations))
|
blocked_others = set(max_ctr.other_locations).difference(set(ctr.other_locations))
|
||||||
@@ -1356,7 +1360,8 @@ def validate_key_layout(key_layout, world, player):
|
|||||||
state.big_key_special = check_bk_special(key_layout.sector.regions, world, player)
|
state.big_key_special = check_bk_special(key_layout.sector.regions, world, player)
|
||||||
for region in key_layout.start_regions:
|
for region in key_layout.start_regions:
|
||||||
dungeon_entrance, portal_door = find_outside_connection(region)
|
dungeon_entrance, portal_door = find_outside_connection(region)
|
||||||
if dungeon_entrance and dungeon_entrance.name in ['Ganons Tower', 'Inverted Ganons Tower', 'Pyramid Fairy']:
|
if (key_layout.prize_relevant and dungeon_entrance and
|
||||||
|
dungeon_entrance.name in ['Ganons Tower', 'Inverted Ganons Tower', 'Pyramid Fairy']):
|
||||||
state.append_door_to_list(portal_door, state.prize_doors)
|
state.append_door_to_list(portal_door, state.prize_doors)
|
||||||
state.prize_door_set[portal_door] = dungeon_entrance
|
state.prize_door_set[portal_door] = dungeon_entrance
|
||||||
else:
|
else:
|
||||||
@@ -1396,7 +1401,7 @@ def validate_key_layout_sub_loop(key_layout, state, checked_states, flat_proposa
|
|||||||
state_copy.used_smalls += 1
|
state_copy.used_smalls += 1
|
||||||
if state_copy.used_smalls > ttl_small_key_only:
|
if state_copy.used_smalls > ttl_small_key_only:
|
||||||
state_copy.used_locations += 1
|
state_copy.used_locations += 1
|
||||||
code = state_id(state_copy, flat_proposal)
|
code = validate_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,
|
valid = validate_key_layout_sub_loop(key_layout, state_copy, checked_states, flat_proposal,
|
||||||
state, available_small_locations, world, player)
|
state, available_small_locations, world, player)
|
||||||
@@ -1410,7 +1415,7 @@ def validate_key_layout_sub_loop(key_layout, state, checked_states, flat_proposa
|
|||||||
open_a_door(state.big_doors[0].door, state_copy, flat_proposal, world, player)
|
open_a_door(state.big_doors[0].door, state_copy, flat_proposal, world, player)
|
||||||
if not found_forced_bk:
|
if not found_forced_bk:
|
||||||
state_copy.used_locations += 1
|
state_copy.used_locations += 1
|
||||||
code = state_id(state_copy, flat_proposal)
|
code = validate_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,
|
valid = validate_key_layout_sub_loop(key_layout, state_copy, checked_states, flat_proposal,
|
||||||
state, available_small_locations, world, player)
|
state, available_small_locations, world, player)
|
||||||
@@ -1422,7 +1427,7 @@ def validate_key_layout_sub_loop(key_layout, state, checked_states, flat_proposa
|
|||||||
if not state.prize_doors_opened and key_layout.prize_relevant:
|
if not state.prize_doors_opened and key_layout.prize_relevant:
|
||||||
state_copy = state.copy()
|
state_copy = state.copy()
|
||||||
open_a_door(next(iter(state_copy.prize_door_set)), state_copy, flat_proposal, world, player)
|
open_a_door(next(iter(state_copy.prize_door_set)), state_copy, flat_proposal, world, player)
|
||||||
code = state_id(state_copy, flat_proposal)
|
code = validate_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,
|
valid = validate_key_layout_sub_loop(key_layout, state_copy, checked_states, flat_proposal,
|
||||||
state, available_small_locations, world, player)
|
state, available_small_locations, world, player)
|
||||||
@@ -1496,7 +1501,9 @@ def create_key_counters(key_layout, world, player):
|
|||||||
special_region = region
|
special_region = region
|
||||||
for region in key_layout.start_regions:
|
for region in key_layout.start_regions:
|
||||||
dungeon_entrance, portal_door = find_outside_connection(region)
|
dungeon_entrance, portal_door = find_outside_connection(region)
|
||||||
if dungeon_entrance and dungeon_entrance.name in ['Ganons Tower', 'Inverted Ganons Tower', 'Pyramid Fairy']:
|
if (len(key_layout.start_regions) > 1 and dungeon_entrance and
|
||||||
|
dungeon_entrance.name in ['Ganons Tower', 'Inverted Ganons Tower', 'Pyramid Fairy']
|
||||||
|
and key_layout.key_logic.dungeon in dungeon_prize):
|
||||||
state.append_door_to_list(portal_door, state.prize_doors)
|
state.append_door_to_list(portal_door, state.prize_doors)
|
||||||
state.prize_door_set[portal_door] = dungeon_entrance
|
state.prize_door_set[portal_door] = dungeon_entrance
|
||||||
key_layout.prize_relevant = True
|
key_layout.prize_relevant = True
|
||||||
@@ -1616,6 +1623,16 @@ def state_id(state, flat_proposal):
|
|||||||
return s_id
|
return s_id
|
||||||
|
|
||||||
|
|
||||||
|
def validate_id(state, flat_proposal):
|
||||||
|
s_id = '1' if state.big_key_opened else '0'
|
||||||
|
for d in flat_proposal:
|
||||||
|
s_id += '1' if d in state.opened_doors else '0'
|
||||||
|
if len(state.prize_door_set) > 0:
|
||||||
|
s_id += '1' if state.prize_doors_opened else '0'
|
||||||
|
s_id += str(state.used_locations)
|
||||||
|
return s_id
|
||||||
|
|
||||||
|
|
||||||
def find_counter(opened_doors, bk_hint, key_layout, prize_flag, raise_on_error=True):
|
def find_counter(opened_doors, bk_hint, key_layout, prize_flag, raise_on_error=True):
|
||||||
counter = find_counter_hint(opened_doors, bk_hint, key_layout, prize_flag)
|
counter = find_counter_hint(opened_doors, bk_hint, key_layout, prize_flag)
|
||||||
if counter is not None:
|
if counter is not None:
|
||||||
@@ -1878,7 +1895,7 @@ def validate_key_placement(key_layout, world, player):
|
|||||||
len(counter.key_only_locations) + keys_outside
|
len(counter.key_only_locations) + keys_outside
|
||||||
if key_layout.prize_relevant:
|
if key_layout.prize_relevant:
|
||||||
found_prize = any(x for x in counter.important_locations if '- Prize' in x.name)
|
found_prize = any(x for x in counter.important_locations if '- Prize' in x.name)
|
||||||
if not found_prize:
|
if not found_prize and key_layout.sector.name in dungeon_prize:
|
||||||
prize_loc = world.get_location(dungeon_prize[key_layout.sector.name], player)
|
prize_loc = world.get_location(dungeon_prize[key_layout.sector.name], player)
|
||||||
# todo: pyramid fairy only care about crystals 5 & 6
|
# todo: pyramid fairy only care about crystals 5 & 6
|
||||||
found_prize = 'Crystal' not in prize_loc.item.name
|
found_prize = 'Crystal' not in prize_loc.item.name
|
||||||
|
|||||||
Reference in New Issue
Block a user