Merge remote-tracking branch 'remotes/door_rando/DoorDev' into Dev

This commit is contained in:
compiling
2020-01-11 09:17:41 +11:00
15 changed files with 213 additions and 43 deletions

View File

@@ -2,7 +2,9 @@ import copy
from enum import Enum, unique
import logging
import json
from collections import OrderedDict
from collections import OrderedDict, deque
from EntranceShuffle import door_addresses
from _vendor.collections_extended import bag
from EntranceShuffle import door_addresses
from Utils import int16_as_bytes
@@ -373,6 +375,7 @@ class CollectionState(object):
self.prog_items = bag()
self.world = parent
self.reachable_regions = {player: set() for player in range(1, parent.players + 1)}
self.colored_regions = {player: {} for player in range(1, parent.players + 1)}
self.events = []
self.path = {}
self.locations_checked = set()
@@ -384,6 +387,7 @@ class CollectionState(object):
player_regions = self.world.get_regions(player)
self.stale[player] = False
rrp = self.reachable_regions[player]
ccr = self.colored_regions[player]
new_regions = True
reachable_regions_count = len(rrp)
while new_regions:
@@ -391,13 +395,53 @@ class CollectionState(object):
for candidate in player_regions:
if candidate.can_reach_private(self):
rrp.add(candidate)
if candidate.type == RegionType.Dungeon:
c_switch_present = False
for ext in candidate.exits:
door = self.world.check_for_door(ext.name, player)
if door is not None and door.crystal == CrystalBarrier.Either:
c_switch_present = True
if c_switch_present:
ccr[candidate] = CrystalBarrier.Either
self.spread_crystal_access(candidate, CrystalBarrier.Either, rrp, ccr, player)
else:
for entrance in candidate.entrances:
door = self.world.check_for_door(entrance.name, player)
if door is None or entrance.parent_region.type != RegionType.Dungeon:
ccr[candidate] = CrystalBarrier.Orange
if entrance.parent_region in ccr.keys():
color_type = ccr[entrance.parent_region]
current_type = ccr[candidate] if candidate in ccr.keys() else None
ccr[candidate] = color_type if current_type is None or color_type == current_type else CrystalBarrier.Either
new_regions = len(rrp) > reachable_regions_count
reachable_regions_count = len(rrp)
def spread_crystal_access(self, region, crystal, rrp, ccr, player):
queue = deque([(region, crystal)])
visited = set()
while len(queue) > 0:
region, crystal = queue.popleft()
visited.add(region)
for ext in region.exits:
connect = ext.connected_region
if connect not in visited and connect is not None and connect.type == RegionType.Dungeon:
if connect in rrp and ext.can_reach(self) and connect:
door = self.world.check_for_door(ext.name, player)
current_crystal = ccr[connect]
if door is not None and not door.blocked and current_crystal != crystal and current_crystal != CrystalBarrier.Either:
if door.crystal in [CrystalBarrier.Either, CrystalBarrier.Null]:
ccr[connect] = crystal
queue.append((connect, crystal))
else:
queue.append((connect, door.crystal))
if door.crystal != current_crystal:
ccr[connect] = CrystalBarrier.Either
def copy(self):
ret = CollectionState(self.world)
ret.prog_items = self.prog_items.copy()
ret.reachable_regions = {player: copy.copy(self.reachable_regions[player]) for player in range(1, self.world.players + 1)}
ret.colored_regions = {player: copy.copy(self.colored_regions[player]) for player in range(1, self.world.players + 1)}
ret.events = copy.copy(self.events)
ret.path = copy.copy(self.path)
ret.locations_checked = copy.copy(self.locations_checked)
@@ -418,6 +462,15 @@ class CollectionState(object):
return spot.can_reach(self)
def sweep_for_crystal_access(self):
for player, rrp in self.reachable_regions.items():
dungeon_regions = [x for x in rrp if x.type == RegionType.Dungeon]
ccr = self.colored_regions[player]
for region in dungeon_regions:
if region in ccr.keys():
self.spread_crystal_access(region, ccr[region], rrp, ccr, player)
self.stale[player] = True
def sweep_for_events(self, key_only=False, locations=None):
# this may need improvement
if locations is None:
@@ -435,6 +488,18 @@ class CollectionState(object):
self.collect(event.item, True, event)
new_locations = len(reachable_events) > checked_locations
checked_locations = len(reachable_events)
if new_locations:
self.sweep_for_crystal_access()
def can_reach_blue(self, region, player):
if region not in self.colored_regions[player].keys():
return False
return self.colored_regions[player][region] in [CrystalBarrier.Blue, CrystalBarrier.Either]
def can_reach_orange(self, region, player):
if region not in self.colored_regions[player].keys():
return False
return self.colored_regions[player][region] in [CrystalBarrier.Orange, CrystalBarrier.Either]
def _do_not_flood_the_keys(self, reachable_events):
adjusted_checks = list(reachable_events)
@@ -721,7 +786,7 @@ class CollectionState(object):
class RegionType(Enum):
LightWorld = 1
DarkWorld = 2
Cave = 3 # Also includes Houses
Cave = 3 # Also includes Houses
Dungeon = 4
@property
@@ -1277,7 +1342,6 @@ class Shop(object):
def __init__(self, region, room_id, type, shopkeeper_config, custom, locked):
self.region = region
self.room_id = room_id
self.default_door_id = default_door_id
self.type = type
self.inventory = [None, None, None]
self.shopkeeper_config = shopkeeper_config
@@ -1297,8 +1361,6 @@ class Shop(object):
config = self.item_count
if len(entrances) == 1 and entrances[0].name in door_addresses:
door_id = door_addresses[entrances[0].name][0]+1
elif self.default_door_id is not None:
door_id = self.default_door_id
else:
door_id = 0
config |= 0x40 # ignore door id