278 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			278 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								from typing import Dict, Tuple, List
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from BaseClasses import Region, MultiWorld, LocationProgressType, ItemClassification, CollectionState
							 | 
						||
| 
								 | 
							
								from .items import ShapezItem
							 | 
						||
| 
								 | 
							
								from .locations import ShapezLocation
							 | 
						||
| 
								 | 
							
								from .data.strings import ITEMS, REGIONS, GOALS, LOCATIONS, OPTIONS
							 | 
						||
| 
								 | 
							
								from worlds.generic.Rules import add_rule
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								shapesanity_processing = [REGIONS.full, REGIONS.half, REGIONS.piece, REGIONS.stitched, REGIONS.east_wind,
							 | 
						||
| 
								 | 
							
								                          REGIONS.half_half, REGIONS.col_east_wind, REGIONS.col_half_half, REGIONS.col_full,
							 | 
						||
| 
								 | 
							
								                          REGIONS.col_half]
							 | 
						||
| 
								 | 
							
								shapesanity_coloring = [REGIONS.uncol, REGIONS.painted, REGIONS.mixed]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								all_regions = [
							 | 
						||
| 
								 | 
							
								    REGIONS.menu, REGIONS.belt, REGIONS.extract, REGIONS.main,
							 | 
						||
| 
								 | 
							
								    REGIONS.levels_1, REGIONS.levels_2, REGIONS.levels_3, REGIONS.levels_4, REGIONS.levels_5,
							 | 
						||
| 
								 | 
							
								    REGIONS.upgrades_1, REGIONS.upgrades_2, REGIONS.upgrades_3, REGIONS.upgrades_4, REGIONS.upgrades_5,
							 | 
						||
| 
								 | 
							
								    REGIONS.paint_not_quad, REGIONS.cut_not_quad, REGIONS.rotate_cw, REGIONS.stack_shape, REGIONS.store_shape,
							 | 
						||
| 
								 | 
							
								    REGIONS.trash_shape, REGIONS.blueprint, REGIONS.wiring, REGIONS.mam, REGIONS.any_building,
							 | 
						||
| 
								 | 
							
								    REGIONS.all_buildings, REGIONS.all_buildings_x1_6_belt,
							 | 
						||
| 
								 | 
							
								    *[REGIONS.sanity(processing, coloring)
							 | 
						||
| 
								 | 
							
								      for processing in shapesanity_processing
							 | 
						||
| 
								 | 
							
								      for coloring in shapesanity_coloring],
							 | 
						||
| 
								 | 
							
								]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def can_cut_half(state: CollectionState, player: int) -> bool:
							 | 
						||
| 
								 | 
							
								    return state.has(ITEMS.cutter, player)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def can_rotate_90(state: CollectionState, player: int) -> bool:
							 | 
						||
| 
								 | 
							
								    return state.has_any((ITEMS.rotator, ITEMS.rotator_ccw), player)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def can_rotate_180(state: CollectionState, player: int) -> bool:
							 | 
						||
| 
								 | 
							
								    return state.has_any((ITEMS.rotator, ITEMS.rotator_ccw, ITEMS.rotator_180), player)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def can_stack(state: CollectionState, player: int) -> bool:
							 | 
						||
| 
								 | 
							
								    return state.has(ITEMS.stacker, player)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def can_paint(state: CollectionState, player: int) -> bool:
							 | 
						||
| 
								 | 
							
								    return state.has_any((ITEMS.painter, ITEMS.painter_double), player) or can_use_quad_painter(state, player)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def can_mix_colors(state: CollectionState, player: int) -> bool:
							 | 
						||
| 
								 | 
							
								    return state.has(ITEMS.color_mixer, player)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def has_tunnel(state: CollectionState, player: int) -> bool:
							 | 
						||
| 
								 | 
							
								    return state.has_any((ITEMS.tunnel, ITEMS.tunnel_tier_ii), player)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def has_balancer(state: CollectionState, player: int) -> bool:
							 | 
						||
| 
								 | 
							
								    return state.has(ITEMS.balancer, player) or state.has_all((ITEMS.comp_merger, ITEMS.comp_splitter), player)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def can_use_quad_painter(state: CollectionState, player: int) -> bool:
							 | 
						||
| 
								 | 
							
								    return (state.has_all((ITEMS.painter_quad, ITEMS.wires), player) and
							 | 
						||
| 
								 | 
							
								            state.has_any((ITEMS.switch, ITEMS.const_signal), player))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def can_make_stitched_shape(state: CollectionState, player: int, floating: bool) -> bool:
							 | 
						||
| 
								 | 
							
								    return (can_stack(state, player) and
							 | 
						||
| 
								 | 
							
								            ((state.has(ITEMS.cutter_quad, player) and not floating) or
							 | 
						||
| 
								 | 
							
								             (can_cut_half(state, player) and can_rotate_90(state, player))))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def can_build_mam(state: CollectionState, player: int, floating: bool) -> bool:
							 | 
						||
| 
								 | 
							
								    return (can_make_stitched_shape(state, player, floating) and can_paint(state, player) and
							 | 
						||
| 
								 | 
							
								            can_mix_colors(state, player) and has_balancer(state, player) and has_tunnel(state, player) and
							 | 
						||
| 
								 | 
							
								            state.has_all((ITEMS.belt_reader, ITEMS.storage, ITEMS.item_filter,
							 | 
						||
| 
								 | 
							
								                           ITEMS.wires, ITEMS.logic_gates, ITEMS.virtual_proc), player))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def can_make_east_windmill(state: CollectionState, player: int) -> bool:
							 | 
						||
| 
								 | 
							
								    # Only used for shapesanity => single layers
							 | 
						||
| 
								 | 
							
								    return (can_stack(state, player) and
							 | 
						||
| 
								 | 
							
								            (state.has(ITEMS.cutter_quad, player) or (can_cut_half(state, player) and can_rotate_180(state, player))))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def can_make_half_half_shape(state: CollectionState, player: int) -> bool:
							 | 
						||
| 
								 | 
							
								    # Only used for shapesanity => single layers
							 | 
						||
| 
								 | 
							
								    return can_stack(state, player) and state.has_any((ITEMS.cutter, ITEMS.cutter_quad), player)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def can_make_half_shape(state: CollectionState, player: int) -> bool:
							 | 
						||
| 
								 | 
							
								    # Only used for shapesanity => single layers
							 | 
						||
| 
								 | 
							
								    return can_cut_half(state, player) or state.has_all((ITEMS.cutter_quad, ITEMS.stacker), player)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def has_x_belt_multiplier(state: CollectionState, player: int, needed: float) -> bool:
							 | 
						||
| 
								 | 
							
								    # Assumes there are no upgrade traps
							 | 
						||
| 
								 | 
							
								    multiplier = 1.0
							 | 
						||
| 
								 | 
							
								    # Rising upgrades do the least improvement if received before other upgrades
							 | 
						||
| 
								 | 
							
								    for _ in range(state.count(ITEMS.upgrade_rising_belt, player)):
							 | 
						||
| 
								 | 
							
								        multiplier *= 2
							 | 
						||
| 
								 | 
							
								    multiplier += state.count(ITEMS.upgrade_gigantic_belt, player)*10
							 | 
						||
| 
								 | 
							
								    multiplier += state.count(ITEMS.upgrade_big_belt, player)
							 | 
						||
| 
								 | 
							
								    multiplier += state.count(ITEMS.upgrade_small_belt, player)*0.1
							 | 
						||
| 
								 | 
							
								    return multiplier >= needed
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def has_logic_list_building(state: CollectionState, player: int, buildings: List[str], index: int,
							 | 
						||
| 
								 | 
							
								                            includeuseful: bool) -> bool:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Includes balancer, tunnel, and trash in logic in order to make them appear in earlier spheres
							 | 
						||
| 
								 | 
							
								    if includeuseful and not (state.has(ITEMS.trash, player) and has_balancer(state, player) and
							 | 
						||
| 
								 | 
							
								                              has_tunnel(state, player)):
							 | 
						||
| 
								 | 
							
								        return False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if buildings[index] == ITEMS.cutter:
							 | 
						||
| 
								 | 
							
								        if buildings.index(ITEMS.stacker) < index:
							 | 
						||
| 
								 | 
							
								            return state.has_any((ITEMS.cutter, ITEMS.cutter_quad), player)
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            return can_cut_half(state, player)
							 | 
						||
| 
								 | 
							
								    elif buildings[index] == ITEMS.rotator:
							 | 
						||
| 
								 | 
							
								        return can_rotate_90(state, player)
							 | 
						||
| 
								 | 
							
								    elif buildings[index] == ITEMS.stacker:
							 | 
						||
| 
								 | 
							
								        return can_stack(state, player)
							 | 
						||
| 
								 | 
							
								    elif buildings[index] == ITEMS.painter:
							 | 
						||
| 
								 | 
							
								        return can_paint(state, player)
							 | 
						||
| 
								 | 
							
								    elif buildings[index] == ITEMS.color_mixer:
							 | 
						||
| 
								 | 
							
								        return can_mix_colors(state, player)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def create_shapez_regions(player: int, multiworld: MultiWorld, floating: bool,
							 | 
						||
| 
								 | 
							
								                          included_locations: Dict[str, Tuple[str, LocationProgressType]],
							 | 
						||
| 
								 | 
							
								                          location_name_to_id: Dict[str, int], level_logic_buildings: List[str],
							 | 
						||
| 
								 | 
							
								                          upgrade_logic_buildings: List[str], early_useful: str, goal: str) -> List[Region]:
							 | 
						||
| 
								 | 
							
								    """Creates and returns a list of all regions with entrances and all locations placed correctly."""
							 | 
						||
| 
								 | 
							
								    regions: Dict[str, Region] = {name: Region(name, player, multiworld) for name in all_regions}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Creates ShapezLocations for every included location and puts them into the correct region
							 | 
						||
| 
								 | 
							
								    for name, data in included_locations.items():
							 | 
						||
| 
								 | 
							
								        regions[data[0]].locations.append(ShapezLocation(player, name, location_name_to_id[name],
							 | 
						||
| 
								 | 
							
								                                                         regions[data[0]], data[1]))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Create goal event
							 | 
						||
| 
								 | 
							
								    if goal in [GOALS.vanilla, GOALS.mam]:
							 | 
						||
| 
								 | 
							
								        goal_region = regions[REGIONS.levels_5]
							 | 
						||
| 
								 | 
							
								    elif goal == GOALS.even_fasterer:
							 | 
						||
| 
								 | 
							
								        goal_region = regions[REGIONS.upgrades_5]
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        goal_region = regions[REGIONS.all_buildings]
							 | 
						||
| 
								 | 
							
								    goal_location = ShapezLocation(player, LOCATIONS.goal, None, goal_region, LocationProgressType.DEFAULT)
							 | 
						||
| 
								 | 
							
								    goal_location.place_locked_item(ShapezItem(ITEMS.goal, ItemClassification.progression_skip_balancing, None, player))
							 | 
						||
| 
								 | 
							
								    if goal == GOALS.efficiency_iii:
							 | 
						||
| 
								 | 
							
								        add_rule(goal_location, lambda state: has_x_belt_multiplier(state, player, 8))
							 | 
						||
| 
								 | 
							
								    goal_region.locations.append(goal_location)
							 | 
						||
| 
								 | 
							
								    multiworld.completion_condition[player] = lambda state: state.has(ITEMS.goal, player)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Connect Menu to rest of regions
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.menu].connect(regions[REGIONS.belt], "Placing belts", lambda state: state.has(ITEMS.belt, player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.menu].connect(regions[REGIONS.extract], "Extracting shapes from patches",
							 | 
						||
| 
								 | 
							
								                                  lambda state: state.has_any((ITEMS.extractor, ITEMS.extractor_chain), player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.extract].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.main], "Transporting shapes over the canvas",
							 | 
						||
| 
								 | 
							
								        lambda state: state.has_any((ITEMS.belt, ITEMS.comp_merger, ITEMS.comp_splitter), player)
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Connect achievement regions
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(regions[REGIONS.paint_not_quad], "Painting with (double) painter",
							 | 
						||
| 
								 | 
							
								                                  lambda state: state.has_any((ITEMS.painter, ITEMS.painter_double), player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.extract].connect(regions[REGIONS.cut_not_quad], "Cutting with half cutter",
							 | 
						||
| 
								 | 
							
								                                     lambda state: can_cut_half(state, player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.extract].connect(regions[REGIONS.rotate_cw], "Rotating clockwise",
							 | 
						||
| 
								 | 
							
								                                     lambda state: state.has(ITEMS.rotator, player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.extract].connect(regions[REGIONS.stack_shape], "Stacking shapes",
							 | 
						||
| 
								 | 
							
								                                     lambda state: can_stack(state, player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.extract].connect(regions[REGIONS.store_shape], "Storing shapes",
							 | 
						||
| 
								 | 
							
								                                     lambda state: state.has(ITEMS.storage, player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.extract].connect(regions[REGIONS.trash_shape], "Trashing shapes",
							 | 
						||
| 
								 | 
							
								                                     lambda state: state.has(ITEMS.trash, player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(regions[REGIONS.blueprint], "Copying and placing blueprints",
							 | 
						||
| 
								 | 
							
								                                  lambda state: state.has(ITEMS.blueprints, player) and
							 | 
						||
| 
								 | 
							
								                                                can_make_stitched_shape(state, player, floating) and
							 | 
						||
| 
								 | 
							
								                                                can_paint(state, player) and can_mix_colors(state, player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.menu].connect(regions[REGIONS.wiring], "Using the wires layer",
							 | 
						||
| 
								 | 
							
								                                  lambda state: state.has(ITEMS.wires, player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(regions[REGIONS.mam], "Building a MAM",
							 | 
						||
| 
								 | 
							
								                                  lambda state: can_build_mam(state, player, floating))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.menu].connect(regions[REGIONS.any_building], "Placing any building", lambda state: state.has_any((
							 | 
						||
| 
								 | 
							
								        ITEMS.belt, ITEMS.balancer, ITEMS.comp_merger, ITEMS.comp_splitter, ITEMS.tunnel, ITEMS.tunnel_tier_ii,
							 | 
						||
| 
								 | 
							
								        ITEMS.extractor, ITEMS.extractor_chain, ITEMS.cutter, ITEMS.cutter_quad, ITEMS.rotator, ITEMS.rotator_ccw,
							 | 
						||
| 
								 | 
							
								        ITEMS.rotator_180, ITEMS.stacker, ITEMS.painter, ITEMS.painter_double, ITEMS.painter_quad, ITEMS.color_mixer,
							 | 
						||
| 
								 | 
							
								        ITEMS.trash, ITEMS.belt_reader, ITEMS.storage, ITEMS.switch, ITEMS.item_filter, ITEMS.display, ITEMS.wires
							 | 
						||
| 
								 | 
							
								    ), player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(regions[REGIONS.all_buildings], "Using all main buildings",
							 | 
						||
| 
								 | 
							
								                                  lambda state: can_make_stitched_shape(state, player, floating) and
							 | 
						||
| 
								 | 
							
								                                                can_paint(state, player) and can_mix_colors(state, player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.all_buildings].connect(regions[REGIONS.all_buildings_x1_6_belt],
							 | 
						||
| 
								 | 
							
								                                           "Delivering per second with 1.6x belt speed",
							 | 
						||
| 
								 | 
							
								                                           lambda state: has_x_belt_multiplier(state, player, 1.6))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Progressively connect level and upgrade regions
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.levels_1], "Using first level building",
							 | 
						||
| 
								 | 
							
								        lambda state: has_logic_list_building(state, player, level_logic_buildings, 0, False))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.levels_1].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.levels_2], "Using second level building",
							 | 
						||
| 
								 | 
							
								        lambda state: has_logic_list_building(state, player, level_logic_buildings, 1, False))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.levels_2].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.levels_3], "Using third level building",
							 | 
						||
| 
								 | 
							
								        lambda state: has_logic_list_building(state, player, level_logic_buildings, 2,
							 | 
						||
| 
								 | 
							
								                                              early_useful == OPTIONS.buildings_3))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.levels_3].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.levels_4], "Using fourth level building",
							 | 
						||
| 
								 | 
							
								        lambda state: has_logic_list_building(state, player, level_logic_buildings, 3, False))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.levels_4].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.levels_5], "Using fifth level building",
							 | 
						||
| 
								 | 
							
								        lambda state: has_logic_list_building(state, player, level_logic_buildings, 4,
							 | 
						||
| 
								 | 
							
								                                              early_useful == OPTIONS.buildings_5))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.upgrades_1], "Using first upgrade building",
							 | 
						||
| 
								 | 
							
								        lambda state: has_logic_list_building(state, player, upgrade_logic_buildings, 0, False))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.upgrades_1].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.upgrades_2], "Using second upgrade building",
							 | 
						||
| 
								 | 
							
								        lambda state: has_logic_list_building(state, player, upgrade_logic_buildings, 1, False))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.upgrades_2].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.upgrades_3], "Using third upgrade building",
							 | 
						||
| 
								 | 
							
								        lambda state: has_logic_list_building(state, player, upgrade_logic_buildings, 2,
							 | 
						||
| 
								 | 
							
								                                              early_useful == OPTIONS.buildings_3))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.upgrades_3].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.upgrades_4], "Using fourth upgrade building",
							 | 
						||
| 
								 | 
							
								        lambda state: has_logic_list_building(state, player, upgrade_logic_buildings, 3, False))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.upgrades_4].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.upgrades_5], "Using fifth upgrade building",
							 | 
						||
| 
								 | 
							
								        lambda state: has_logic_list_building(state, player, upgrade_logic_buildings, 4,
							 | 
						||
| 
								 | 
							
								                                              early_useful == OPTIONS.buildings_5))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Connect Uncolored shapesanity regions to Main
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.sanity(REGIONS.full, REGIONS.uncol)], "Delivering unprocessed", lambda state: True)
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.sanity(REGIONS.half, REGIONS.uncol)], "Cutting in single half",
							 | 
						||
| 
								 | 
							
								        lambda state: can_make_half_shape(state, player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.sanity(REGIONS.piece, REGIONS.uncol)], "Cutting in single piece",
							 | 
						||
| 
								 | 
							
								        lambda state: (can_cut_half(state, player) and can_rotate_90(state, player)) or
							 | 
						||
| 
								 | 
							
								                      state.has(ITEMS.cutter_quad, player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.sanity(REGIONS.half_half, REGIONS.uncol)], "Cutting and stacking into two halves",
							 | 
						||
| 
								 | 
							
								        lambda state: can_make_half_half_shape(state, player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.sanity(REGIONS.stitched, REGIONS.uncol)], "Stitching complex shapes",
							 | 
						||
| 
								 | 
							
								        lambda state: can_make_stitched_shape(state, player, floating))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.sanity(REGIONS.east_wind, REGIONS.uncol)], "Rotating and stitching a single windmill half",
							 | 
						||
| 
								 | 
							
								        lambda state: can_make_east_windmill(state, player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.sanity(REGIONS.col_full, REGIONS.uncol)], "Painting with a quad painter or stitching",
							 | 
						||
| 
								 | 
							
								        lambda state: can_make_stitched_shape(state, player, floating) or can_use_quad_painter(state, player))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.sanity(REGIONS.col_east_wind, REGIONS.uncol)], "Why windmill, why?",
							 | 
						||
| 
								 | 
							
								        lambda state: can_make_stitched_shape(state, player, floating) or
							 | 
						||
| 
								 | 
							
								                      (can_use_quad_painter(state, player) and can_make_east_windmill(state, player)))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.sanity(REGIONS.col_half_half, REGIONS.uncol)], "Quad painting a half-half shape",
							 | 
						||
| 
								 | 
							
								        lambda state: can_make_stitched_shape(state, player, floating) or
							 | 
						||
| 
								 | 
							
								                      (can_use_quad_painter(state, player) and can_make_half_half_shape(state, player)))
							 | 
						||
| 
								 | 
							
								    regions[REGIONS.main].connect(
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.sanity(REGIONS.col_half, REGIONS.uncol)], "Quad painting a half shape",
							 | 
						||
| 
								 | 
							
								        lambda state: can_make_stitched_shape(state, player, floating) or
							 | 
						||
| 
								 | 
							
								                      (can_use_quad_painter(state, player) and can_make_half_shape(state, player)))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # Progressively connect colored shapesanity regions
							 | 
						||
| 
								 | 
							
								    for processing in shapesanity_processing:
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.sanity(processing, REGIONS.uncol)].connect(
							 | 
						||
| 
								 | 
							
								            regions[REGIONS.sanity(processing, REGIONS.painted)], f"Painting a {processing.lower()} shape",
							 | 
						||
| 
								 | 
							
								            lambda state: can_paint(state, player))
							 | 
						||
| 
								 | 
							
								        regions[REGIONS.sanity(processing, REGIONS.painted)].connect(
							 | 
						||
| 
								 | 
							
								            regions[REGIONS.sanity(processing, REGIONS.mixed)], f"Mixing colors for a {processing.lower()} shape",
							 | 
						||
| 
								 | 
							
								            lambda state: can_mix_colors(state, player))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return [region for region in regions.values() if len(region.locations) or len(region.exits)]
							 |