Merge remote-tracking branch 'codemann/OverworldShuffle' into codemann_OverworldShuffle
This commit is contained in:
@@ -11,6 +11,7 @@ from yaml.representer import Representer
|
||||
import RaceRandom as random
|
||||
from BaseClasses import DoorType, LocationType
|
||||
from OverworldShuffle import default_flute_connections, flute_data
|
||||
from source.overworld.FluteShuffle import default_flute_connections, flute_data
|
||||
from source.tools.MysteryUtils import get_weights, roll_settings
|
||||
from Utils import HexInt, hex_representer
|
||||
|
||||
|
||||
270
source/overworld/FluteShuffle.py
Normal file
270
source/overworld/FluteShuffle.py
Normal file
@@ -0,0 +1,270 @@
|
||||
import copy
|
||||
import logging
|
||||
|
||||
import RaceRandom as random
|
||||
from BaseClasses import Entrance, RegionType, Terrain
|
||||
from DungeonGenerator import GenerationException
|
||||
from OWEdges import OWTileRegions
|
||||
from source.overworld.EntranceShuffle2 import connect_simple
|
||||
|
||||
|
||||
def shuffle_flute_spots(world, player):
|
||||
def connect_flutes(flute_destinations):
|
||||
for o in range(0, len(flute_destinations)):
|
||||
owid = flute_destinations[o]
|
||||
regions = flute_data[owid][0]
|
||||
if not world.is_tile_swapped(owid, player):
|
||||
connect_simple(world, 'Flute Spot ' + str(o + 1), regions[0], player)
|
||||
else:
|
||||
connect_simple(world, 'Flute Spot ' + str(o + 1), regions[1], player)
|
||||
|
||||
if world.owFluteShuffle[player] == 'vanilla':
|
||||
flute_spots = default_flute_connections.copy()
|
||||
sort_flute_spots(world, player, flute_spots)
|
||||
world.owflutespots[player] = flute_spots
|
||||
connect_flutes(flute_spots)
|
||||
else:
|
||||
from OverworldShuffle import one_way_ledges
|
||||
|
||||
flute_spots = 8
|
||||
flute_pool = list(flute_data.keys())
|
||||
new_spots = list()
|
||||
ignored_regions = set()
|
||||
used_flute_regions = []
|
||||
forbidden_spots = []
|
||||
forbidden_regions = []
|
||||
|
||||
def addSpot(owid, ignore_proximity, forced):
|
||||
if world.owFluteShuffle[player] == 'balanced':
|
||||
def getIgnored(regionname, base_owid, owid):
|
||||
region = world.get_region(regionname, player)
|
||||
for exit in region.exits:
|
||||
if exit.connected_region is not None and exit.connected_region.type in [RegionType.LightWorld, RegionType.DarkWorld] and exit.connected_region.name not in new_ignored:
|
||||
if exit.connected_region.name in OWTileRegions and (OWTileRegions[exit.connected_region.name] in [base_owid, owid] or OWTileRegions[regionname] == base_owid):
|
||||
new_ignored.add(exit.connected_region.name)
|
||||
getIgnored(exit.connected_region.name, base_owid, OWTileRegions[exit.connected_region.name])
|
||||
if regionname in one_way_ledges:
|
||||
for ledge_region in one_way_ledges[regionname]:
|
||||
if ledge_region not in new_ignored:
|
||||
new_ignored.add(ledge_region)
|
||||
getIgnored(ledge_region, base_owid, OWTileRegions[ledge_region])
|
||||
|
||||
if not world.is_tile_swapped(owid, player):
|
||||
new_region = flute_data[owid][0][0]
|
||||
else:
|
||||
new_region = flute_data[owid][0][1]
|
||||
|
||||
if new_region in ignored_regions and not forced:
|
||||
return False
|
||||
|
||||
new_ignored = {new_region}
|
||||
getIgnored(new_region, OWTileRegions[new_region], OWTileRegions[new_region])
|
||||
if not ignore_proximity and not forced and random.randint(0, 31) != 0 and new_ignored.intersection(ignored_regions):
|
||||
return False
|
||||
ignored_regions.update(new_ignored)
|
||||
if owid in flute_pool:
|
||||
flute_pool.remove(owid)
|
||||
if ignore_proximity and not forced:
|
||||
logging.getLogger('').warning(f'Warning: Adding flute spot within proximity: {hex(owid)}')
|
||||
logging.getLogger('').debug(f'Placing flute at: {hex(owid)}')
|
||||
new_spots.append(owid)
|
||||
else:
|
||||
# TODO: Inspect later, seems to happen only with 'random' flute shuffle
|
||||
logging.getLogger('').warning(f'Warning: Attempted to place flute spot not in pool: {hex(owid)}')
|
||||
return True
|
||||
|
||||
if world.customizer:
|
||||
custom_spots = world.customizer.get_owflutespots()
|
||||
if custom_spots and player in custom_spots:
|
||||
if 'force' in custom_spots[player]:
|
||||
for id in custom_spots[player]['force']:
|
||||
owid = id & 0xBF
|
||||
addSpot(owid, True, True)
|
||||
flute_spots -= 1
|
||||
if not world.is_tile_swapped(owid, player):
|
||||
used_flute_regions.append(flute_data[owid][0][0])
|
||||
else:
|
||||
used_flute_regions.append(flute_data[owid][0][1])
|
||||
if 'forbid' in custom_spots[player]:
|
||||
for id in custom_spots[player]['forbid']:
|
||||
owid = id & 0xBF
|
||||
if owid not in new_spots:
|
||||
forbidden_spots.append(owid)
|
||||
if not world.is_tile_swapped(owid, player):
|
||||
forbidden_regions.append(flute_data[owid][0][0])
|
||||
else:
|
||||
forbidden_regions.append(flute_data[owid][0][1])
|
||||
|
||||
# determine sectors (isolated groups of regions) to place flute spots
|
||||
flute_regions = {(f[0][0] if (o not in world.owswaps[player][0]) != (world.mode[player] == 'inverted') else f[0][1]) : o for o, f in flute_data.items() if o not in new_spots and o not in forbidden_spots}
|
||||
flute_sectors = [(len([r for l in s for r in l]), [r for l in s for r in l if r in flute_regions]) for s in world.owsectors[player]]
|
||||
flute_sectors = [s for s in flute_sectors if len(s[1]) > 0]
|
||||
region_total = sum([c for c,_ in flute_sectors])
|
||||
sector_total = len(flute_sectors)
|
||||
empty_sector_total = 0
|
||||
sector_has_spot = []
|
||||
|
||||
# determine which sectors still need a flute spot
|
||||
for sector in flute_sectors:
|
||||
already_has_spot = any(region in sector for region in used_flute_regions)
|
||||
sector_has_spot.append(already_has_spot)
|
||||
if not already_has_spot:
|
||||
empty_sector_total += 1
|
||||
if flute_spots < empty_sector_total:
|
||||
logging.getLogger('').warning(f'Warning: Not every sector can have a flute spot, generation might fail')
|
||||
# pretend like some of the empty sectors already have a flute spot, don't know if they will be reachable
|
||||
for i in range(len(flute_sectors)):
|
||||
if not sector_has_spot[i]:
|
||||
sector_has_spot[i] = True
|
||||
empty_sector_total -= 1
|
||||
if flute_spots == empty_sector_total:
|
||||
break
|
||||
|
||||
# distribute flute spots for each sector
|
||||
for i in range(len(flute_sectors)):
|
||||
sector = flute_sectors[i]
|
||||
sector_total -= 1
|
||||
if not sector_has_spot[i]:
|
||||
empty_sector_total -= 1
|
||||
spots_to_place = min(flute_spots - empty_sector_total, max(0 if sector_has_spot[i] else 1, round((sector[0] * (flute_spots - sector_total) / region_total) + 0.5)))
|
||||
target_spots = len(new_spots) + spots_to_place
|
||||
logging.getLogger('').debug(f'Sector of {sector[0]} regions gets {spots_to_place} spot(s)')
|
||||
|
||||
if 0x30 in flute_pool and 0x30 not in forbidden_spots and len(new_spots) < target_spots and ('Desert Teleporter Ledge' in sector[1] or 'Mire Teleporter Ledge' in sector[1]):
|
||||
addSpot(0x30, True, True) # guarantee desert/mire access
|
||||
|
||||
random.shuffle(sector[1])
|
||||
f = 0
|
||||
t = 0
|
||||
while len(new_spots) < target_spots:
|
||||
if f >= len(sector[1]):
|
||||
f = 0
|
||||
t += 1
|
||||
if t > 5:
|
||||
raise GenerationException('Infinite loop detected in flute shuffle')
|
||||
owid = flute_regions[sector[1][f]]
|
||||
if owid not in new_spots and owid not in forbidden_spots:
|
||||
addSpot(owid, t > 0, False)
|
||||
f += 1
|
||||
|
||||
region_total -= sector[0]
|
||||
flute_spots -= spots_to_place
|
||||
|
||||
# connect new flute spots
|
||||
sort_flute_spots(world, player, new_spots)
|
||||
world.owflutespots[player] = new_spots
|
||||
connect_flutes(new_spots)
|
||||
|
||||
# update spoiler
|
||||
#new_spots = list(map(lambda o: flute_data[o][1], new_spots))
|
||||
s = list(map(lambda x: ' ' if x not in new_spots else 'F', [i for i in range(0x40)]))
|
||||
text_output = flute_spoiler_table.replace('s', '%s') % ( s[0x02], s[0x07],
|
||||
s[0x00], s[0x03], s[0x05],
|
||||
s[0x00], s[0x02],s[0x03], s[0x05], s[0x07], s[0x0a], s[0x0f],
|
||||
s[0x0a], s[0x0f],
|
||||
s[0x10],s[0x11],s[0x12],s[0x13],s[0x14],s[0x15],s[0x16],s[0x17], s[0x10],s[0x11],s[0x12],s[0x13],s[0x14],s[0x15],s[0x16],s[0x17],
|
||||
s[0x18], s[0x1a],s[0x1b], s[0x1d],s[0x1e],
|
||||
s[0x22], s[0x25], s[0x1a], s[0x1d],
|
||||
s[0x28],s[0x29],s[0x2a],s[0x2b],s[0x2c],s[0x2d],s[0x2e],s[0x2f], s[0x18], s[0x1b], s[0x1e],
|
||||
s[0x30], s[0x32],s[0x33],s[0x34],s[0x35], s[0x37], s[0x22], s[0x25],
|
||||
s[0x3a],s[0x3b],s[0x3c], s[0x3f],
|
||||
s[0x28],s[0x29],s[0x2a],s[0x2b],s[0x2c],s[0x2d],s[0x2e],s[0x2f],
|
||||
s[0x32],s[0x33],s[0x34], s[0x37],
|
||||
s[0x30], s[0x35],
|
||||
s[0x3a],s[0x3b],s[0x3c], s[0x3f])
|
||||
world.spoiler.set_map('flute', text_output, new_spots, player)
|
||||
create_dynamic_flute_exits(world, player)
|
||||
|
||||
|
||||
def sort_flute_spots(world, player, flute_spots):
|
||||
if world.owLayout[player] != 'grid':
|
||||
flute_spots.sort(key=lambda id: flute_data[id][1] if id != 0x03 or not world.is_tile_swapped(0x03, player) else 0x04)
|
||||
else:
|
||||
world_layout = world.owgrid[player][0] if world.mode[player] != 'inverted' else world.owgrid[player][1]
|
||||
layout_list = sum(world_layout, [])
|
||||
layout_map = {id & 0xBF: i for i, id in enumerate(layout_list)}
|
||||
flute_spots.sort(key=lambda id: layout_map[flute_data[id][1] if id != 0x03 or not world.is_tile_swapped(0x03, player) else 0x04])
|
||||
|
||||
|
||||
def create_dynamic_flute_exits(world, player):
|
||||
flute_in_pool = True if player not in world.customitemarray else any(i for i, n in world.customitemarray[player].items() if i == 'flute' and n > 0)
|
||||
if not flute_in_pool:
|
||||
return
|
||||
for region in (r for r in world.regions if r.player == player and r.terrain == Terrain.Land and r.name not in ['Zoras Domain', 'Master Sword Meadow', 'Hobo Bridge']):
|
||||
if region.type == (RegionType.LightWorld if world.mode[player] != 'inverted' else RegionType.DarkWorld):
|
||||
exitname = 'Flute From ' + region.name
|
||||
exit = Entrance(region.player, exitname, region)
|
||||
exit.spot_type = 'Flute'
|
||||
exit.connect(world.get_region('Flute Sky', player))
|
||||
region.exits.append(exit)
|
||||
world.initialize_regions()
|
||||
|
||||
|
||||
default_flute_connections = [
|
||||
0x03, 0x16, 0x18, 0x2c, 0x2f, 0x30, 0x3b, 0x3f
|
||||
]
|
||||
|
||||
flute_data = {
|
||||
#OWID LW Region DW Region Slot VRAM BG Y BG X Link Y Link X Cam Y Cam X Unk1 Unk2 IconY IconX AltY AltX AltVRAM AltBGY AltBGX AltCamY AltCamX AltUnk1 AltUnk2 AltIconY AltIconX
|
||||
0x00: (['Lost Woods East Area', 'Skull Woods Forest'], 0x09, 0x1042, 0x022e, 0x0202, 0x0290, 0x0288, 0x029b, 0x028f, 0xfff2, 0x000e, 0x0290, 0x0288, 0x0290, 0x0290),
|
||||
0x02: (['Lumberjack Area', 'Dark Lumberjack Area'], 0x02, 0x059c, 0x00d6, 0x04e6, 0x0138, 0x0558, 0x0143, 0x0563, 0xfffa, 0xfffa, 0x01d8, 0x0518),
|
||||
0x03: (['West Death Mountain (Bottom)', 'West Dark Death Mountain (Top)'], 0x0b, 0x1600, 0x02ca, 0x060e, 0x0328, 0x0678, 0x0337, 0x0683, 0xfff6, 0xfff2, 0x03bb, 0x0680, 0x0118, 0x0860, 0x05c0, 0x00b8, 0x07ec, 0x0127, 0x086b, 0xfff8, 0x0004, 0x0148, 0x0850),
|
||||
0x05: (['East Death Mountain (Bottom)', 'East Dark Death Mountain (Bottom)'], 0x0e, 0x1860, 0x031e, 0x0d00, 0x0388, 0x0da8, 0x038d, 0x0d7d, 0x0000, 0x0000, 0x03c8, 0x0d98),
|
||||
0x07: (['Death Mountain TR Pegs Area', 'Turtle Rock Area'], 0x07, 0x0804, 0x0102, 0x0e1a, 0x0160, 0x0e90, 0x016f, 0x0e97, 0xfffe, 0x0006, 0x0150, 0x0ea0),
|
||||
0x0a: (['Mountain Pass Area', 'Bumper Cave Area'], 0x0a, 0x0180, 0x0220, 0x0406, 0x0280, 0x0488, 0x028f, 0x0493, 0x0000, 0xfffa, 0x0390, 0x04d8),
|
||||
0x0f: (['Zora Waterfall Area', 'Catfish Area'], 0x0f, 0x0316, 0x025c, 0x0eb2, 0x02c0, 0x0f28, 0x02cb, 0x0f2f, 0x0002, 0xfffe, 0x0360, 0x0f58),
|
||||
0x10: (['Lost Woods Pass West Area', 'Skull Woods Pass West Area'], 0x10, 0x0080, 0x0400, 0x0000, 0x0448, 0x0058, 0x046f, 0x0085, 0x0000, 0x0000, 0x04f8, 0x0088),
|
||||
0x11: (['Kakariko Fortune Area', 'Dark Fortune Area'], 0x11, 0x0912, 0x051e, 0x0292, 0x0588, 0x0318, 0x058d, 0x031f, 0x0000, 0xfffe, 0x05f8, 0x0318),
|
||||
0x12: (['Kakariko Pond Area', 'Outcast Pond Area'], 0x12, 0x0890, 0x051a, 0x0476, 0x0578, 0x04f8, 0x0587, 0x0503, 0xfff6, 0x000a, 0x05b8, 0x04f8),
|
||||
0x13: (['Sanctuary Area', 'Dark Chapel Area'], 0x13, 0x051c, 0x04aa, 0x06de, 0x0508, 0x0758, 0x0517, 0x0763, 0xfff6, 0x0002, 0x05b8, 0x0738),
|
||||
0x14: (['Graveyard Area', 'Dark Graveyard Area'], 0x14, 0x089c, 0x051e, 0x08e6, 0x0580, 0x0958, 0x058b, 0x0963, 0x0000, 0xfffa, 0x05f0, 0x0918, 0x0580, 0x0948),
|
||||
0x15: (['River Bend East Bank', 'Qirn Jump East Bank'], 0x15, 0x041a, 0x0486, 0x0ad2, 0x04e8, 0x0b48, 0x04f3, 0x0b4f, 0x0008, 0xfffe, 0x0548, 0x0b78),
|
||||
0x16: (['Potion Shop Area', 'Dark Witch Area'], 0x16, 0x0888, 0x0516, 0x0c4e, 0x0578, 0x0cc8, 0x0583, 0x0cd3, 0xfffa, 0xfff2, 0x05e8, 0x0c9f),
|
||||
0x17: (['Zora Approach Ledge', 'Catfish Approach Ledge'], 0x17, 0x039e, 0x047e, 0x0ef2, 0x04e0, 0x0f68, 0x04eb, 0x0f6f, 0x0000, 0xfffe, 0x0580, 0x0f48),
|
||||
0x18: (['Kakariko Village', 'Village of Outcasts'], 0x18, 0x0b30, 0x0759, 0x017e, 0x07b7, 0x0200, 0x07c6, 0x020b, 0x0007, 0x0002, 0x0830, 0x0240, 0x07c8, 0x01f8),
|
||||
0x1a: (['Forgotten Forest Area', 'Shield Shop Fence'], 0x1a, 0x081a, 0x070f, 0x04d2, 0x0770, 0x0548, 0x077c, 0x054f, 0xffff, 0xfffe, 0x0770, 0x0518),
|
||||
0x1b: (['Hyrule Castle Courtyard', 'Pyramid Area'], 0x1b, 0x0c30, 0x077a, 0x0786, 0x07d8, 0x07f8, 0x07e7, 0x0803, 0x0006, 0xfffa, 0x07f8, 0x07f8),
|
||||
0x1d: (['Wooden Bridge Area', 'Broken Bridge Northeast'], 0x1d, 0x0602, 0x06c2, 0x0a0e, 0x0720, 0x0a80, 0x072f, 0x0a8b, 0xfffe, 0x0002, 0x0750, 0x0a70),
|
||||
0x1e: (['Eastern Palace Area', 'Palace of Darkness Area'], 0x26, 0x1802, 0x091e, 0x0c0e, 0x09c0, 0x0c80, 0x098b, 0x0c8b, 0x0000, 0x0002, 0x09a0, 0x0cb0),
|
||||
0x22: (['Blacksmith Area', 'Hammer Pegs Area'], 0x22, 0x058c, 0x08aa, 0x0462, 0x0908, 0x04d8, 0x0917, 0x04df, 0x0006, 0xfffe, 0x0978, 0x04e8),
|
||||
0x25: (['Sand Dunes Area', 'Dark Dunes Area'], 0x25, 0x030e, 0x085a, 0x0a76, 0x08b8, 0x0ae8, 0x08c7, 0x0af3, 0x0006, 0xfffa, 0x0918, 0x0b18),
|
||||
0x28: (['Maze Race Area', 'Dig Game Area'], 0x28, 0x0908, 0x0b1e, 0x003a, 0x0b88, 0x00b8, 0x0b8d, 0x00bf, 0x0000, 0x0006, 0x0ba8, 0x00b8),
|
||||
0x29: (['Kakariko Suburb Area', 'Frog Area'], 0x29, 0x0408, 0x0a7c, 0x0242, 0x0ae0, 0x02c0, 0x0aeb, 0x02c7, 0x0002, 0xfffe, 0x0b30, 0x02e0),
|
||||
0x2a: (['Flute Boy Area', 'Stumpy Area'], 0x2a, 0x058e, 0x0aac, 0x046e, 0x0b10, 0x04e8, 0x0b1b, 0x04f3, 0x0002, 0x0002, 0x0b60, 0x04f8),
|
||||
0x2b: (['Central Bonk Rocks Area', 'Dark Bonk Rocks Area'], 0x2b, 0x0620, 0x0acc, 0x0700, 0x0b30, 0x0790, 0x0b3b, 0x0785, 0xfff2, 0x0000, 0x0b80, 0x0760),
|
||||
0x2c: (['Links House Area', 'Big Bomb Shop Area'], 0x2c, 0x0588, 0x0ab9, 0x0840, 0x0b17, 0x08b8, 0x0b26, 0x08bf, 0xfff7, 0x0000, 0x0bb0, 0x08a8),
|
||||
0x2d: (['Stone Bridge South Area', 'Hammer Bridge South Area'], 0x2d, 0x0886, 0x0b1e, 0x0a2a, 0x0ba0, 0x0aa8, 0x0b8b, 0x0aaf, 0x0000, 0x0006, 0x0bf0, 0x0ab8),
|
||||
0x2e: (['Tree Line Area', 'Dark Tree Line Area'], 0x2e, 0x0100, 0x0a1a, 0x0c00, 0x0a78, 0x0c30, 0x0a87, 0x0c7d, 0x0006, 0x0000, 0x0ac8, 0x0c70),
|
||||
0x2f: (['Eastern Nook Area', 'Darkness Nook Area'], 0x2f, 0x0798, 0x0afa, 0x0eb2, 0x0b58, 0x0f30, 0x0b67, 0x0f37, 0xfff6, 0x000e, 0x0bc0, 0x0f00),
|
||||
0x30: (['Desert Teleporter Ledge', 'Mire Teleporter Ledge'], 0x38, 0x1880, 0x0f1e, 0x0000, 0x0fa8, 0x0078, 0x0f8d, 0x008d, 0x0000, 0x0000, 0x0ff0, 0x0070),
|
||||
0x32: (['Flute Boy Approach Area', 'Stumpy Approach Area'], 0x32, 0x03a0, 0x0c6c, 0x0500, 0x0cd0, 0x05a8, 0x0cdb, 0x0585, 0x0002, 0x0000, 0x0d00, 0x0528),
|
||||
0x33: (['C Whirlpool Outer Area', 'Dark C Whirlpool Outer Area'], 0x33, 0x0180, 0x0c20, 0x0600, 0x0c80, 0x0628, 0x0c8f, 0x067d, 0x0000, 0x0000, 0x0ce0, 0x0688),
|
||||
0x34: (['Statues Area', 'Hype Cave Area'], 0x34, 0x088e, 0x0d00, 0x0866, 0x0d60, 0x08d8, 0x0d6f, 0x08e3, 0x0000, 0x000a, 0x0dd0, 0x08e8),
|
||||
#0x35: (['Lake Hylia Northwest Bank', 'Ice Lake Northwest Bank'], 0x35, 0x0d00, 0x0da6, 0x0a06, 0x0e08, 0x0a80, 0x0e13, 0x0a8b, 0xfffa, 0xfffa, 0x0dc8, 0x0a90),
|
||||
0x35: (['Lake Hylia South Shore', 'Ice Lake Southeast Ledge'], 0x3e, 0x1860, 0x0f1e, 0x0d00, 0x0f98, 0x0da8, 0x0f8b, 0x0d85, 0x0000, 0x0000, 0x0fd8, 0x0da8),
|
||||
0x37: (['Ice Cave Area', 'Shopping Mall Area'], 0x37, 0x0786, 0x0cf6, 0x0e2e, 0x0d58, 0x0ea0, 0x0d63, 0x0eab, 0x000a, 0x0002, 0x0d98, 0x0ed0),
|
||||
0x3a: (['Desert Pass Area', 'Swamp Nook Area'], 0x3a, 0x001a, 0x0e08, 0x04c6, 0x0e70, 0x0540, 0x0e7d, 0x054b, 0x0006, 0x000a, 0x0ee0, 0x0570),
|
||||
0x3b: (['Dam Area', 'Swamp Area'], 0x3b, 0x069e, 0x0edf, 0x06f2, 0x0f3d, 0x0778, 0x0f4c, 0x077f, 0xfff1, 0xfffe, 0x0fd0, 0x0770),
|
||||
0x3c: (['South Pass Area', 'Dark South Pass Area'], 0x3c, 0x0584, 0x0ed0, 0x081e, 0x0f38, 0x0898, 0x0f45, 0x08a3, 0xfffe, 0x0002, 0x0fa8, 0x0898),
|
||||
0x3f: (['Octoballoon Area', 'Bomber Corner Area'], 0x3f, 0x0810, 0x0f05, 0x0e75, 0x0f67, 0x0ef3, 0x0f72, 0x0efa, 0xfffb, 0x000b, 0x0fd0, 0x0ef0)
|
||||
}
|
||||
|
||||
flute_spoiler_table = \
|
||||
""" 0 1 2 3 4 5 6 7
|
||||
+---+-+---+---+-+
|
||||
01234567 A(00)| |s| | |s|
|
||||
+--------+ | s +-+ s | s +-+
|
||||
A(00)|s ss s s| B(08)| |s| | |s|
|
||||
B(08)| s s| +-+-+-+-+-+-+-+-+
|
||||
C(10)|ssssssss| C(10)|s|s|s|s|s|s|s|s|
|
||||
D(18)|s ss ss | +-+-+-+-+-+-+-+-+
|
||||
E(20)| s s | D(18)| |s| |s| |
|
||||
F(28)|ssssssss| | s +-+ s +-+ s |
|
||||
G(30)|s ssss s| E(20)| |s| |s| |
|
||||
H(38)| sss s| +-+-+-+-+-+-+-+-+
|
||||
+--------+ F(28)|s|s|s|s|s|s|s|s|
|
||||
+-+-+-+-+-+-+-+-+
|
||||
G(30)| |s|s|s| |s|
|
||||
| s +-+-+-+ s +-+
|
||||
H(38)| |s|s|s| |s|
|
||||
+---+-+-+-+---+-+"""
|
||||
@@ -1,9 +1,10 @@
|
||||
import copy
|
||||
import logging
|
||||
import RaceRandom as random
|
||||
import random as _random
|
||||
from typing import List, Dict, Optional, Set, Tuple
|
||||
from BaseClasses import OWEdge, World, Direction, Terrain
|
||||
from typing import Dict, List, Optional, Set, Tuple
|
||||
|
||||
import RaceRandom as random
|
||||
from BaseClasses import Direction, OWEdge, Terrain, World
|
||||
from OverworldShuffle import connect_two_way, validate_layout
|
||||
|
||||
ENABLE_KEEP_SIMILAR_SPECIAL_HANDLING = False
|
||||
|
||||
@@ -2,10 +2,13 @@ import logging
|
||||
import os
|
||||
from datetime import datetime
|
||||
from typing import Dict, List
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
from BaseClasses import Direction, OWEdge
|
||||
from source.overworld.LayoutGenerator import Screen
|
||||
|
||||
|
||||
def get_edge_lists(grid: List[List[List[int]]],
|
||||
overworld_screens: Dict[int, Screen],
|
||||
large_screen_quadrant_info: Dict[int, Dict]) -> Dict:
|
||||
|
||||
Reference in New Issue
Block a user