Ice Palace added

Dynamic logical doors added for ice cross w/ push block
Improved crystal switch pathing
Minor update to PoD
This commit is contained in:
aerinon
2019-11-01 16:13:23 -06:00
parent 49cfe923b6
commit e08bf3776a
14 changed files with 442 additions and 703 deletions

View File

@@ -21,6 +21,7 @@ class GraphPiece:
def __init__(self):
self.hanger_info = None
self.hanger_crystal = None
self.hooks = {}
self.visited_regions = set()
@@ -91,35 +92,22 @@ def gen_dungeon_info(available_sectors, entrance_regions, proposed_map, valid_do
original_state = extend_reachable_state_improved(entrance_regions, ExplorationState(), proposed_map, valid_doors, world, player)
dungeon['Origin'] = create_graph_piece_from_state(None, original_state, original_state, proposed_map)
doors_to_connect = set()
blue_hooks = []
hanger_set = set()
o_state_cache = {}
for sector in available_sectors:
for door in sector.outstanding_doors:
doors_to_connect.add(door)
if not door.stonewall and door not in proposed_map.keys():
hanger_set.add(door)
parent = parent_region(door, world, player).parent_region
o_state = extend_reachable_state_improved([parent], ExplorationState(), proposed_map, valid_doors, world, player)
o_state_cache[door.name] = o_state
piece = create_graph_piece_from_state(door, o_state, o_state, proposed_map)
dungeon[door.name] = piece
for hook, crystal in piece.hooks.items():
if crystal == CrystalBarrier.Blue or crystal == CrystalBarrier.Either:
h_type = hook_from_door(hook)
if h_type not in blue_hooks:
blue_hooks.append(h_type) # todo: specific hooks and valid path to c_switch
if len(blue_hooks) > 0:
for sector in available_sectors:
for door in sector.outstanding_doors:
h_type = hanger_from_door(door)
if not door.stonewall and door not in proposed_map.keys() and h_type in blue_hooks:
parent = parent_region(door, world, player).parent_region
blue_start = ExplorationState(CrystalBarrier.Blue)
b_state = extend_reachable_state_improved([parent], blue_start, proposed_map, valid_doors, world, player)
o_state = o_state_cache[door.name]
dungeon[door.name] = create_graph_piece_from_state(door, o_state, b_state, proposed_map)
check_blue_states(hanger_set, dungeon, o_state_cache, proposed_map, valid_doors, world, player)
# catalog hooks: Dict<Hook, Set<>
# and hangers:
# catalog hooks: Dict<Hook, Set<Door, Crystal, Door>>
# and hangers: Dict<Hang, Set<Door>>
avail_hooks = defaultdict(set)
hangers = defaultdict(set)
for key, piece in dungeon.items():
@@ -136,6 +124,46 @@ def gen_dungeon_info(available_sectors, entrance_regions, proposed_map, valid_do
return dungeon, hangers, avail_hooks
def check_blue_states(hanger_set, dungeon, o_state_cache, proposed_map, valid_doors, world, player):
not_blue = set()
not_blue.update(hanger_set)
doors_to_check = set()
doors_to_check.update(hanger_set) # doors to check, check everything on first pass
blue_hooks = []
blue_hangers = []
new_blues = True
while new_blues:
new_blues = False
for door in doors_to_check:
piece = dungeon[door.name]
for hook, crystal in piece.hooks.items():
if crystal == CrystalBarrier.Blue or crystal == CrystalBarrier.Either:
h_type = hook_from_door(hook)
if h_type not in blue_hooks:
new_blues = True
blue_hooks.append(h_type)
if piece.hanger_crystal == CrystalBarrier.Either:
h_type = hanger_from_door(piece.hanger_info)
if h_type not in blue_hangers:
new_blues = True
blue_hangers.append(h_type)
doors_to_check = set()
for door in not_blue: # am I now blue?
hang_type = hanger_from_door(door) # am I hangable on a hook?
hook_type = hook_from_door(door) # am I hookable onto a hanger?
if (hang_type in blue_hooks and not door.stonewall) or hook_type in blue_hangers:
explore_blue_state(door, dungeon, o_state_cache[door.name], proposed_map, valid_doors, world, player)
doors_to_check.add(door)
not_blue.difference_update(doors_to_check)
def explore_blue_state(door, dungeon, o_state, proposed_map, valid_doors, world, player):
parent = parent_region(door, world, player).parent_region
blue_start = ExplorationState(CrystalBarrier.Blue)
b_state = extend_reachable_state_improved([parent], blue_start, proposed_map, valid_doors, world, player)
dungeon[door.name] = create_graph_piece_from_state(door, o_state, b_state, proposed_map)
def make_a_choice(dungeon, hangers, avail_hooks, prev_choices):
# choose a hanger
all_hooks = set()
@@ -268,14 +296,21 @@ def create_graph_piece_from_state(door, o_state, b_state, proposed_map):
if all_unattached[d] != exp_d.crystal:
if all_unattached[d] == CrystalBarrier.Orange and exp_d.crystal == CrystalBarrier.Blue:
all_unattached[d] = CrystalBarrier.Null
else:
elif all_unattached[d] == CrystalBarrier.Blue and exp_d.crystal == CrystalBarrier.Orange:
# the swapping case
logging.getLogger('').warning('Mismatched state @ %s (o:%s b:%s)', d.name, all_unattached[d], exp_d.crystal)
elif all_unattached[d] == CrystalBarrier.Either:
all_unattached[d] = exp_d.crystal # pessimism, and if not this, leave it alone
else:
all_unattached[exp_d.door] = exp_d.crystal
h_crystal = door.crystal if door is not None else None
for d, crystal in all_unattached.items():
if (door is None or d != door) and not d.blocked and d not in proposed_map.keys():
graph_piece.hooks[d] = crystal
if d == door:
h_crystal = crystal
graph_piece.hanger_info = door
graph_piece.hanger_crystal = h_crystal
graph_piece.visited_regions.update(o_state.visited_blue)
graph_piece.visited_regions.update(o_state.visited_orange)
graph_piece.visited_regions.update(b_state.visited_blue)
@@ -328,6 +363,15 @@ def connect_doors(a, b, world, player):
connect_one_way(world, a.name, b.name, player)
else:
connect_two_way(world, a.name, b.name, player)
dep_doors, target = [], None
if len(a.dependents) > 0:
dep_doors, target = a.dependents, b
elif len(b.dependents) > 0:
dep_doors, target = b.dependents, a
if target is not None:
target_region = world.get_entrance(target.name, player).parent_region
for dep in dep_doors:
connect_simple_door(dep, target_region, world, player)
return
# If we failed to account for a type, panic
raise RuntimeError('Unknown door type ' + a.type.name)
@@ -376,6 +420,11 @@ def connect_one_way(world, entrancename, exitname, player):
y.dest = x
def connect_simple_door(exit_door, region, world, player):
world.get_entrance(exit_door.name, player).connect(region)
exit_door.dest = region
class ExplorationState(object):
def __init__(self, init_crystal=CrystalBarrier.Orange):
@@ -518,9 +567,15 @@ class ExplorationState(object):
def add_all_doors_check_proposed(self, region, proposed_map, valid_doors, world, player):
for door in get_dungeon_doors(region, world, player):
if self.can_traverse(door):
if door.dest is None and not self.in_door_list_ic(door, self.unattached_doors)\
and door not in proposed_map.keys() and door in valid_doors:
if door.controller is not None:
door = door.controller
if door.dest is None and door not in proposed_map.keys() and door in valid_doors:
if not self.in_door_list_ic(door, self.unattached_doors):
self.append_door_to_list(door, self.unattached_doors)
else:
other = self.find_door_in_list(door, self.unattached_doors)
if self.crystal != other.crystal:
other.crystal = CrystalBarrier.Either
elif door.req_event is not None and door.req_event not in self.events and not self.in_door_list(door, self.event_doors):
self.append_door_to_list(door, self.event_doors)
elif not self.in_door_list(door, self.avail_doors):
@@ -589,6 +644,13 @@ class ExplorationState(object):
return True
return False
@staticmethod
def find_door_in_list(door, door_list):
for d in door_list:
if d.door == door:
return d
return None
def append_door_to_list(self, door, door_list):
if door.crystal == CrystalBarrier.Null:
door_list.append(ExplorableDoor(door, self.crystal))