Merge pull request #30 from Catobat/GridImprovements
Grid Layout Shuffle Customizer and improvements
This commit is contained in:
@@ -567,7 +567,7 @@ def link_overworld(world, player):
|
|||||||
remove_connected(forward_edge_sets, back_edge_sets)
|
remove_connected(forward_edge_sets, back_edge_sets)
|
||||||
assert len(connected_edges) == len(default_connections) * 2, connected_edges
|
assert len(connected_edges) == len(default_connections) * 2, connected_edges
|
||||||
|
|
||||||
valid_layout = validate_layout(world, player)
|
valid_layout = world.accessibility[player] == 'none' or validate_layout(world, player)
|
||||||
|
|
||||||
tries -= 1
|
tries -= 1
|
||||||
assert valid_layout, 'Could not find a valid OW layout'
|
assert valid_layout, 'Could not find a valid OW layout'
|
||||||
@@ -1369,9 +1369,6 @@ def build_accessible_region_list(world, start_region, player, build_copy_world=F
|
|||||||
return explored_regions
|
return explored_regions
|
||||||
|
|
||||||
def validate_layout(world, player):
|
def validate_layout(world, player):
|
||||||
if world.accessibility[player] == 'none':
|
|
||||||
return True
|
|
||||||
|
|
||||||
entrance_connectors = {
|
entrance_connectors = {
|
||||||
'East Death Mountain (Bottom)': ['East Death Mountain (Top East)'],
|
'East Death Mountain (Bottom)': ['East Death Mountain (Top East)'],
|
||||||
'Kakariko Suburb Area': ['Maze Race Ledge'],
|
'Kakariko Suburb Area': ['Maze Race Ledge'],
|
||||||
@@ -1458,7 +1455,7 @@ def validate_layout(world, player):
|
|||||||
while unreachable_count != len(unreachable_regions):
|
while unreachable_count != len(unreachable_regions):
|
||||||
# find unreachable regions
|
# find unreachable regions
|
||||||
unreachable_regions = {}
|
unreachable_regions = {}
|
||||||
for region_name in list(OWTileRegions.copy().keys()):
|
for region_name in list(OWTileRegions.keys()):
|
||||||
if region_name not in explored_regions and region_name not in isolated_regions:
|
if region_name not in explored_regions and region_name not in isolated_regions:
|
||||||
region = world.get_region(region_name, player)
|
region = world.get_region(region_name, player)
|
||||||
unreachable_regions[region_name] = region
|
unreachable_regions[region_name] = region
|
||||||
@@ -1504,6 +1501,52 @@ def validate_layout(world, player):
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def get_separate_ow_areas(world, player):
|
||||||
|
"""
|
||||||
|
Returns a list of separated areas in the overworld layout.
|
||||||
|
It looks at the distinct connected components when only considering
|
||||||
|
OW edge and whirlpool connections (no entrances, portals, mirror, or flute).
|
||||||
|
Uses Union-Find to handle directed edges properly (treats them as undirected).
|
||||||
|
"""
|
||||||
|
parent = {}
|
||||||
|
|
||||||
|
def find(x):
|
||||||
|
if x not in parent:
|
||||||
|
parent[x] = x
|
||||||
|
if parent[x] != x:
|
||||||
|
parent[x] = find(parent[x]) # Path compression
|
||||||
|
return parent[x]
|
||||||
|
|
||||||
|
def union(x, y):
|
||||||
|
root_x = find(x)
|
||||||
|
root_y = find(y)
|
||||||
|
if root_x != root_y:
|
||||||
|
parent[root_y] = root_x
|
||||||
|
|
||||||
|
all_regions = set(OWTileRegions.keys()) - set(isolated_regions)
|
||||||
|
considered_exit_spot_types = set(['OpenTerrain', 'OWTerrain', 'Ledge', 'OWEdge', 'Whirlpool'])
|
||||||
|
|
||||||
|
# Initialize all regions in Union-Find
|
||||||
|
for region_name in all_regions:
|
||||||
|
find(region_name)
|
||||||
|
|
||||||
|
# Build connections by examining all edges (treating directed as undirected)
|
||||||
|
for region_name in all_regions:
|
||||||
|
region = world.get_region(region_name, player)
|
||||||
|
for exit in region.exits:
|
||||||
|
if exit.spot_type in considered_exit_spot_types and exit.connected_region is not None and exit.connected_region.name in all_regions:
|
||||||
|
union(region_name, exit.connected_region.name)
|
||||||
|
|
||||||
|
# Group regions by their root
|
||||||
|
areas = {}
|
||||||
|
for region_name in all_regions:
|
||||||
|
root = find(region_name)
|
||||||
|
if root not in areas:
|
||||||
|
areas[root] = []
|
||||||
|
areas[root].append(region_name)
|
||||||
|
|
||||||
|
return list(areas.values())
|
||||||
|
|
||||||
test_connections = [
|
test_connections = [
|
||||||
#('Links House ES', 'Octoballoon WS'),
|
#('Links House ES', 'Octoballoon WS'),
|
||||||
#('Links House NE', 'Lost Woods Pass SW')
|
#('Links House NE', 'Lost Woods Pass SW')
|
||||||
|
|||||||
@@ -277,10 +277,45 @@ someDescription:
|
|||||||
|
|
||||||
`grid` contains additional options that only have an effect when `ow_layout` is set to `grid`.
|
`grid` contains additional options that only have an effect when `ow_layout` is set to `grid`.
|
||||||
|
|
||||||
|
#### fixed_arrangements
|
||||||
|
|
||||||
|
Use this to dictate the relative positioning between multiple screens (or quadrants of large screens). Screens and quadrants are addressed by their OW Slot ID (independently of their world), ranging from 0x00 to 0x3F. An `arrangement` is given as a list of rows with equal lenghts. If you do not want to specify a full rectangle of screens, you can use `.` as a placeholder to allow the generator to place any screen there. The `world` property can be set to `light`, `dark` or `both` (default value) and determines for which worlds the arrangement applies.
|
||||||
|
|
||||||
|
This example forces Death Mountain to stay connected the same as vanilla in both worlds:
|
||||||
|
```
|
||||||
|
fixed_arrangements:
|
||||||
|
- arrangement:
|
||||||
|
- 0x03 0x04 0x05 0x06 0x07
|
||||||
|
- 0x0B 0x0C 0x0D 0x0E .
|
||||||
|
world: both
|
||||||
|
```
|
||||||
|
|
||||||
|
#### restricted_positions
|
||||||
|
|
||||||
|
Use this to restrict cells to a specified set of possible positions. The `world` property can be set to `light`, `dark` or `both` (default value) and determines for which worlds the restriction applies.
|
||||||
|
|
||||||
|
This example forces the Sanctuary and Link's House screens in both worlds to get placed in corners of the grid:
|
||||||
|
```
|
||||||
|
restricted_positions:
|
||||||
|
- cells:
|
||||||
|
- 0x13
|
||||||
|
- 0x2C
|
||||||
|
positions:
|
||||||
|
- 0x00
|
||||||
|
- 0x07
|
||||||
|
- 0x38
|
||||||
|
- 0x3F
|
||||||
|
world: both
|
||||||
|
```
|
||||||
|
|
||||||
#### wrap_horizontal / wrap_vertical
|
#### wrap_horizontal / wrap_vertical
|
||||||
|
|
||||||
Set these to `true` to allow for overworld edge transitions to wrap from one side of a world to the opposite side. With `wrap_horizontal`, there can be east transitions on the eastern edge of the world map that send the player to the western edge of the world. With `wrap_vertical`, there can be south transitions on the southern edge of the world map that send the player to the northern edge of the world.
|
Set these to `true` to allow for overworld edge transitions to wrap from one side of a world to the opposite side. With `wrap_horizontal`, there can be east transitions on the eastern edge of the world map that send the player to the western edge of the world. With `wrap_vertical`, there can be south transitions on the southern edge of the world map that send the player to the northern edge of the world.
|
||||||
|
|
||||||
|
#### split_large_screens
|
||||||
|
|
||||||
|
When set to `true`, the four quadrants of each large screen are placed on the grid independently of each other.
|
||||||
|
|
||||||
### ow-crossed
|
### ow-crossed
|
||||||
|
|
||||||
This must be defined by player. Each player number should be listed with the appropriate sections and each of these players MUST have `ow_crossed` enabled in the `settings` section in order for any values here to take effect. This section has four primary subsections: `force_crossed`, `force_noncrossed`, `limit_crossed`, and `undefined_chance`. There are also
|
This must be defined by player. Each player number should be listed with the appropriate sections and each of these players MUST have `ow_crossed` enabled in the `settings` section in order for any values here to take effect. This section has four primary subsections: `force_crossed`, `force_noncrossed`, `limit_crossed`, and `undefined_chance`. There are also
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
meta:
|
settings:
|
||||||
players: 1
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
two-way:
|
two-way:
|
||||||
|
|||||||
140
presets/world/owr_checkerboardshuffle.yaml
Normal file
140
presets/world/owr_checkerboardshuffle.yaml
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: grid
|
||||||
|
ow-grid:
|
||||||
|
1:
|
||||||
|
restricted_positions:
|
||||||
|
- cells:
|
||||||
|
- 0x00
|
||||||
|
- 0x02
|
||||||
|
- 0x04
|
||||||
|
- 0x06
|
||||||
|
- 0x09
|
||||||
|
- 0x0B
|
||||||
|
- 0x0D
|
||||||
|
- 0x0F
|
||||||
|
- 0x10
|
||||||
|
- 0x12
|
||||||
|
- 0x14
|
||||||
|
- 0x16
|
||||||
|
- 0x19
|
||||||
|
- 0x1B
|
||||||
|
- 0x1D
|
||||||
|
- 0x1F
|
||||||
|
- 0x20
|
||||||
|
- 0x22
|
||||||
|
- 0x24
|
||||||
|
- 0x26
|
||||||
|
- 0x29
|
||||||
|
- 0x2B
|
||||||
|
- 0x2D
|
||||||
|
- 0x2F
|
||||||
|
- 0x30
|
||||||
|
- 0x32
|
||||||
|
- 0x34
|
||||||
|
- 0x36
|
||||||
|
- 0x39
|
||||||
|
- 0x3B
|
||||||
|
- 0x3D
|
||||||
|
- 0x3F
|
||||||
|
positions:
|
||||||
|
- 0x00
|
||||||
|
- 0x02
|
||||||
|
- 0x04
|
||||||
|
- 0x06
|
||||||
|
- 0x09
|
||||||
|
- 0x0B
|
||||||
|
- 0x0D
|
||||||
|
- 0x0F
|
||||||
|
- 0x10
|
||||||
|
- 0x12
|
||||||
|
- 0x14
|
||||||
|
- 0x16
|
||||||
|
- 0x19
|
||||||
|
- 0x1B
|
||||||
|
- 0x1D
|
||||||
|
- 0x1F
|
||||||
|
- 0x20
|
||||||
|
- 0x22
|
||||||
|
- 0x24
|
||||||
|
- 0x26
|
||||||
|
- 0x29
|
||||||
|
- 0x2B
|
||||||
|
- 0x2D
|
||||||
|
- 0x2F
|
||||||
|
- 0x30
|
||||||
|
- 0x32
|
||||||
|
- 0x34
|
||||||
|
- 0x36
|
||||||
|
- 0x39
|
||||||
|
- 0x3B
|
||||||
|
- 0x3D
|
||||||
|
- 0x3F
|
||||||
|
world: both
|
||||||
|
- cells:
|
||||||
|
- 0x01
|
||||||
|
- 0x03
|
||||||
|
- 0x05
|
||||||
|
- 0x07
|
||||||
|
- 0x08
|
||||||
|
- 0x0A
|
||||||
|
- 0x0C
|
||||||
|
- 0x0E
|
||||||
|
- 0x11
|
||||||
|
- 0x13
|
||||||
|
- 0x15
|
||||||
|
- 0x17
|
||||||
|
- 0x18
|
||||||
|
- 0x1A
|
||||||
|
- 0x1C
|
||||||
|
- 0x1E
|
||||||
|
- 0x21
|
||||||
|
- 0x23
|
||||||
|
- 0x25
|
||||||
|
- 0x27
|
||||||
|
- 0x28
|
||||||
|
- 0x2A
|
||||||
|
- 0x2C
|
||||||
|
- 0x2E
|
||||||
|
- 0x31
|
||||||
|
- 0x33
|
||||||
|
- 0x35
|
||||||
|
- 0x37
|
||||||
|
- 0x38
|
||||||
|
- 0x3A
|
||||||
|
- 0x3C
|
||||||
|
- 0x3E
|
||||||
|
positions:
|
||||||
|
- 0x01
|
||||||
|
- 0x03
|
||||||
|
- 0x05
|
||||||
|
- 0x07
|
||||||
|
- 0x08
|
||||||
|
- 0x0A
|
||||||
|
- 0x0C
|
||||||
|
- 0x0E
|
||||||
|
- 0x11
|
||||||
|
- 0x13
|
||||||
|
- 0x15
|
||||||
|
- 0x17
|
||||||
|
- 0x18
|
||||||
|
- 0x1A
|
||||||
|
- 0x1C
|
||||||
|
- 0x1E
|
||||||
|
- 0x21
|
||||||
|
- 0x23
|
||||||
|
- 0x25
|
||||||
|
- 0x27
|
||||||
|
- 0x28
|
||||||
|
- 0x2A
|
||||||
|
- 0x2C
|
||||||
|
- 0x2E
|
||||||
|
- 0x31
|
||||||
|
- 0x33
|
||||||
|
- 0x35
|
||||||
|
- 0x37
|
||||||
|
- 0x38
|
||||||
|
- 0x3A
|
||||||
|
- 0x3C
|
||||||
|
- 0x3E
|
||||||
|
world: both
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
groups:
|
groups:
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
groups:
|
groups:
|
||||||
|
|||||||
147
presets/world/owr_quadrantshuffle-grid.yaml
Normal file
147
presets/world/owr_quadrantshuffle-grid.yaml
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: grid
|
||||||
|
ow-grid:
|
||||||
|
1:
|
||||||
|
restricted_positions:
|
||||||
|
- cells:
|
||||||
|
- 0x00
|
||||||
|
- 0x01
|
||||||
|
- 0x02
|
||||||
|
- 0x03
|
||||||
|
- 0x08
|
||||||
|
- 0x09
|
||||||
|
- 0x0A
|
||||||
|
- 0x0B
|
||||||
|
- 0x10
|
||||||
|
- 0x11
|
||||||
|
- 0x12
|
||||||
|
- 0x13
|
||||||
|
- 0x18
|
||||||
|
- 0x19
|
||||||
|
- 0x1A
|
||||||
|
- 0x1B
|
||||||
|
positions:
|
||||||
|
- 0x00
|
||||||
|
- 0x01
|
||||||
|
- 0x02
|
||||||
|
- 0x03
|
||||||
|
- 0x08
|
||||||
|
- 0x09
|
||||||
|
- 0x0A
|
||||||
|
- 0x0B
|
||||||
|
- 0x10
|
||||||
|
- 0x11
|
||||||
|
- 0x12
|
||||||
|
- 0x13
|
||||||
|
- 0x18
|
||||||
|
- 0x19
|
||||||
|
- 0x1A
|
||||||
|
- 0x1B
|
||||||
|
world: both
|
||||||
|
- cells:
|
||||||
|
- 0x20
|
||||||
|
- 0x21
|
||||||
|
- 0x22
|
||||||
|
- 0x23
|
||||||
|
- 0x28
|
||||||
|
- 0x29
|
||||||
|
- 0x2A
|
||||||
|
- 0x2B
|
||||||
|
- 0x30
|
||||||
|
- 0x31
|
||||||
|
- 0x32
|
||||||
|
- 0x33
|
||||||
|
- 0x38
|
||||||
|
- 0x39
|
||||||
|
- 0x3A
|
||||||
|
- 0x3B
|
||||||
|
positions:
|
||||||
|
- 0x20
|
||||||
|
- 0x21
|
||||||
|
- 0x22
|
||||||
|
- 0x23
|
||||||
|
- 0x28
|
||||||
|
- 0x29
|
||||||
|
- 0x2A
|
||||||
|
- 0x2B
|
||||||
|
- 0x30
|
||||||
|
- 0x31
|
||||||
|
- 0x32
|
||||||
|
- 0x33
|
||||||
|
- 0x38
|
||||||
|
- 0x39
|
||||||
|
- 0x3A
|
||||||
|
- 0x3B
|
||||||
|
world: both
|
||||||
|
- cells:
|
||||||
|
- 0x04
|
||||||
|
- 0x05
|
||||||
|
- 0x06
|
||||||
|
- 0x07
|
||||||
|
- 0x0C
|
||||||
|
- 0x0D
|
||||||
|
- 0x0E
|
||||||
|
- 0x0F
|
||||||
|
- 0x14
|
||||||
|
- 0x15
|
||||||
|
- 0x16
|
||||||
|
- 0x17
|
||||||
|
- 0x1C
|
||||||
|
- 0x1D
|
||||||
|
- 0x1E
|
||||||
|
- 0x1F
|
||||||
|
positions:
|
||||||
|
- 0x04
|
||||||
|
- 0x05
|
||||||
|
- 0x06
|
||||||
|
- 0x07
|
||||||
|
- 0x0C
|
||||||
|
- 0x0D
|
||||||
|
- 0x0E
|
||||||
|
- 0x0F
|
||||||
|
- 0x14
|
||||||
|
- 0x15
|
||||||
|
- 0x16
|
||||||
|
- 0x17
|
||||||
|
- 0x1C
|
||||||
|
- 0x1D
|
||||||
|
- 0x1E
|
||||||
|
- 0x1F
|
||||||
|
world: both
|
||||||
|
- cells:
|
||||||
|
- 0x24
|
||||||
|
- 0x25
|
||||||
|
- 0x26
|
||||||
|
- 0x27
|
||||||
|
- 0x2C
|
||||||
|
- 0x2D
|
||||||
|
- 0x2E
|
||||||
|
- 0x2F
|
||||||
|
- 0x34
|
||||||
|
- 0x35
|
||||||
|
- 0x36
|
||||||
|
- 0x37
|
||||||
|
- 0x3C
|
||||||
|
- 0x3D
|
||||||
|
- 0x3E
|
||||||
|
- 0x3F
|
||||||
|
positions:
|
||||||
|
- 0x24
|
||||||
|
- 0x25
|
||||||
|
- 0x26
|
||||||
|
- 0x27
|
||||||
|
- 0x2C
|
||||||
|
- 0x2D
|
||||||
|
- 0x2E
|
||||||
|
- 0x2F
|
||||||
|
- 0x34
|
||||||
|
- 0x35
|
||||||
|
- 0x36
|
||||||
|
- 0x37
|
||||||
|
- 0x3C
|
||||||
|
- 0x3D
|
||||||
|
- 0x3E
|
||||||
|
- 0x3F
|
||||||
|
world: both
|
||||||
|
split_large_screens: true
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
settings:
|
settings:
|
||||||
1:
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow_whirlpool: false
|
ow_whirlpool: false
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
two-way:
|
two-way:
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
groups:
|
groups:
|
||||||
|
|||||||
147
presets/world/owr_ringshuffle-grid.yaml
Normal file
147
presets/world/owr_ringshuffle-grid.yaml
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: grid
|
||||||
|
ow-grid:
|
||||||
|
1:
|
||||||
|
restricted_positions:
|
||||||
|
- cells:
|
||||||
|
- 0x00
|
||||||
|
- 0x01
|
||||||
|
- 0x02
|
||||||
|
- 0x03
|
||||||
|
- 0x04
|
||||||
|
- 0x05
|
||||||
|
- 0x06
|
||||||
|
- 0x07
|
||||||
|
- 0x08
|
||||||
|
- 0x0F
|
||||||
|
- 0x10
|
||||||
|
- 0x17
|
||||||
|
- 0x18
|
||||||
|
- 0x1F
|
||||||
|
- 0x20
|
||||||
|
- 0x27
|
||||||
|
- 0x28
|
||||||
|
- 0x2F
|
||||||
|
- 0x30
|
||||||
|
- 0x37
|
||||||
|
- 0x38
|
||||||
|
- 0x39
|
||||||
|
- 0x3A
|
||||||
|
- 0x3B
|
||||||
|
- 0x3C
|
||||||
|
- 0x3D
|
||||||
|
- 0x3E
|
||||||
|
- 0x3F
|
||||||
|
positions:
|
||||||
|
- 0x00
|
||||||
|
- 0x01
|
||||||
|
- 0x02
|
||||||
|
- 0x03
|
||||||
|
- 0x04
|
||||||
|
- 0x05
|
||||||
|
- 0x06
|
||||||
|
- 0x07
|
||||||
|
- 0x08
|
||||||
|
- 0x0F
|
||||||
|
- 0x10
|
||||||
|
- 0x17
|
||||||
|
- 0x18
|
||||||
|
- 0x1F
|
||||||
|
- 0x20
|
||||||
|
- 0x27
|
||||||
|
- 0x28
|
||||||
|
- 0x2F
|
||||||
|
- 0x30
|
||||||
|
- 0x37
|
||||||
|
- 0x38
|
||||||
|
- 0x39
|
||||||
|
- 0x3A
|
||||||
|
- 0x3B
|
||||||
|
- 0x3C
|
||||||
|
- 0x3D
|
||||||
|
- 0x3E
|
||||||
|
- 0x3F
|
||||||
|
world: both
|
||||||
|
- cells:
|
||||||
|
- 0x09
|
||||||
|
- 0x0A
|
||||||
|
- 0x0B
|
||||||
|
- 0x0C
|
||||||
|
- 0x0D
|
||||||
|
- 0x0E
|
||||||
|
- 0x11
|
||||||
|
- 0x16
|
||||||
|
- 0x19
|
||||||
|
- 0x1E
|
||||||
|
- 0x21
|
||||||
|
- 0x26
|
||||||
|
- 0x29
|
||||||
|
- 0x2E
|
||||||
|
- 0x31
|
||||||
|
- 0x32
|
||||||
|
- 0x33
|
||||||
|
- 0x34
|
||||||
|
- 0x35
|
||||||
|
- 0x36
|
||||||
|
positions:
|
||||||
|
- 0x09
|
||||||
|
- 0x0A
|
||||||
|
- 0x0B
|
||||||
|
- 0x0C
|
||||||
|
- 0x0D
|
||||||
|
- 0x0E
|
||||||
|
- 0x11
|
||||||
|
- 0x16
|
||||||
|
- 0x19
|
||||||
|
- 0x1E
|
||||||
|
- 0x21
|
||||||
|
- 0x26
|
||||||
|
- 0x29
|
||||||
|
- 0x2E
|
||||||
|
- 0x31
|
||||||
|
- 0x32
|
||||||
|
- 0x33
|
||||||
|
- 0x34
|
||||||
|
- 0x35
|
||||||
|
- 0x36
|
||||||
|
world: both
|
||||||
|
- cells:
|
||||||
|
- 0x12
|
||||||
|
- 0x13
|
||||||
|
- 0x14
|
||||||
|
- 0x15
|
||||||
|
- 0x1A
|
||||||
|
- 0x1D
|
||||||
|
- 0x22
|
||||||
|
- 0x25
|
||||||
|
- 0x2A
|
||||||
|
- 0x2B
|
||||||
|
- 0x2C
|
||||||
|
- 0x2D
|
||||||
|
positions:
|
||||||
|
- 0x12
|
||||||
|
- 0x13
|
||||||
|
- 0x14
|
||||||
|
- 0x15
|
||||||
|
- 0x1A
|
||||||
|
- 0x1D
|
||||||
|
- 0x22
|
||||||
|
- 0x25
|
||||||
|
- 0x2A
|
||||||
|
- 0x2B
|
||||||
|
- 0x2C
|
||||||
|
- 0x2D
|
||||||
|
world: both
|
||||||
|
- cells:
|
||||||
|
- 0x1B
|
||||||
|
- 0x1C
|
||||||
|
- 0x23
|
||||||
|
- 0x24
|
||||||
|
positions:
|
||||||
|
- 0x1B
|
||||||
|
- 0x1C
|
||||||
|
- 0x23
|
||||||
|
- 0x24
|
||||||
|
world: both
|
||||||
|
split_large_screens: true
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
two-way:
|
two-way:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
settings:
|
settings:
|
||||||
1:
|
1:
|
||||||
|
ow_parallel: false
|
||||||
ow_whirlpool: false
|
ow_whirlpool: false
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
@@ -77,6 +78,25 @@ ow-edges:
|
|||||||
Desert Pass EC*: Dam WC*
|
Desert Pass EC*: Dam WC*
|
||||||
Desert Pass ES*: Dam WS*
|
Desert Pass ES*: Dam WS*
|
||||||
Dam EC*: South Pass WC*
|
Dam EC*: South Pass WC*
|
||||||
|
ow-grid:
|
||||||
|
1:
|
||||||
|
fixed_arrangements:
|
||||||
|
- arrangement:
|
||||||
|
- 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07
|
||||||
|
- 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F
|
||||||
|
- 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17
|
||||||
|
- 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F
|
||||||
|
- 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27
|
||||||
|
- 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F
|
||||||
|
- 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37
|
||||||
|
- 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F
|
||||||
|
world: light
|
||||||
|
restricted_positions:
|
||||||
|
- cells:
|
||||||
|
- 0x00
|
||||||
|
positions:
|
||||||
|
- 0x00
|
||||||
|
world: light
|
||||||
ow-whirlpools:
|
ow-whirlpools:
|
||||||
1:
|
1:
|
||||||
two-way:
|
two-way:
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
two-way:
|
two-way:
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
two-way:
|
two-way:
|
||||||
|
|||||||
149
presets/world/owr_shuffle-largescreenpool.yaml
Normal file
149
presets/world/owr_shuffle-largescreenpool.yaml
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: grid
|
||||||
|
ow-grid:
|
||||||
|
1:
|
||||||
|
restricted_positions:
|
||||||
|
- cells:
|
||||||
|
- 0x00
|
||||||
|
- 0x03
|
||||||
|
- 0x05
|
||||||
|
- 0x18
|
||||||
|
- 0x1B
|
||||||
|
- 0x1E
|
||||||
|
- 0x30
|
||||||
|
- 0x35
|
||||||
|
positions:
|
||||||
|
- 0x00
|
||||||
|
- 0x03
|
||||||
|
- 0x05
|
||||||
|
- 0x18
|
||||||
|
- 0x1B
|
||||||
|
- 0x1E
|
||||||
|
- 0x30
|
||||||
|
- 0x35
|
||||||
|
world: both
|
||||||
|
- cells:
|
||||||
|
- 0x01
|
||||||
|
- 0x04
|
||||||
|
- 0x06
|
||||||
|
- 0x19
|
||||||
|
- 0x1C
|
||||||
|
- 0x1F
|
||||||
|
- 0x31
|
||||||
|
- 0x36
|
||||||
|
positions:
|
||||||
|
- 0x01
|
||||||
|
- 0x04
|
||||||
|
- 0x06
|
||||||
|
- 0x19
|
||||||
|
- 0x1C
|
||||||
|
- 0x1F
|
||||||
|
- 0x31
|
||||||
|
- 0x36
|
||||||
|
world: both
|
||||||
|
- cells:
|
||||||
|
- 0x08
|
||||||
|
- 0x0B
|
||||||
|
- 0x0D
|
||||||
|
- 0x20
|
||||||
|
- 0x23
|
||||||
|
- 0x26
|
||||||
|
- 0x38
|
||||||
|
- 0x3D
|
||||||
|
positions:
|
||||||
|
- 0x08
|
||||||
|
- 0x0B
|
||||||
|
- 0x0D
|
||||||
|
- 0x20
|
||||||
|
- 0x23
|
||||||
|
- 0x26
|
||||||
|
- 0x38
|
||||||
|
- 0x3D
|
||||||
|
world: both
|
||||||
|
- cells:
|
||||||
|
- 0x09
|
||||||
|
- 0x0C
|
||||||
|
- 0x0E
|
||||||
|
- 0x21
|
||||||
|
- 0x24
|
||||||
|
- 0x27
|
||||||
|
- 0x39
|
||||||
|
- 0x3E
|
||||||
|
positions:
|
||||||
|
- 0x09
|
||||||
|
- 0x0C
|
||||||
|
- 0x0E
|
||||||
|
- 0x21
|
||||||
|
- 0x24
|
||||||
|
- 0x27
|
||||||
|
- 0x39
|
||||||
|
- 0x3E
|
||||||
|
world: both
|
||||||
|
- cells:
|
||||||
|
- 0x02
|
||||||
|
- 0x07
|
||||||
|
- 0x0A
|
||||||
|
- 0x0F
|
||||||
|
- 0x10
|
||||||
|
- 0x11
|
||||||
|
- 0x12
|
||||||
|
- 0x13
|
||||||
|
- 0x14
|
||||||
|
- 0x15
|
||||||
|
- 0x16
|
||||||
|
- 0x17
|
||||||
|
- 0x1A
|
||||||
|
- 0x1D
|
||||||
|
- 0x22
|
||||||
|
- 0x25
|
||||||
|
- 0x28
|
||||||
|
- 0x29
|
||||||
|
- 0x2A
|
||||||
|
- 0x2B
|
||||||
|
- 0x2C
|
||||||
|
- 0x2D
|
||||||
|
- 0x2E
|
||||||
|
- 0x2F
|
||||||
|
- 0x32
|
||||||
|
- 0x33
|
||||||
|
- 0x34
|
||||||
|
- 0x37
|
||||||
|
- 0x3A
|
||||||
|
- 0x3B
|
||||||
|
- 0x3C
|
||||||
|
- 0x3F
|
||||||
|
positions:
|
||||||
|
- 0x02
|
||||||
|
- 0x07
|
||||||
|
- 0x0A
|
||||||
|
- 0x0F
|
||||||
|
- 0x10
|
||||||
|
- 0x11
|
||||||
|
- 0x12
|
||||||
|
- 0x13
|
||||||
|
- 0x14
|
||||||
|
- 0x15
|
||||||
|
- 0x16
|
||||||
|
- 0x17
|
||||||
|
- 0x1A
|
||||||
|
- 0x1D
|
||||||
|
- 0x22
|
||||||
|
- 0x25
|
||||||
|
- 0x28
|
||||||
|
- 0x29
|
||||||
|
- 0x2A
|
||||||
|
- 0x2B
|
||||||
|
- 0x2C
|
||||||
|
- 0x2D
|
||||||
|
- 0x2E
|
||||||
|
- 0x2F
|
||||||
|
- 0x32
|
||||||
|
- 0x33
|
||||||
|
- 0x34
|
||||||
|
- 0x37
|
||||||
|
- 0x3A
|
||||||
|
- 0x3B
|
||||||
|
- 0x3C
|
||||||
|
- 0x3F
|
||||||
|
world: both
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: wild
|
||||||
settings:
|
settings:
|
||||||
1:
|
1:
|
||||||
ow_whirlpool: false
|
ow_whirlpool: false
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_parallel: false
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
two-way:
|
two-way:
|
||||||
@@ -69,6 +72,25 @@ ow-edges:
|
|||||||
Swamp Nook EC*: Swamp WC*
|
Swamp Nook EC*: Swamp WC*
|
||||||
Swamp Nook ES*: Swamp WS*
|
Swamp Nook ES*: Swamp WS*
|
||||||
Swamp EC*: Dark South Pass WC*
|
Swamp EC*: Dark South Pass WC*
|
||||||
|
ow-grid:
|
||||||
|
1:
|
||||||
|
fixed_arrangements:
|
||||||
|
- arrangement:
|
||||||
|
- 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07
|
||||||
|
- 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F
|
||||||
|
- 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17
|
||||||
|
- 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F
|
||||||
|
- 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27
|
||||||
|
- 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F
|
||||||
|
- 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37
|
||||||
|
- 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F
|
||||||
|
world: dark
|
||||||
|
restricted_positions:
|
||||||
|
- cells:
|
||||||
|
- 0x00
|
||||||
|
positions:
|
||||||
|
- 0x00
|
||||||
|
world: dark
|
||||||
ow-whirlpools:
|
ow-whirlpools:
|
||||||
1:
|
1:
|
||||||
two-way:
|
two-way:
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
groups:
|
groups:
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
two-way:
|
two-way:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
settings:
|
settings:
|
||||||
1:
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow_terrain: false
|
ow_terrain: false
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
settings:
|
settings:
|
||||||
1:
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow_terrain: true
|
ow_terrain: true
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
two-way:
|
two-way:
|
||||||
|
|||||||
16
presets/world/owr_shuffle-vanillamountain.yaml
Normal file
16
presets/world/owr_shuffle-vanillamountain.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
ow-edges:
|
||||||
|
1:
|
||||||
|
two-way:
|
||||||
|
West Death Mountain EN*: East Death Mountain WN*
|
||||||
|
West Death Mountain ES*: East Death Mountain WS*
|
||||||
|
East Death Mountain EN*: Death Mountain TR Pegs WN*
|
||||||
|
West Dark Death Mountain EN*: East Dark Death Mountain WN*
|
||||||
|
West Dark Death Mountain ES*: East Dark Death Mountain WS*
|
||||||
|
East Dark Death Mountain EN*: Turtle Rock WN*
|
||||||
|
ow-grid:
|
||||||
|
1:
|
||||||
|
fixed_arrangements:
|
||||||
|
- arrangement:
|
||||||
|
- 0x03 0x04 0x05 0x06 0x07
|
||||||
|
- 0x0B 0x0C 0x0D 0x0E .
|
||||||
|
world: both
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
two-way:
|
two-way:
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: wild
|
||||||
ow-edges:
|
ow-edges:
|
||||||
1:
|
1:
|
||||||
two-way:
|
two-way:
|
||||||
|
|||||||
7
presets/world/owr_shuffle-wrappedgrid.yaml
Normal file
7
presets/world/owr_shuffle-wrappedgrid.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
settings:
|
||||||
|
1:
|
||||||
|
ow_layout: grid
|
||||||
|
ow-grid:
|
||||||
|
1:
|
||||||
|
wrap_horizontal: true
|
||||||
|
wrap_vertical: true
|
||||||
@@ -144,6 +144,25 @@ ow-edges:
|
|||||||
Swamp EC*: Dark South Pass WC*
|
Swamp EC*: Dark South Pass WC*
|
||||||
South Pass ES*: Lake Hylia WS*
|
South Pass ES*: Lake Hylia WS*
|
||||||
Dark South Pass ES*: Ice Lake WS*
|
Dark South Pass ES*: Ice Lake WS*
|
||||||
|
ow-grid:
|
||||||
|
1:
|
||||||
|
fixed_arrangements:
|
||||||
|
- arrangement:
|
||||||
|
- 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07
|
||||||
|
- 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F
|
||||||
|
- 0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17
|
||||||
|
- 0x18 0x19 0x1A 0x1B 0x1C 0x1D 0x1E 0x1F
|
||||||
|
- 0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27
|
||||||
|
- 0x28 0x29 0x2A 0x2B 0x2C 0x2D 0x2E 0x2F
|
||||||
|
- 0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37
|
||||||
|
- 0x38 0x39 0x3A 0x3B 0x3C 0x3D 0x3E 0x3F
|
||||||
|
world: both
|
||||||
|
restricted_positions:
|
||||||
|
- cells:
|
||||||
|
- 0x00
|
||||||
|
positions:
|
||||||
|
- 0x00
|
||||||
|
world: both
|
||||||
ow-whirlpools:
|
ow-whirlpools:
|
||||||
1:
|
1:
|
||||||
two-way:
|
two-way:
|
||||||
|
|||||||
@@ -509,6 +509,7 @@ class CustomSettings(object):
|
|||||||
self.world_rep['ow-whirlpools'] = whirlpools = {}
|
self.world_rep['ow-whirlpools'] = whirlpools = {}
|
||||||
self.world_rep['ow-tileflips'] = flips = {}
|
self.world_rep['ow-tileflips'] = flips = {}
|
||||||
self.world_rep['ow-flutespots'] = flute = {}
|
self.world_rep['ow-flutespots'] = flute = {}
|
||||||
|
self.world_rep['ow-grid'] = owgrid = {}
|
||||||
for p in self.player_range:
|
for p in self.player_range:
|
||||||
connections = edges[p] = {}
|
connections = edges[p] = {}
|
||||||
connections['two-way'] = {}
|
connections['two-way'] = {}
|
||||||
@@ -529,6 +530,57 @@ class CustomSettings(object):
|
|||||||
else:
|
else:
|
||||||
flute[p]['force'] = list(HexInt(id) for id in sorted(default_flute_connections))
|
flute[p]['force'] = list(HexInt(id) for id in sorted(default_flute_connections))
|
||||||
flute[p]['forbid'] = []
|
flute[p]['forbid'] = []
|
||||||
|
# layout grid
|
||||||
|
owgrid[p] = {}
|
||||||
|
grid = world.owgrid[p]
|
||||||
|
if grid is None:
|
||||||
|
grid = [
|
||||||
|
[[HexInt(row * 8 + col) for col in range(8)] for row in range(8)],
|
||||||
|
[[HexInt(row * 8 + col) for col in range(8)] for row in range(8)]
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
grid = [
|
||||||
|
[[HexInt(cell & 0xBF) for cell in row] for row in grid[0]],
|
||||||
|
[[HexInt(cell & 0xBF) for cell in row] for row in grid[1]]
|
||||||
|
]
|
||||||
|
# Create fixed_arrangements for both worlds
|
||||||
|
owgrid[p]['fixed_arrangements'] = [
|
||||||
|
{
|
||||||
|
'arrangement': [' '.join(f'0x{cell:02X}' for cell in row) for row in grid[0]],
|
||||||
|
'world': 'light'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'arrangement': [' '.join(f'0x{cell:02X}' for cell in row) for row in grid[1]],
|
||||||
|
'world': 'dark'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
# Pin top left corners to position 0x00
|
||||||
|
owgrid[p]['restricted_positions'] = [
|
||||||
|
{
|
||||||
|
'cells': [HexInt(grid[0][0][0])],
|
||||||
|
'positions': [HexInt(0x00)],
|
||||||
|
'world': 'light'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'cells': [HexInt(grid[1][0][0])],
|
||||||
|
'positions': [HexInt(0x00)],
|
||||||
|
'world': 'dark'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
# Set advanced grid options
|
||||||
|
horizontal_wrap = False
|
||||||
|
vertical_wrap = False
|
||||||
|
split_large_screens = False
|
||||||
|
if world.customizer:
|
||||||
|
grid_options = world.customizer.get_owgrid()
|
||||||
|
if grid_options and p in grid_options:
|
||||||
|
grid_options = grid_options[p]
|
||||||
|
horizontal_wrap = 'wrap_horizontal' in grid_options and grid_options['wrap_horizontal'] == True
|
||||||
|
vertical_wrap = 'wrap_vertical' in grid_options and grid_options['wrap_vertical'] == True
|
||||||
|
split_large_screens = 'split_large_screens' in grid_options and grid_options['split_large_screens'] == True
|
||||||
|
owgrid[p]['wrap_horizontal'] = horizontal_wrap
|
||||||
|
owgrid[p]['wrap_vertical'] = vertical_wrap
|
||||||
|
owgrid[p]['split_large_screens'] = split_large_screens
|
||||||
for key, data in world.spoiler.overworlds.items():
|
for key, data in world.spoiler.overworlds.items():
|
||||||
player = data['player'] if 'player' in data else 1
|
player = data['player'] if 'player' in data else 1
|
||||||
connections = edges[player]
|
connections = edges[player]
|
||||||
@@ -536,7 +588,7 @@ class CustomSettings(object):
|
|||||||
connections[sub][data['entrance']] = data['exit']
|
connections[sub][data['entrance']] = data['exit']
|
||||||
for key, data in world.spoiler.whirlpools.items():
|
for key, data in world.spoiler.whirlpools.items():
|
||||||
player = data['player'] if 'player' in data else 1
|
player = data['player'] if 'player' in data else 1
|
||||||
whirlconnects = whirlconnects[player]
|
whirlconnects = whirlpools[player]
|
||||||
sub = 'two-way' if data['direction'] == 'both' else 'one-way'
|
sub = 'two-way' if data['direction'] == 'both' else 'one-way'
|
||||||
whirlconnects[sub][data['entrance']] = data['exit']
|
whirlconnects[sub][data['entrance']] = data['exit']
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,18 @@ from datetime import datetime
|
|||||||
from typing import Dict, List
|
from typing import Dict, List
|
||||||
from PIL import Image, ImageDraw
|
from PIL import Image, ImageDraw
|
||||||
from BaseClasses import Direction, OWEdge
|
from BaseClasses import Direction, OWEdge
|
||||||
from source.overworld.LayoutGenerator import Screen
|
from source.overworld.LayoutGenerator import Screen, get_screen_id_from_cell
|
||||||
|
|
||||||
|
def get_quadrant_from_cell_id(cell_id: int, screen_id: int) -> str:
|
||||||
|
offset = (cell_id & 0xBF) - (screen_id & 0xBF)
|
||||||
|
if offset == 0x00:
|
||||||
|
return "NW"
|
||||||
|
elif offset == 0x01:
|
||||||
|
return "NE"
|
||||||
|
elif offset == 0x08:
|
||||||
|
return "SW"
|
||||||
|
else:
|
||||||
|
return "SE"
|
||||||
|
|
||||||
def get_edge_lists(grid: List[List[List[int]]],
|
def get_edge_lists(grid: List[List[List[int]]],
|
||||||
overworld_screens: Dict[int, Screen],
|
overworld_screens: Dict[int, Screen],
|
||||||
@@ -13,7 +24,7 @@ def get_edge_lists(grid: List[List[List[int]]],
|
|||||||
Get list of edges for each cell and direction.
|
Get list of edges for each cell and direction.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
grid: 3D list [world][row][col] containing screen IDs
|
grid: 3D list [world][row][col] containing cell IDs
|
||||||
overworld_screens: Dict of screen_id -> Screen objects
|
overworld_screens: Dict of screen_id -> Screen objects
|
||||||
large_screen_quadrant_info: Dict of screen_id -> quadrant info for large screens
|
large_screen_quadrant_info: Dict of screen_id -> quadrant info for large screens
|
||||||
|
|
||||||
@@ -24,47 +35,27 @@ def get_edge_lists(grid: List[List[List[int]]],
|
|||||||
GRID_SIZE = 8
|
GRID_SIZE = 8
|
||||||
edge_lists = {}
|
edge_lists = {}
|
||||||
|
|
||||||
# Large screen base IDs
|
|
||||||
large_screen_base_ids = [0x00, 0x03, 0x05, 0x18, 0x1B, 0x1E, 0x30, 0x35,
|
|
||||||
0x40, 0x43, 0x45, 0x58, 0x5B, 0x5E, 0x70, 0x75]
|
|
||||||
|
|
||||||
for world_idx in range(2):
|
for world_idx in range(2):
|
||||||
# Build a map of screen_id -> list of (row, col) positions for large screens
|
|
||||||
large_screen_positions = {}
|
|
||||||
for row in range(GRID_SIZE):
|
for row in range(GRID_SIZE):
|
||||||
for col in range(GRID_SIZE):
|
for col in range(GRID_SIZE):
|
||||||
screen_id = grid[world_idx][row][col]
|
cell_id = grid[world_idx][row][col]
|
||||||
if screen_id != -1 and screen_id in large_screen_base_ids:
|
|
||||||
if screen_id not in large_screen_positions:
|
|
||||||
large_screen_positions[screen_id] = []
|
|
||||||
large_screen_positions[screen_id].append((row, col))
|
|
||||||
|
|
||||||
for row in range(GRID_SIZE):
|
if cell_id == -1:
|
||||||
for col in range(GRID_SIZE):
|
|
||||||
screen_id = grid[world_idx][row][col]
|
|
||||||
|
|
||||||
if screen_id == -1:
|
|
||||||
# Empty cell - no edges
|
# Empty cell - no edges
|
||||||
for direction in [Direction.North, Direction.South, Direction.East, Direction.West]:
|
for direction in [Direction.North, Direction.South, Direction.East, Direction.West]:
|
||||||
edge_lists[(world_idx, row, col, direction)] = []
|
edge_lists[(world_idx, row, col, direction)] = []
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
screen_id = get_screen_id_from_cell(cell_id)
|
||||||
screen = overworld_screens.get(screen_id)
|
screen = overworld_screens.get(screen_id)
|
||||||
if not screen:
|
if not screen:
|
||||||
for direction in [Direction.North, Direction.South, Direction.East, Direction.West]:
|
for direction in [Direction.North, Direction.South, Direction.East, Direction.West]:
|
||||||
edge_lists[(world_idx, row, col, direction)] = []
|
edge_lists[(world_idx, row, col, direction)] = []
|
||||||
continue
|
continue
|
||||||
|
|
||||||
is_large = screen_id in large_screen_base_ids
|
if screen.big:
|
||||||
|
# For large screens, determine quadrant from cell ID
|
||||||
if is_large:
|
quadrant = get_quadrant_from_cell_id(cell_id, screen_id)
|
||||||
# For large screens, determine which quadrant this cell is
|
|
||||||
# Find all positions of this large screen and determine quadrant
|
|
||||||
positions = large_screen_positions.get(screen_id, [(row, col)])
|
|
||||||
|
|
||||||
# Determine quadrant by finding relative position
|
|
||||||
# The quadrant is determined by which cells are adjacent
|
|
||||||
quadrant = determine_large_screen_quadrant(row, col, positions, GRID_SIZE)
|
|
||||||
|
|
||||||
# Get edges for this quadrant
|
# Get edges for this quadrant
|
||||||
if screen_id in large_screen_quadrant_info:
|
if screen_id in large_screen_quadrant_info:
|
||||||
@@ -85,45 +76,6 @@ def get_edge_lists(grid: List[List[List[int]]],
|
|||||||
|
|
||||||
return edge_lists
|
return edge_lists
|
||||||
|
|
||||||
def determine_large_screen_quadrant(row: int, col: int, positions: List[tuple], grid_size: int) -> str:
|
|
||||||
"""
|
|
||||||
Determine which quadrant (NW, NE, SW, SE) a cell is in for a large screen.
|
|
||||||
Handles wrapping correctly by checking adjacency patterns.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
row: Current cell row
|
|
||||||
col: Current cell column
|
|
||||||
positions: List of all (row, col) positions for this large screen
|
|
||||||
grid_size: Size of the grid (8)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Quadrant string: "NW", "NE", "SW", or "SE"
|
|
||||||
"""
|
|
||||||
positions_set = set(positions)
|
|
||||||
|
|
||||||
# Check which adjacent cells also belong to this large screen
|
|
||||||
has_right = ((row, (col + 1) % grid_size) in positions_set)
|
|
||||||
has_below = (((row + 1) % grid_size, col) in positions_set)
|
|
||||||
has_left = ((row, (col - 1) % grid_size) in positions_set)
|
|
||||||
has_above = (((row - 1) % grid_size, col) in positions_set)
|
|
||||||
|
|
||||||
# Determine quadrant based on adjacency
|
|
||||||
# NW: has right and below neighbors
|
|
||||||
# NE: has left and below neighbors
|
|
||||||
# SW: has right and above neighbors
|
|
||||||
# SE: has left and above neighbors
|
|
||||||
|
|
||||||
if has_right and has_below:
|
|
||||||
return "NW"
|
|
||||||
elif has_left and has_below:
|
|
||||||
return "NE"
|
|
||||||
elif has_right and has_above:
|
|
||||||
return "SW"
|
|
||||||
elif has_left and has_above:
|
|
||||||
return "SE"
|
|
||||||
else:
|
|
||||||
raise Exception("?")
|
|
||||||
|
|
||||||
def is_crossed_edge(edge: OWEdge, overworld_screens: Dict[int, Screen]) -> bool:
|
def is_crossed_edge(edge: OWEdge, overworld_screens: Dict[int, Screen]) -> bool:
|
||||||
if edge.dest is None:
|
if edge.dest is None:
|
||||||
return False
|
return False
|
||||||
@@ -132,6 +84,40 @@ def is_crossed_edge(edge: OWEdge, overworld_screens: Dict[int, Screen]) -> bool:
|
|||||||
dest_screen = overworld_screens.get(edge.dest.owIndex)
|
dest_screen = overworld_screens.get(edge.dest.owIndex)
|
||||||
return source_screen.dark_world != dest_screen.dark_world
|
return source_screen.dark_world != dest_screen.dark_world
|
||||||
|
|
||||||
|
def are_large_screen_cells_connected(cell_id1: int, cell_id2: int, quadrant1: str, quadrant2: str, direction: str) -> bool:
|
||||||
|
"""
|
||||||
|
Check if two cells of a large screen are connected (should have no border between them).
|
||||||
|
|
||||||
|
For cells to be connected:
|
||||||
|
1. They must be from the same large screen (same base screen ID)
|
||||||
|
2. Their quadrants must be adjacent in the expected direction
|
||||||
|
|
||||||
|
Args:
|
||||||
|
cell_id1: Cell ID of the first cell
|
||||||
|
cell_id2: Cell ID of the second cell
|
||||||
|
quadrant1: Quadrant of the first cell ("NW", "NE", "SW", "SE")
|
||||||
|
quadrant2: Quadrant of the second cell
|
||||||
|
direction: Direction from cell1 to cell2 ("east", "south")
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if the cells should have no border between them
|
||||||
|
"""
|
||||||
|
# Must be from the same large screen
|
||||||
|
screen_id1 = get_screen_id_from_cell(cell_id1)
|
||||||
|
screen_id2 = get_screen_id_from_cell(cell_id2)
|
||||||
|
if screen_id1 != screen_id2:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Check if quadrants are properly adjacent
|
||||||
|
if direction == "east":
|
||||||
|
# For east connection: NW->NE or SW->SE
|
||||||
|
return (quadrant1 == "NW" and quadrant2 == "NE") or (quadrant1 == "SW" and quadrant2 == "SE")
|
||||||
|
elif direction == "south":
|
||||||
|
# For south connection: NW->SW or NE->SE
|
||||||
|
return (quadrant1 == "NW" and quadrant2 == "SW") or (quadrant1 == "NE" and quadrant2 == "SE")
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
def visualize_layout(grid: List[List[List[int]]], output_dir: str,
|
def visualize_layout(grid: List[List[List[int]]], output_dir: str,
|
||||||
overworld_screens: Dict[int, Screen],
|
overworld_screens: Dict[int, Screen],
|
||||||
large_screen_quadrant_info: Dict[int, Dict]) -> None:
|
large_screen_quadrant_info: Dict[int, Dict]) -> None:
|
||||||
@@ -162,68 +148,32 @@ def visualize_layout(grid: List[List[List[int]]], output_dir: str,
|
|||||||
output_height = world_height
|
output_height = world_height
|
||||||
output_img = Image.new('RGB', (output_width, output_height), color='black')
|
output_img = Image.new('RGB', (output_width, output_height), color='black')
|
||||||
|
|
||||||
# Large screen base IDs (defined once for reuse)
|
|
||||||
large_screen_base_ids = [0x00, 0x03, 0x05, 0x18, 0x1B, 0x1E, 0x30, 0x35,
|
|
||||||
0x40, 0x43, 0x45, 0x58, 0x5B, 0x5E, 0x70, 0x75]
|
|
||||||
|
|
||||||
# Process both worlds
|
# Process both worlds
|
||||||
for world_idx in range(2):
|
for world_idx in range(2):
|
||||||
x_offset = 0 if world_idx == 0 else (world_width + gap)
|
x_offset = 0 if world_idx == 0 else (world_width + gap)
|
||||||
|
|
||||||
# Build a map of screen_id -> list of (row, col) positions for large screens
|
|
||||||
large_screen_positions = {}
|
|
||||||
for row in range(GRID_SIZE):
|
|
||||||
for col in range(GRID_SIZE):
|
|
||||||
screen_id = grid[world_idx][row][col]
|
|
||||||
if screen_id != -1 and screen_id in large_screen_base_ids:
|
|
||||||
if screen_id not in large_screen_positions:
|
|
||||||
large_screen_positions[screen_id] = []
|
|
||||||
large_screen_positions[screen_id].append((row, col))
|
|
||||||
|
|
||||||
# Process each cell in the grid individually
|
# Process each cell in the grid individually
|
||||||
# This handles wrapped large screens correctly by drawing each quadrant separately
|
|
||||||
for row in range(GRID_SIZE):
|
for row in range(GRID_SIZE):
|
||||||
for col in range(GRID_SIZE):
|
for col in range(GRID_SIZE):
|
||||||
screen_id = grid[world_idx][row][col]
|
cell_id = grid[world_idx][row][col]
|
||||||
|
|
||||||
if screen_id == -1:
|
if cell_id == -1:
|
||||||
# Empty cell - fill with black (already black from initialization)
|
# Empty cell - fill with black (already black from initialization)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
is_large = screen_id in large_screen_base_ids
|
screen_id = get_screen_id_from_cell(cell_id)
|
||||||
|
screen = overworld_screens.get(screen_id)
|
||||||
|
if not screen:
|
||||||
|
continue
|
||||||
|
|
||||||
# Calculate source position in the world image
|
is_large = screen.big
|
||||||
source_row = (screen_id % 0x40) >> 3
|
|
||||||
source_col = screen_id % 0x08
|
|
||||||
world_img = lightworld_img if screen_id < 0x40 else darkworld_img
|
|
||||||
|
|
||||||
if is_large:
|
# Calculate source position in the world image based on cell_id
|
||||||
# For large screens, determine which quadrant this cell represents
|
# For large screens, cell_id already encodes the quadrant position
|
||||||
positions = large_screen_positions.get(screen_id, [(row, col)])
|
source_row = (cell_id % 0x40) >> 3
|
||||||
quadrant = determine_large_screen_quadrant(row, col, positions, GRID_SIZE)
|
source_col = cell_id % 0x08
|
||||||
|
world_img = lightworld_img if cell_id < 0x40 else darkworld_img
|
||||||
|
|
||||||
# Map quadrant to source offset within the 2x2 large screen
|
|
||||||
quadrant_offsets = {
|
|
||||||
"NW": (0, 0),
|
|
||||||
"NE": (1, 0),
|
|
||||||
"SW": (0, 1),
|
|
||||||
"SE": (1, 1)
|
|
||||||
}
|
|
||||||
q_col_offset, q_row_offset = quadrant_offsets[quadrant]
|
|
||||||
|
|
||||||
# Calculate source position for this quadrant
|
|
||||||
source_x = (source_col + q_col_offset) * SOURCE_CELL_SIZE
|
|
||||||
source_y = (source_row + q_row_offset) * SOURCE_CELL_SIZE
|
|
||||||
|
|
||||||
# Crop single cell from source (the specific quadrant)
|
|
||||||
cropped = world_img.crop((
|
|
||||||
source_x,
|
|
||||||
source_y,
|
|
||||||
source_x + SOURCE_CELL_SIZE,
|
|
||||||
source_y + SOURCE_CELL_SIZE
|
|
||||||
))
|
|
||||||
else:
|
|
||||||
# Small screen (1x1)
|
|
||||||
source_x = source_col * SOURCE_CELL_SIZE
|
source_x = source_col * SOURCE_CELL_SIZE
|
||||||
source_y = source_row * SOURCE_CELL_SIZE
|
source_y = source_row * SOURCE_CELL_SIZE
|
||||||
|
|
||||||
@@ -257,52 +207,93 @@ def visualize_layout(grid: List[List[List[int]]], output_dir: str,
|
|||||||
for world_idx in range(2):
|
for world_idx in range(2):
|
||||||
x_offset = 0 if world_idx == 0 else (world_width + gap)
|
x_offset = 0 if world_idx == 0 else (world_width + gap)
|
||||||
|
|
||||||
# Build large screen positions map for this world
|
|
||||||
large_screen_positions = {}
|
|
||||||
for row in range(GRID_SIZE):
|
|
||||||
for col in range(GRID_SIZE):
|
|
||||||
screen_id = grid[world_idx][row][col]
|
|
||||||
if screen_id != -1 and screen_id in large_screen_base_ids:
|
|
||||||
if screen_id not in large_screen_positions:
|
|
||||||
large_screen_positions[screen_id] = []
|
|
||||||
large_screen_positions[screen_id].append((row, col))
|
|
||||||
|
|
||||||
# Draw borders for each cell
|
# Draw borders for each cell
|
||||||
|
# For large screens, only draw borders where cells are not connected
|
||||||
for row in range(GRID_SIZE):
|
for row in range(GRID_SIZE):
|
||||||
for col in range(GRID_SIZE):
|
for col in range(GRID_SIZE):
|
||||||
screen_id = grid[world_idx][row][col]
|
cell_id = grid[world_idx][row][col]
|
||||||
|
|
||||||
if screen_id == -1:
|
if cell_id == -1:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
is_large = screen_id in large_screen_base_ids
|
screen_id = get_screen_id_from_cell(cell_id)
|
||||||
|
screen = overworld_screens.get(screen_id)
|
||||||
|
if not screen:
|
||||||
|
continue
|
||||||
|
|
||||||
|
is_large = screen.big
|
||||||
|
|
||||||
dest_x = x_offset + col * OUTPUT_CELL_SIZE
|
dest_x = x_offset + col * OUTPUT_CELL_SIZE
|
||||||
dest_y = row * OUTPUT_CELL_SIZE
|
dest_y = row * OUTPUT_CELL_SIZE
|
||||||
|
|
||||||
if is_large:
|
if is_large:
|
||||||
# For large screens, determine which quadrant this cell is
|
quadrant = get_quadrant_from_cell_id(cell_id, screen_id)
|
||||||
positions = large_screen_positions.get(screen_id, [(row, col)])
|
|
||||||
quadrant = determine_large_screen_quadrant(row, col, positions, GRID_SIZE)
|
|
||||||
|
|
||||||
# Draw border only on the outer edges of the large screen
|
# Check each border direction
|
||||||
# (not on internal edges between quadrants)
|
# Top border: draw if this is a north quadrant OR if the cell above is not connected
|
||||||
# NW: draw top and left borders
|
draw_top = True
|
||||||
# NE: draw top and right borders
|
|
||||||
# SW: draw bottom and left borders
|
|
||||||
# SE: draw bottom and right borders
|
|
||||||
|
|
||||||
if quadrant in ["NW", "NE"]:
|
|
||||||
# Draw top border
|
|
||||||
draw.line([(dest_x, dest_y), (dest_x + OUTPUT_CELL_SIZE - 1, dest_y)], fill='black', width=BORDER_WIDTH)
|
|
||||||
if quadrant in ["SW", "SE"]:
|
if quadrant in ["SW", "SE"]:
|
||||||
# Draw bottom border
|
# Check if cell above is connected
|
||||||
draw.line([(dest_x, dest_y + OUTPUT_CELL_SIZE - 1), (dest_x + OUTPUT_CELL_SIZE - 1, dest_y + OUTPUT_CELL_SIZE - 1)], fill='black', width=BORDER_WIDTH)
|
above_row = (row - 1) % GRID_SIZE
|
||||||
if quadrant in ["NW", "SW"]:
|
above_cell_id = grid[world_idx][above_row][col]
|
||||||
# Draw left border
|
if above_cell_id != -1:
|
||||||
draw.line([(dest_x, dest_y), (dest_x, dest_y + OUTPUT_CELL_SIZE - 1)], fill='black', width=BORDER_WIDTH)
|
above_screen_id = get_screen_id_from_cell(above_cell_id)
|
||||||
|
above_screen = overworld_screens.get(above_screen_id)
|
||||||
|
if above_screen and above_screen.big:
|
||||||
|
above_quadrant = get_quadrant_from_cell_id(above_cell_id, above_screen_id)
|
||||||
|
if are_large_screen_cells_connected(above_cell_id, cell_id, above_quadrant, quadrant, "south"):
|
||||||
|
draw_top = False
|
||||||
|
|
||||||
|
# Bottom border: draw if this is a south quadrant OR if the cell below is not connected
|
||||||
|
draw_bottom = True
|
||||||
|
if quadrant in ["NW", "NE"]:
|
||||||
|
# Check if cell below is connected
|
||||||
|
below_row = (row + 1) % GRID_SIZE
|
||||||
|
below_cell_id = grid[world_idx][below_row][col]
|
||||||
|
if below_cell_id != -1:
|
||||||
|
below_screen_id = get_screen_id_from_cell(below_cell_id)
|
||||||
|
below_screen = overworld_screens.get(below_screen_id)
|
||||||
|
if below_screen and below_screen.big:
|
||||||
|
below_quadrant = get_quadrant_from_cell_id(below_cell_id, below_screen_id)
|
||||||
|
if are_large_screen_cells_connected(cell_id, below_cell_id, quadrant, below_quadrant, "south"):
|
||||||
|
draw_bottom = False
|
||||||
|
|
||||||
|
# Left border: draw if this is a west quadrant OR if the cell to the left is not connected
|
||||||
|
draw_left = True
|
||||||
if quadrant in ["NE", "SE"]:
|
if quadrant in ["NE", "SE"]:
|
||||||
# Draw right border
|
# Check if cell to the left is connected
|
||||||
|
left_col = (col - 1) % GRID_SIZE
|
||||||
|
left_cell_id = grid[world_idx][row][left_col]
|
||||||
|
if left_cell_id != -1:
|
||||||
|
left_screen_id = get_screen_id_from_cell(left_cell_id)
|
||||||
|
left_screen = overworld_screens.get(left_screen_id)
|
||||||
|
if left_screen and left_screen.big:
|
||||||
|
left_quadrant = get_quadrant_from_cell_id(left_cell_id, left_screen_id)
|
||||||
|
if are_large_screen_cells_connected(left_cell_id, cell_id, left_quadrant, quadrant, "east"):
|
||||||
|
draw_left = False
|
||||||
|
|
||||||
|
# Right border: draw if this is an east quadrant OR if the cell to the right is not connected
|
||||||
|
draw_right = True
|
||||||
|
if quadrant in ["NW", "SW"]:
|
||||||
|
# Check if cell to the right is connected
|
||||||
|
right_col = (col + 1) % GRID_SIZE
|
||||||
|
right_cell_id = grid[world_idx][row][right_col]
|
||||||
|
if right_cell_id != -1:
|
||||||
|
right_screen_id = get_screen_id_from_cell(right_cell_id)
|
||||||
|
right_screen = overworld_screens.get(right_screen_id)
|
||||||
|
if right_screen and right_screen.big:
|
||||||
|
right_quadrant = get_quadrant_from_cell_id(right_cell_id, right_screen_id)
|
||||||
|
if are_large_screen_cells_connected(cell_id, right_cell_id, quadrant, right_quadrant, "east"):
|
||||||
|
draw_right = False
|
||||||
|
|
||||||
|
# Draw the borders
|
||||||
|
if draw_top:
|
||||||
|
draw.line([(dest_x, dest_y), (dest_x + OUTPUT_CELL_SIZE - 1, dest_y)], fill='black', width=BORDER_WIDTH)
|
||||||
|
if draw_bottom:
|
||||||
|
draw.line([(dest_x, dest_y + OUTPUT_CELL_SIZE - 1), (dest_x + OUTPUT_CELL_SIZE - 1, dest_y + OUTPUT_CELL_SIZE - 1)], fill='black', width=BORDER_WIDTH)
|
||||||
|
if draw_left:
|
||||||
|
draw.line([(dest_x, dest_y), (dest_x, dest_y + OUTPUT_CELL_SIZE - 1)], fill='black', width=BORDER_WIDTH)
|
||||||
|
if draw_right:
|
||||||
draw.line([(dest_x + OUTPUT_CELL_SIZE - 1, dest_y), (dest_x + OUTPUT_CELL_SIZE - 1, dest_y + OUTPUT_CELL_SIZE - 1)], fill='black', width=BORDER_WIDTH)
|
draw.line([(dest_x + OUTPUT_CELL_SIZE - 1, dest_y), (dest_x + OUTPUT_CELL_SIZE - 1, dest_y + OUTPUT_CELL_SIZE - 1)], fill='black', width=BORDER_WIDTH)
|
||||||
else:
|
else:
|
||||||
# Small screen - draw border around single cell
|
# Small screen - draw border around single cell
|
||||||
@@ -315,8 +306,8 @@ def visualize_layout(grid: List[List[List[int]]], output_dir: str,
|
|||||||
# Draw edge connection indicators for each cell
|
# Draw edge connection indicators for each cell
|
||||||
for row in range(GRID_SIZE):
|
for row in range(GRID_SIZE):
|
||||||
for col in range(GRID_SIZE):
|
for col in range(GRID_SIZE):
|
||||||
screen_id = grid[world_idx][row][col]
|
cell_id = grid[world_idx][row][col]
|
||||||
if screen_id == -1:
|
if cell_id == -1:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
dest_x = x_offset + col * OUTPUT_CELL_SIZE
|
dest_x = x_offset + col * OUTPUT_CELL_SIZE
|
||||||
|
|||||||
Reference in New Issue
Block a user