Lingo: Add panels mode door shuffle (#3163)
* Created panels mode door shuffle * Added some panel door item names * Remove RUNT TURN panel door Not really useful. * Fix logic with First SIX related stuff * Add group_doors to slot data * Fix LEVEL 2 behavior with panels mode * Fixed unit tests * Fixed duplicate IDs from merge * Just regenerated new IDs * Fixed duplication of color and door group items * Removed unnecessary unit test option * Fix The Seeker being achievable without entrance door * Fix The Observant being achievable without locked panels * Added some more panel doors * Added Progressive Suits Area * Lingo: Fix Basement access with THE MASTER * Added indirect conditions for MASTER-blocked entrances * Fixed Incomparable achievement access * Fix STAIRS panel logic * Fix merge error with good items * Is this clearer? * DREAD and TURN LEARN * Allow a weird edge case for reduced locations Panels mode door shuffle + grouped doors + color shuffle + pilgrimage enabled is exactly the right number of items for reduced locations. Removing color shuffle also allows for disabling pilgrimage, adding sunwarp locking, or both, with a couple of locations left over. * Prevent small sphere one on panels mode * Added shuffle_doors aliases for old options * Fixed a unit test * Updated datafile * Tweaked requirements for reduced locations * Added player name to OptionError messages * Update generated.dat
This commit is contained in:
parent
d030a698a6
commit
cc22161644
|
@ -170,7 +170,8 @@ class LingoWorld(World):
|
||||||
slot_options = [
|
slot_options = [
|
||||||
"death_link", "victory_condition", "shuffle_colors", "shuffle_doors", "shuffle_paintings", "shuffle_panels",
|
"death_link", "victory_condition", "shuffle_colors", "shuffle_doors", "shuffle_paintings", "shuffle_panels",
|
||||||
"enable_pilgrimage", "sunwarp_access", "mastery_achievements", "level_2_requirement", "location_checks",
|
"enable_pilgrimage", "sunwarp_access", "mastery_achievements", "level_2_requirement", "location_checks",
|
||||||
"early_color_hallways", "pilgrimage_allows_roof_access", "pilgrimage_allows_paintings", "shuffle_sunwarps"
|
"early_color_hallways", "pilgrimage_allows_roof_access", "pilgrimage_allows_paintings", "shuffle_sunwarps",
|
||||||
|
"group_doors"
|
||||||
]
|
]
|
||||||
|
|
||||||
slot_data = {
|
slot_data = {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -1478,3 +1478,145 @@ progression:
|
||||||
Progressive Art Gallery: 444563
|
Progressive Art Gallery: 444563
|
||||||
Progressive Colorful: 444580
|
Progressive Colorful: 444580
|
||||||
Progressive Pilgrimage: 444583
|
Progressive Pilgrimage: 444583
|
||||||
|
Progressive Suits Area: 444602
|
||||||
|
Progressive Symmetry Room: 444608
|
||||||
|
Progressive Number Hunt: 444654
|
||||||
|
panel_doors:
|
||||||
|
Starting Room:
|
||||||
|
HIDDEN: 444589
|
||||||
|
Hidden Room:
|
||||||
|
OPEN: 444590
|
||||||
|
Hub Room:
|
||||||
|
ORDER: 444591
|
||||||
|
SLAUGHTER: 444592
|
||||||
|
TRACE: 444594
|
||||||
|
RAT: 444595
|
||||||
|
OPEN: 444596
|
||||||
|
Crossroads:
|
||||||
|
DECAY: 444597
|
||||||
|
NOPE: 444598
|
||||||
|
WE ROT: 444599
|
||||||
|
WORDS SWORD: 444600
|
||||||
|
BEND HI: 444601
|
||||||
|
Lost Area:
|
||||||
|
LOST: 444603
|
||||||
|
Amen Name Area:
|
||||||
|
AMEN NAME: 444604
|
||||||
|
The Tenacious:
|
||||||
|
Black Palindromes: 444605
|
||||||
|
Near Far Area:
|
||||||
|
NEAR FAR: 444606
|
||||||
|
Warts Straw Area:
|
||||||
|
WARTS STRAW: 444609
|
||||||
|
Leaf Feel Area:
|
||||||
|
LEAF FEEL: 444610
|
||||||
|
Outside The Agreeable:
|
||||||
|
MASSACRED: 444611
|
||||||
|
BLACK: 444612
|
||||||
|
CLOSE: 444613
|
||||||
|
RIGHT: 444614
|
||||||
|
Compass Room:
|
||||||
|
Lookout: 444615
|
||||||
|
Hedge Maze:
|
||||||
|
DOWN: 444617
|
||||||
|
The Perceptive:
|
||||||
|
GAZE: 444618
|
||||||
|
The Observant:
|
||||||
|
BACKSIDE: 444619
|
||||||
|
STAIRS: 444621
|
||||||
|
The Incomparable:
|
||||||
|
Giant Sevens: 444622
|
||||||
|
Orange Tower:
|
||||||
|
Access: 444623
|
||||||
|
Orange Tower First Floor:
|
||||||
|
SECRET: 444624
|
||||||
|
Orange Tower Fourth Floor:
|
||||||
|
HOT CRUSTS: 444625
|
||||||
|
Orange Tower Fifth Floor:
|
||||||
|
SIZE: 444626
|
||||||
|
First Second Third Fourth:
|
||||||
|
FIRST SECOND THIRD FOURTH: 444627
|
||||||
|
The Colorful (White):
|
||||||
|
BEGIN: 444628
|
||||||
|
The Colorful (Black):
|
||||||
|
FOUND: 444630
|
||||||
|
The Colorful (Red):
|
||||||
|
LOAF: 444631
|
||||||
|
The Colorful (Yellow):
|
||||||
|
CREAM: 444632
|
||||||
|
The Colorful (Blue):
|
||||||
|
SUN: 444633
|
||||||
|
The Colorful (Purple):
|
||||||
|
SPOON: 444634
|
||||||
|
The Colorful (Orange):
|
||||||
|
LETTERS: 444635
|
||||||
|
The Colorful (Green):
|
||||||
|
WALLS: 444636
|
||||||
|
The Colorful (Brown):
|
||||||
|
IRON: 444637
|
||||||
|
The Colorful (Gray):
|
||||||
|
OBSTACLE: 444638
|
||||||
|
Owl Hallway:
|
||||||
|
STRAYS: 444639
|
||||||
|
Outside The Initiated:
|
||||||
|
UNCOVER: 444640
|
||||||
|
OXEN: 444641
|
||||||
|
Outside The Bold:
|
||||||
|
UNOPEN: 444642
|
||||||
|
BEGIN: 444643
|
||||||
|
Outside The Undeterred:
|
||||||
|
ZERO: 444644
|
||||||
|
PEN: 444645
|
||||||
|
TWO: 444646
|
||||||
|
THREE: 444647
|
||||||
|
FOUR: 444648
|
||||||
|
Number Hunt:
|
||||||
|
FIVE: 444649
|
||||||
|
SIX: 444650
|
||||||
|
SEVEN: 444651
|
||||||
|
EIGHT: 444652
|
||||||
|
NINE: 444653
|
||||||
|
Color Hunt:
|
||||||
|
EXIT: 444655
|
||||||
|
RED: 444656
|
||||||
|
BLUE: 444658
|
||||||
|
YELLOW: 444659
|
||||||
|
ORANGE: 444660
|
||||||
|
PURPLE: 444661
|
||||||
|
GREEN: 444662
|
||||||
|
The Bearer:
|
||||||
|
FARTHER: 444663
|
||||||
|
MIDDLE: 444664
|
||||||
|
Knight Night (Final):
|
||||||
|
TRUSTED: 444665
|
||||||
|
Outside The Wondrous:
|
||||||
|
SHRINK: 444666
|
||||||
|
Hallway Room (1):
|
||||||
|
CASTLE: 444667
|
||||||
|
Hallway Room (2):
|
||||||
|
COUNTERCLOCKWISE: 444669
|
||||||
|
Hallway Room (3):
|
||||||
|
TRANSFORMATION: 444670
|
||||||
|
Hallway Room (4):
|
||||||
|
WHEELBARROW: 444671
|
||||||
|
Outside The Wanderer:
|
||||||
|
WANDERLUST: 444672
|
||||||
|
Art Gallery:
|
||||||
|
ORDER: 444673
|
||||||
|
Room Room:
|
||||||
|
STAIRS: 444674
|
||||||
|
Colors: 444676
|
||||||
|
Outside The Wise:
|
||||||
|
KITTEN CAT: 444677
|
||||||
|
Outside The Scientific:
|
||||||
|
OPEN: 444678
|
||||||
|
Directional Gallery:
|
||||||
|
TURN LEARN: 444679
|
||||||
|
panel_groups:
|
||||||
|
Tenacious Entrance Panels: 444593
|
||||||
|
Symmetry Room Panels: 444607
|
||||||
|
Backside Entrance Panels: 444620
|
||||||
|
Colorful Panels: 444629
|
||||||
|
Color Hunt Panels: 444657
|
||||||
|
Hallway Room Panels: 444668
|
||||||
|
Room Room Panels: 444675
|
||||||
|
|
|
@ -12,6 +12,11 @@ class RoomAndPanel(NamedTuple):
|
||||||
panel: str
|
panel: str
|
||||||
|
|
||||||
|
|
||||||
|
class RoomAndPanelDoor(NamedTuple):
|
||||||
|
room: Optional[str]
|
||||||
|
panel_door: str
|
||||||
|
|
||||||
|
|
||||||
class EntranceType(Flag):
|
class EntranceType(Flag):
|
||||||
NORMAL = auto()
|
NORMAL = auto()
|
||||||
PAINTING = auto()
|
PAINTING = auto()
|
||||||
|
@ -63,9 +68,15 @@ class Panel(NamedTuple):
|
||||||
exclude_reduce: bool
|
exclude_reduce: bool
|
||||||
achievement: bool
|
achievement: bool
|
||||||
non_counting: bool
|
non_counting: bool
|
||||||
|
panel_door: Optional[RoomAndPanelDoor] # This will always be fully specified.
|
||||||
location_name: Optional[str]
|
location_name: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
|
class PanelDoor(NamedTuple):
|
||||||
|
item_name: str
|
||||||
|
panel_group: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class Painting(NamedTuple):
|
class Painting(NamedTuple):
|
||||||
id: str
|
id: str
|
||||||
room: str
|
room: str
|
||||||
|
|
|
@ -3,7 +3,7 @@ from typing import Dict, List, NamedTuple, Set
|
||||||
|
|
||||||
from BaseClasses import Item, ItemClassification
|
from BaseClasses import Item, ItemClassification
|
||||||
from .static_logic import DOORS_BY_ROOM, PROGRESSIVE_ITEMS, get_door_group_item_id, get_door_item_id, \
|
from .static_logic import DOORS_BY_ROOM, PROGRESSIVE_ITEMS, get_door_group_item_id, get_door_item_id, \
|
||||||
get_progressive_item_id, get_special_item_id
|
get_progressive_item_id, get_special_item_id, PANEL_DOORS_BY_ROOM, get_panel_door_item_id, get_panel_group_item_id
|
||||||
|
|
||||||
|
|
||||||
class ItemType(Enum):
|
class ItemType(Enum):
|
||||||
|
@ -65,6 +65,21 @@ def load_item_data():
|
||||||
ItemClassification.progression, ItemType.NORMAL, True, [])
|
ItemClassification.progression, ItemType.NORMAL, True, [])
|
||||||
ITEMS_BY_GROUP.setdefault("Doors", []).append(group)
|
ITEMS_BY_GROUP.setdefault("Doors", []).append(group)
|
||||||
|
|
||||||
|
panel_groups: Set[str] = set()
|
||||||
|
for room_name, panel_doors in PANEL_DOORS_BY_ROOM.items():
|
||||||
|
for panel_door_name, panel_door in panel_doors.items():
|
||||||
|
if panel_door.panel_group is not None:
|
||||||
|
panel_groups.add(panel_door.panel_group)
|
||||||
|
|
||||||
|
ALL_ITEM_TABLE[panel_door.item_name] = ItemData(get_panel_door_item_id(room_name, panel_door_name),
|
||||||
|
ItemClassification.progression, ItemType.NORMAL, False, [])
|
||||||
|
ITEMS_BY_GROUP.setdefault("Panels", []).append(panel_door.item_name)
|
||||||
|
|
||||||
|
for group in panel_groups:
|
||||||
|
ALL_ITEM_TABLE[group] = ItemData(get_panel_group_item_id(group), ItemClassification.progression,
|
||||||
|
ItemType.NORMAL, False, [])
|
||||||
|
ITEMS_BY_GROUP.setdefault("Panels", []).append(group)
|
||||||
|
|
||||||
special_items: Dict[str, ItemClassification] = {
|
special_items: Dict[str, ItemClassification] = {
|
||||||
":)": ItemClassification.filler,
|
":)": ItemClassification.filler,
|
||||||
"The Feeling of Being Lost": ItemClassification.filler,
|
"The Feeling of Being Lost": ItemClassification.filler,
|
||||||
|
|
|
@ -8,21 +8,31 @@ from .items import TRAP_ITEMS
|
||||||
|
|
||||||
|
|
||||||
class ShuffleDoors(Choice):
|
class ShuffleDoors(Choice):
|
||||||
"""If on, opening doors will require their respective "keys".
|
"""This option specifies how doors open.
|
||||||
|
|
||||||
- **Simple:** Doors are sorted into logical groups, which are all opened by
|
- **None:** Doors in the game will open the way they do in vanilla.
|
||||||
receiving an item.
|
- **Panels:** Doors still open as in vanilla, but the panels that open the
|
||||||
- **Complex:** The items are much more granular, and will usually only open
|
doors will be locked, and an item will be required to unlock the panels.
|
||||||
a single door each.
|
- **Doors:** the doors themselves are locked behind items, and will open
|
||||||
|
automatically without needing to solve a panel once the key is obtained.
|
||||||
"""
|
"""
|
||||||
display_name = "Shuffle Doors"
|
display_name = "Shuffle Doors"
|
||||||
option_none = 0
|
option_none = 0
|
||||||
option_simple = 1
|
option_panels = 1
|
||||||
option_complex = 2
|
option_doors = 2
|
||||||
|
alias_simple = 2
|
||||||
|
alias_complex = 2
|
||||||
|
|
||||||
|
|
||||||
|
class GroupDoors(Toggle):
|
||||||
|
"""By default, door shuffle in either panels or doors mode will create individual keys for every panel or door to be locked.
|
||||||
|
|
||||||
|
When group doors is on, some panels and doors are sorted into logical groups, which are opened together by receiving an item."""
|
||||||
|
display_name = "Group Doors"
|
||||||
|
|
||||||
|
|
||||||
class ProgressiveOrangeTower(DefaultOnToggle):
|
class ProgressiveOrangeTower(DefaultOnToggle):
|
||||||
"""When "Shuffle Doors" is on, this setting governs the manner in which the Orange Tower floors open up.
|
"""When "Shuffle Doors" is on doors mode, this setting governs the manner in which the Orange Tower floors open up.
|
||||||
|
|
||||||
- **Off:** There is an item for each floor of the tower, and each floor's
|
- **Off:** There is an item for each floor of the tower, and each floor's
|
||||||
item is the only one needed to access that floor.
|
item is the only one needed to access that floor.
|
||||||
|
@ -33,7 +43,7 @@ class ProgressiveOrangeTower(DefaultOnToggle):
|
||||||
|
|
||||||
|
|
||||||
class ProgressiveColorful(DefaultOnToggle):
|
class ProgressiveColorful(DefaultOnToggle):
|
||||||
"""When "Shuffle Doors" is on "complex", this setting governs the manner in which The Colorful opens up.
|
"""When "Shuffle Doors" is on either panels or doors mode and "Group Doors" is off, this setting governs the manner in which The Colorful opens up.
|
||||||
|
|
||||||
- **Off:** There is an item for each room of The Colorful, meaning that
|
- **Off:** There is an item for each room of The Colorful, meaning that
|
||||||
random rooms in the middle of the sequence can open up without giving you
|
random rooms in the middle of the sequence can open up without giving you
|
||||||
|
@ -253,6 +263,7 @@ lingo_option_groups = [
|
||||||
@dataclass
|
@dataclass
|
||||||
class LingoOptions(PerGameCommonOptions):
|
class LingoOptions(PerGameCommonOptions):
|
||||||
shuffle_doors: ShuffleDoors
|
shuffle_doors: ShuffleDoors
|
||||||
|
group_doors: GroupDoors
|
||||||
progressive_orange_tower: ProgressiveOrangeTower
|
progressive_orange_tower: ProgressiveOrangeTower
|
||||||
progressive_colorful: ProgressiveColorful
|
progressive_colorful: ProgressiveColorful
|
||||||
location_checks: LocationChecks
|
location_checks: LocationChecks
|
||||||
|
|
|
@ -7,8 +7,8 @@ from .items import ALL_ITEM_TABLE, ItemType
|
||||||
from .locations import ALL_LOCATION_TABLE, LocationClassification
|
from .locations import ALL_LOCATION_TABLE, LocationClassification
|
||||||
from .options import LocationChecks, ShuffleDoors, SunwarpAccess, VictoryCondition
|
from .options import LocationChecks, ShuffleDoors, SunwarpAccess, VictoryCondition
|
||||||
from .static_logic import DOORS_BY_ROOM, PAINTINGS, PAINTING_ENTRANCES, PAINTING_EXITS, \
|
from .static_logic import DOORS_BY_ROOM, PAINTINGS, PAINTING_ENTRANCES, PAINTING_EXITS, \
|
||||||
PANELS_BY_ROOM, PROGRESSION_BY_ROOM, REQUIRED_PAINTING_ROOMS, REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS, \
|
PANELS_BY_ROOM, REQUIRED_PAINTING_ROOMS, REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS, PROGRESSIVE_DOORS_BY_ROOM, \
|
||||||
SUNWARP_ENTRANCES, SUNWARP_EXITS
|
PANEL_DOORS_BY_ROOM, PROGRESSIVE_PANELS_BY_ROOM, SUNWARP_ENTRANCES, SUNWARP_EXITS
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from . import LingoWorld
|
from . import LingoWorld
|
||||||
|
@ -18,6 +18,8 @@ class AccessRequirements:
|
||||||
rooms: Set[str]
|
rooms: Set[str]
|
||||||
doors: Set[RoomAndDoor]
|
doors: Set[RoomAndDoor]
|
||||||
colors: Set[str]
|
colors: Set[str]
|
||||||
|
items: Set[str]
|
||||||
|
progression: Dict[str, int]
|
||||||
the_master: bool
|
the_master: bool
|
||||||
postgame: bool
|
postgame: bool
|
||||||
|
|
||||||
|
@ -25,6 +27,8 @@ class AccessRequirements:
|
||||||
self.rooms = set()
|
self.rooms = set()
|
||||||
self.doors = set()
|
self.doors = set()
|
||||||
self.colors = set()
|
self.colors = set()
|
||||||
|
self.items = set()
|
||||||
|
self.progression = dict()
|
||||||
self.the_master = False
|
self.the_master = False
|
||||||
self.postgame = False
|
self.postgame = False
|
||||||
|
|
||||||
|
@ -32,12 +36,17 @@ class AccessRequirements:
|
||||||
self.rooms |= other.rooms
|
self.rooms |= other.rooms
|
||||||
self.doors |= other.doors
|
self.doors |= other.doors
|
||||||
self.colors |= other.colors
|
self.colors |= other.colors
|
||||||
|
self.items |= other.items
|
||||||
self.the_master |= other.the_master
|
self.the_master |= other.the_master
|
||||||
self.postgame |= other.postgame
|
self.postgame |= other.postgame
|
||||||
|
|
||||||
|
for progression, index in other.progression.items():
|
||||||
|
if progression not in self.progression or index > self.progression[progression]:
|
||||||
|
self.progression[progression] = index
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"AccessRequirements(rooms={self.rooms}, doors={self.doors}, colors={self.colors}," \
|
return f"AccessRequirements(rooms={self.rooms}, doors={self.doors}, colors={self.colors}, items={self.items}," \
|
||||||
f" the_master={self.the_master}, postgame={self.postgame})"
|
f" progression={self.progression}), the_master={self.the_master}, postgame={self.postgame}"
|
||||||
|
|
||||||
|
|
||||||
class PlayerLocation(NamedTuple):
|
class PlayerLocation(NamedTuple):
|
||||||
|
@ -117,15 +126,15 @@ class LingoPlayerLogic:
|
||||||
self.item_by_door.setdefault(room, {})[door] = item
|
self.item_by_door.setdefault(room, {})[door] = item
|
||||||
|
|
||||||
def handle_non_grouped_door(self, room_name: str, door_data: Door, world: "LingoWorld"):
|
def handle_non_grouped_door(self, room_name: str, door_data: Door, world: "LingoWorld"):
|
||||||
if room_name in PROGRESSION_BY_ROOM and door_data.name in PROGRESSION_BY_ROOM[room_name]:
|
if room_name in PROGRESSIVE_DOORS_BY_ROOM and door_data.name in PROGRESSIVE_DOORS_BY_ROOM[room_name]:
|
||||||
progression_name = PROGRESSION_BY_ROOM[room_name][door_data.name].item_name
|
progression_name = PROGRESSIVE_DOORS_BY_ROOM[room_name][door_data.name].item_name
|
||||||
progression_handling = should_split_progression(progression_name, world)
|
progression_handling = should_split_progression(progression_name, world)
|
||||||
|
|
||||||
if progression_handling == ProgressiveItemBehavior.SPLIT:
|
if progression_handling == ProgressiveItemBehavior.SPLIT:
|
||||||
self.set_door_item(room_name, door_data.name, door_data.item_name)
|
self.set_door_item(room_name, door_data.name, door_data.item_name)
|
||||||
self.real_items.append(door_data.item_name)
|
self.real_items.append(door_data.item_name)
|
||||||
elif progression_handling == ProgressiveItemBehavior.PROGRESSIVE:
|
elif progression_handling == ProgressiveItemBehavior.PROGRESSIVE:
|
||||||
progressive_item_name = PROGRESSION_BY_ROOM[room_name][door_data.name].item_name
|
progressive_item_name = PROGRESSIVE_DOORS_BY_ROOM[room_name][door_data.name].item_name
|
||||||
self.set_door_item(room_name, door_data.name, progressive_item_name)
|
self.set_door_item(room_name, door_data.name, progressive_item_name)
|
||||||
self.real_items.append(progressive_item_name)
|
self.real_items.append(progressive_item_name)
|
||||||
else:
|
else:
|
||||||
|
@ -156,17 +165,31 @@ class LingoPlayerLogic:
|
||||||
victory_condition = world.options.victory_condition
|
victory_condition = world.options.victory_condition
|
||||||
early_color_hallways = world.options.early_color_hallways
|
early_color_hallways = world.options.early_color_hallways
|
||||||
|
|
||||||
if location_checks == LocationChecks.option_reduced and door_shuffle != ShuffleDoors.option_none:
|
if location_checks == LocationChecks.option_reduced:
|
||||||
raise OptionError("You cannot have reduced location checks when door shuffle is on, because there would not"
|
if door_shuffle == ShuffleDoors.option_doors:
|
||||||
" be enough locations for all of the door items.")
|
raise OptionError(f"Slot \"{world.player_name}\" cannot have reduced location checks when door shuffle"
|
||||||
|
f" is on, because there would not be enough locations for all of the door items.")
|
||||||
|
if door_shuffle == ShuffleDoors.option_panels:
|
||||||
|
if not world.options.group_doors:
|
||||||
|
raise OptionError(f"Slot \"{world.player_name}\" cannot have reduced location checks when ungrouped"
|
||||||
|
f" panels mode door shuffle is on, because there would not be enough locations for"
|
||||||
|
f" all of the panel items.")
|
||||||
|
if color_shuffle:
|
||||||
|
raise OptionError(f"Slot \"{world.player_name}\" cannot have reduced location checks with both"
|
||||||
|
f" panels mode door shuffle and color shuffle because there would not be enough"
|
||||||
|
f" locations for all of the items.")
|
||||||
|
if world.options.sunwarp_access >= SunwarpAccess.option_individual:
|
||||||
|
raise OptionError(f"Slot \"{world.player_name}\" cannot have reduced location checks with both"
|
||||||
|
f" panels mode door shuffle and individual or progressive sunwarp access because"
|
||||||
|
f" there would not be enough locations for all of the items.")
|
||||||
|
|
||||||
# Create door items, where needed.
|
# Create door items, where needed.
|
||||||
door_groups: Set[str] = set()
|
door_groups: Set[str] = set()
|
||||||
for room_name, room_data in DOORS_BY_ROOM.items():
|
for room_name, room_data in DOORS_BY_ROOM.items():
|
||||||
for door_name, door_data in room_data.items():
|
for door_name, door_data in room_data.items():
|
||||||
if door_data.skip_item is False and door_data.event is False:
|
if door_data.skip_item is False and door_data.event is False:
|
||||||
if door_data.type == DoorType.NORMAL and door_shuffle != ShuffleDoors.option_none:
|
if door_data.type == DoorType.NORMAL and door_shuffle == ShuffleDoors.option_doors:
|
||||||
if door_data.door_group is not None and door_shuffle == ShuffleDoors.option_simple:
|
if door_data.door_group is not None and world.options.group_doors:
|
||||||
# Grouped doors are handled differently if shuffle doors is on simple.
|
# Grouped doors are handled differently if shuffle doors is on simple.
|
||||||
self.set_door_item(room_name, door_name, door_data.door_group)
|
self.set_door_item(room_name, door_name, door_data.door_group)
|
||||||
door_groups.add(door_data.door_group)
|
door_groups.add(door_data.door_group)
|
||||||
|
@ -189,6 +212,28 @@ class LingoPlayerLogic:
|
||||||
|
|
||||||
self.real_items += door_groups
|
self.real_items += door_groups
|
||||||
|
|
||||||
|
# Create panel items, where needed.
|
||||||
|
if world.options.shuffle_doors == ShuffleDoors.option_panels:
|
||||||
|
panel_groups: Set[str] = set()
|
||||||
|
|
||||||
|
for room_name, room_data in PANEL_DOORS_BY_ROOM.items():
|
||||||
|
for panel_door_name, panel_door_data in room_data.items():
|
||||||
|
if panel_door_data.panel_group is not None and world.options.group_doors:
|
||||||
|
panel_groups.add(panel_door_data.panel_group)
|
||||||
|
elif room_name in PROGRESSIVE_PANELS_BY_ROOM \
|
||||||
|
and panel_door_name in PROGRESSIVE_PANELS_BY_ROOM[room_name]:
|
||||||
|
progression_obj = PROGRESSIVE_PANELS_BY_ROOM[room_name][panel_door_name]
|
||||||
|
progression_handling = should_split_progression(progression_obj.item_name, world)
|
||||||
|
|
||||||
|
if progression_handling == ProgressiveItemBehavior.SPLIT:
|
||||||
|
self.real_items.append(panel_door_data.item_name)
|
||||||
|
elif progression_handling == ProgressiveItemBehavior.PROGRESSIVE:
|
||||||
|
self.real_items.append(progression_obj.item_name)
|
||||||
|
else:
|
||||||
|
self.real_items.append(panel_door_data.item_name)
|
||||||
|
|
||||||
|
self.real_items += panel_groups
|
||||||
|
|
||||||
# Create color items, if needed.
|
# Create color items, if needed.
|
||||||
if color_shuffle:
|
if color_shuffle:
|
||||||
self.real_items += [name for name, item in ALL_ITEM_TABLE.items() if item.type == ItemType.COLOR]
|
self.real_items += [name for name, item in ALL_ITEM_TABLE.items() if item.type == ItemType.COLOR]
|
||||||
|
@ -244,7 +289,7 @@ class LingoPlayerLogic:
|
||||||
elif location_checks == LocationChecks.option_insanity:
|
elif location_checks == LocationChecks.option_insanity:
|
||||||
location_classification = LocationClassification.insanity
|
location_classification = LocationClassification.insanity
|
||||||
|
|
||||||
if door_shuffle != ShuffleDoors.option_none and not early_color_hallways:
|
if door_shuffle == ShuffleDoors.option_doors and not early_color_hallways:
|
||||||
location_classification |= LocationClassification.small_sphere_one
|
location_classification |= LocationClassification.small_sphere_one
|
||||||
|
|
||||||
for location_name, location_data in ALL_LOCATION_TABLE.items():
|
for location_name, location_data in ALL_LOCATION_TABLE.items():
|
||||||
|
@ -286,7 +331,7 @@ class LingoPlayerLogic:
|
||||||
"iterations. This is very unlikely to happen on its own, and probably indicates some "
|
"iterations. This is very unlikely to happen on its own, and probably indicates some "
|
||||||
"kind of logic error.")
|
"kind of logic error.")
|
||||||
|
|
||||||
if door_shuffle != ShuffleDoors.option_none and location_checks != LocationChecks.option_insanity \
|
if door_shuffle == ShuffleDoors.option_doors and location_checks != LocationChecks.option_insanity \
|
||||||
and not early_color_hallways and world.multiworld.players > 1:
|
and not early_color_hallways and world.multiworld.players > 1:
|
||||||
# Under the combination of door shuffle, normal location checks, and no early color hallways, sphere 1 is
|
# Under the combination of door shuffle, normal location checks, and no early color hallways, sphere 1 is
|
||||||
# only three checks. In a multiplayer situation, this can be frustrating for the player because they are
|
# only three checks. In a multiplayer situation, this can be frustrating for the player because they are
|
||||||
|
@ -301,19 +346,19 @@ class LingoPlayerLogic:
|
||||||
# Starting Room - Exit Door gives access to OPEN and TRACE.
|
# Starting Room - Exit Door gives access to OPEN and TRACE.
|
||||||
good_item_options: List[str] = ["Starting Room - Back Right Door", "Second Room - Exit Door"]
|
good_item_options: List[str] = ["Starting Room - Back Right Door", "Second Room - Exit Door"]
|
||||||
|
|
||||||
if not color_shuffle and not world.options.enable_pilgrimage:
|
|
||||||
# HOT CRUST and THIS.
|
|
||||||
good_item_options.append("Pilgrim Room - Sun Painting")
|
|
||||||
|
|
||||||
if not color_shuffle:
|
if not color_shuffle:
|
||||||
if door_shuffle == ShuffleDoors.option_simple:
|
if not world.options.enable_pilgrimage:
|
||||||
|
# HOT CRUST and THIS.
|
||||||
|
good_item_options.append("Pilgrim Room - Sun Painting")
|
||||||
|
|
||||||
|
if world.options.group_doors:
|
||||||
# WELCOME BACK, CLOCKWISE, and DRAWL + RUNS.
|
# WELCOME BACK, CLOCKWISE, and DRAWL + RUNS.
|
||||||
good_item_options.append("Welcome Back Doors")
|
good_item_options.append("Welcome Back Doors")
|
||||||
else:
|
else:
|
||||||
# WELCOME BACK and CLOCKWISE.
|
# WELCOME BACK and CLOCKWISE.
|
||||||
good_item_options.append("Welcome Back Area - Shortcut to Starting Room")
|
good_item_options.append("Welcome Back Area - Shortcut to Starting Room")
|
||||||
|
|
||||||
if door_shuffle == ShuffleDoors.option_simple:
|
if world.options.group_doors:
|
||||||
# Color hallways access (NOTE: reconsider when sunwarp shuffling exists).
|
# Color hallways access (NOTE: reconsider when sunwarp shuffling exists).
|
||||||
good_item_options.append("Rhyme Room Doors")
|
good_item_options.append("Rhyme Room Doors")
|
||||||
|
|
||||||
|
@ -359,13 +404,11 @@ class LingoPlayerLogic:
|
||||||
def randomize_paintings(self, world: "LingoWorld") -> bool:
|
def randomize_paintings(self, world: "LingoWorld") -> bool:
|
||||||
self.painting_mapping.clear()
|
self.painting_mapping.clear()
|
||||||
|
|
||||||
door_shuffle = world.options.shuffle_doors
|
|
||||||
|
|
||||||
# First, assign mappings to the required-exit paintings. We ensure that req-blocked paintings do not lead to
|
# First, assign mappings to the required-exit paintings. We ensure that req-blocked paintings do not lead to
|
||||||
# required paintings.
|
# required paintings.
|
||||||
req_exits = []
|
req_exits = []
|
||||||
required_painting_rooms = REQUIRED_PAINTING_ROOMS
|
required_painting_rooms = REQUIRED_PAINTING_ROOMS
|
||||||
if door_shuffle == ShuffleDoors.option_none:
|
if world.options.shuffle_doors != ShuffleDoors.option_doors:
|
||||||
required_painting_rooms += REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS
|
required_painting_rooms += REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS
|
||||||
req_exits = [painting_id for painting_id, painting in PAINTINGS.items() if painting.required_when_no_doors]
|
req_exits = [painting_id for painting_id, painting in PAINTINGS.items() if painting.required_when_no_doors]
|
||||||
|
|
||||||
|
@ -432,7 +475,7 @@ class LingoPlayerLogic:
|
||||||
for painting_id, painting in PAINTINGS.items():
|
for painting_id, painting in PAINTINGS.items():
|
||||||
if painting_id not in self.painting_mapping.values() \
|
if painting_id not in self.painting_mapping.values() \
|
||||||
and (painting.required or (painting.required_when_no_doors and
|
and (painting.required or (painting.required_when_no_doors and
|
||||||
door_shuffle == ShuffleDoors.option_none)):
|
world.options.shuffle_doors != ShuffleDoors.option_doors)):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -447,12 +490,31 @@ class LingoPlayerLogic:
|
||||||
access_reqs = AccessRequirements()
|
access_reqs = AccessRequirements()
|
||||||
panel_object = PANELS_BY_ROOM[room][panel]
|
panel_object = PANELS_BY_ROOM[room][panel]
|
||||||
|
|
||||||
|
if world.options.shuffle_doors == ShuffleDoors.option_panels and panel_object.panel_door is not None:
|
||||||
|
panel_door_room = panel_object.panel_door.room
|
||||||
|
panel_door_name = panel_object.panel_door.panel_door
|
||||||
|
panel_door = PANEL_DOORS_BY_ROOM[panel_door_room][panel_door_name]
|
||||||
|
|
||||||
|
if panel_door.panel_group is not None and world.options.group_doors:
|
||||||
|
access_reqs.items.add(panel_door.panel_group)
|
||||||
|
elif panel_door_room in PROGRESSIVE_PANELS_BY_ROOM\
|
||||||
|
and panel_door_name in PROGRESSIVE_PANELS_BY_ROOM[panel_door_room]:
|
||||||
|
progression_obj = PROGRESSIVE_PANELS_BY_ROOM[panel_door_room][panel_door_name]
|
||||||
|
progression_handling = should_split_progression(progression_obj.item_name, world)
|
||||||
|
|
||||||
|
if progression_handling == ProgressiveItemBehavior.SPLIT:
|
||||||
|
access_reqs.items.add(panel_door.item_name)
|
||||||
|
elif progression_handling == ProgressiveItemBehavior.PROGRESSIVE:
|
||||||
|
access_reqs.progression[progression_obj.item_name] = progression_obj.index
|
||||||
|
else:
|
||||||
|
access_reqs.items.add(panel_door.item_name)
|
||||||
|
|
||||||
for req_room in panel_object.required_rooms:
|
for req_room in panel_object.required_rooms:
|
||||||
access_reqs.rooms.add(req_room)
|
access_reqs.rooms.add(req_room)
|
||||||
|
|
||||||
for req_door in panel_object.required_doors:
|
for req_door in panel_object.required_doors:
|
||||||
door_object = DOORS_BY_ROOM[room if req_door.room is None else req_door.room][req_door.door]
|
door_object = DOORS_BY_ROOM[room if req_door.room is None else req_door.room][req_door.door]
|
||||||
if door_object.event or world.options.shuffle_doors == ShuffleDoors.option_none:
|
if door_object.event or world.options.shuffle_doors != ShuffleDoors.option_doors:
|
||||||
sub_access_reqs = self.calculate_door_requirements(
|
sub_access_reqs = self.calculate_door_requirements(
|
||||||
room if req_door.room is None else req_door.room, req_door.door, world)
|
room if req_door.room is None else req_door.room, req_door.door, world)
|
||||||
access_reqs.merge(sub_access_reqs)
|
access_reqs.merge(sub_access_reqs)
|
||||||
|
@ -522,11 +584,14 @@ class LingoPlayerLogic:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# We won't coalesce any panels that have requirements beyond colors. To simplify things for now, we will
|
# We won't coalesce any panels that have requirements beyond colors. To simplify things for now, we will
|
||||||
# only coalesce single-color panels. Chains/stacks/combo puzzles will be separate. THE MASTER has
|
# only coalesce single-color panels. Chains/stacks/combo puzzles will be separate. Panel door locked
|
||||||
# special access rules and is handled separately.
|
# puzzles will be separate if panels mode is on. THE MASTER has special access rules and is handled
|
||||||
|
# separately.
|
||||||
if len(panel_data.required_panels) > 0 or len(panel_data.required_doors) > 0\
|
if len(panel_data.required_panels) > 0 or len(panel_data.required_doors) > 0\
|
||||||
or len(panel_data.required_rooms) > 0\
|
or len(panel_data.required_rooms) > 0\
|
||||||
or (world.options.shuffle_colors and len(panel_data.colors) > 1)\
|
or (world.options.shuffle_colors and len(panel_data.colors) > 1)\
|
||||||
|
or (world.options.shuffle_doors == ShuffleDoors.option_panels
|
||||||
|
and panel_data.panel_door is not None)\
|
||||||
or panel_name == "THE MASTER":
|
or panel_name == "THE MASTER":
|
||||||
self.counting_panel_reqs.setdefault(room_name, []).append(
|
self.counting_panel_reqs.setdefault(room_name, []).append(
|
||||||
(self.calculate_panel_requirements(room_name, panel_name, world), 1))
|
(self.calculate_panel_requirements(room_name, panel_name, world), 1))
|
||||||
|
|
|
@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
|
||||||
from BaseClasses import CollectionState
|
from BaseClasses import CollectionState
|
||||||
from .datatypes import RoomAndDoor
|
from .datatypes import RoomAndDoor
|
||||||
from .player_logic import AccessRequirements, PlayerLocation
|
from .player_logic import AccessRequirements, PlayerLocation
|
||||||
from .static_logic import PROGRESSION_BY_ROOM, PROGRESSIVE_ITEMS
|
from .static_logic import PROGRESSIVE_DOORS_BY_ROOM, PROGRESSIVE_ITEMS
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from . import LingoWorld
|
from . import LingoWorld
|
||||||
|
@ -59,6 +59,12 @@ def _lingo_can_satisfy_requirements(state: CollectionState, access: AccessRequir
|
||||||
if not state.has(color.capitalize(), world.player):
|
if not state.has(color.capitalize(), world.player):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if not all(state.has(item, world.player) for item in access.items):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not all(state.has(item, world.player, index) for item, index in access.progression.items()):
|
||||||
|
return False
|
||||||
|
|
||||||
if access.the_master and not lingo_can_use_mastery_location(state, world):
|
if access.the_master and not lingo_can_use_mastery_location(state, world):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -77,7 +83,7 @@ def _lingo_can_open_door(state: CollectionState, room: str, door: str, world: "L
|
||||||
|
|
||||||
item_name = world.player_logic.item_by_door[room][door]
|
item_name = world.player_logic.item_by_door[room][door]
|
||||||
if item_name in PROGRESSIVE_ITEMS:
|
if item_name in PROGRESSIVE_ITEMS:
|
||||||
progression = PROGRESSION_BY_ROOM[room][door]
|
progression = PROGRESSIVE_DOORS_BY_ROOM[room][door]
|
||||||
return state.has(item_name, world.player, progression.index)
|
return state.has(item_name, world.player, progression.index)
|
||||||
|
|
||||||
return state.has(item_name, world.player)
|
return state.has(item_name, world.player)
|
||||||
|
|
|
@ -4,15 +4,17 @@ import pickle
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import Dict, List, Set
|
from typing import Dict, List, Set
|
||||||
|
|
||||||
from .datatypes import Door, Painting, Panel, Progression, Room
|
from .datatypes import Door, Painting, Panel, PanelDoor, Progression, Room
|
||||||
|
|
||||||
ALL_ROOMS: List[Room] = []
|
ALL_ROOMS: List[Room] = []
|
||||||
DOORS_BY_ROOM: Dict[str, Dict[str, Door]] = {}
|
DOORS_BY_ROOM: Dict[str, Dict[str, Door]] = {}
|
||||||
PANELS_BY_ROOM: Dict[str, Dict[str, Panel]] = {}
|
PANELS_BY_ROOM: Dict[str, Dict[str, Panel]] = {}
|
||||||
|
PANEL_DOORS_BY_ROOM: Dict[str, Dict[str, PanelDoor]] = {}
|
||||||
PAINTINGS: Dict[str, Painting] = {}
|
PAINTINGS: Dict[str, Painting] = {}
|
||||||
|
|
||||||
PROGRESSIVE_ITEMS: List[str] = []
|
PROGRESSIVE_ITEMS: Set[str] = set()
|
||||||
PROGRESSION_BY_ROOM: Dict[str, Dict[str, Progression]] = {}
|
PROGRESSIVE_DOORS_BY_ROOM: Dict[str, Dict[str, Progression]] = {}
|
||||||
|
PROGRESSIVE_PANELS_BY_ROOM: Dict[str, Dict[str, Progression]] = {}
|
||||||
|
|
||||||
PAINTING_ENTRANCES: int = 0
|
PAINTING_ENTRANCES: int = 0
|
||||||
PAINTING_EXIT_ROOMS: Set[str] = set()
|
PAINTING_EXIT_ROOMS: Set[str] = set()
|
||||||
|
@ -28,6 +30,8 @@ PANEL_LOCATION_IDS: Dict[str, Dict[str, int]] = {}
|
||||||
DOOR_LOCATION_IDS: Dict[str, Dict[str, int]] = {}
|
DOOR_LOCATION_IDS: Dict[str, Dict[str, int]] = {}
|
||||||
DOOR_ITEM_IDS: Dict[str, Dict[str, int]] = {}
|
DOOR_ITEM_IDS: Dict[str, Dict[str, int]] = {}
|
||||||
DOOR_GROUP_ITEM_IDS: Dict[str, int] = {}
|
DOOR_GROUP_ITEM_IDS: Dict[str, int] = {}
|
||||||
|
PANEL_DOOR_ITEM_IDS: Dict[str, Dict[str, int]] = {}
|
||||||
|
PANEL_GROUP_ITEM_IDS: Dict[str, int] = {}
|
||||||
PROGRESSIVE_ITEM_IDS: Dict[str, int] = {}
|
PROGRESSIVE_ITEM_IDS: Dict[str, int] = {}
|
||||||
|
|
||||||
HASHES: Dict[str, str] = {}
|
HASHES: Dict[str, str] = {}
|
||||||
|
@ -68,6 +72,20 @@ def get_door_group_item_id(name: str):
|
||||||
return DOOR_GROUP_ITEM_IDS[name]
|
return DOOR_GROUP_ITEM_IDS[name]
|
||||||
|
|
||||||
|
|
||||||
|
def get_panel_door_item_id(room: str, name: str):
|
||||||
|
if room not in PANEL_DOOR_ITEM_IDS or name not in PANEL_DOOR_ITEM_IDS[room]:
|
||||||
|
raise Exception(f"Item ID for panel door {room} - {name} not found in ids.yaml.")
|
||||||
|
|
||||||
|
return PANEL_DOOR_ITEM_IDS[room][name]
|
||||||
|
|
||||||
|
|
||||||
|
def get_panel_group_item_id(name: str):
|
||||||
|
if name not in PANEL_GROUP_ITEM_IDS:
|
||||||
|
raise Exception(f"Item ID for panel group {name} not found in ids.yaml.")
|
||||||
|
|
||||||
|
return PANEL_GROUP_ITEM_IDS[name]
|
||||||
|
|
||||||
|
|
||||||
def get_progressive_item_id(name: str):
|
def get_progressive_item_id(name: str):
|
||||||
if name not in PROGRESSIVE_ITEM_IDS:
|
if name not in PROGRESSIVE_ITEM_IDS:
|
||||||
raise Exception(f"Item ID for progressive item {name} not found in ids.yaml.")
|
raise Exception(f"Item ID for progressive item {name} not found in ids.yaml.")
|
||||||
|
@ -97,8 +115,10 @@ def load_static_data_from_file():
|
||||||
ALL_ROOMS.extend(pickdata["ALL_ROOMS"])
|
ALL_ROOMS.extend(pickdata["ALL_ROOMS"])
|
||||||
DOORS_BY_ROOM.update(pickdata["DOORS_BY_ROOM"])
|
DOORS_BY_ROOM.update(pickdata["DOORS_BY_ROOM"])
|
||||||
PANELS_BY_ROOM.update(pickdata["PANELS_BY_ROOM"])
|
PANELS_BY_ROOM.update(pickdata["PANELS_BY_ROOM"])
|
||||||
PROGRESSIVE_ITEMS.extend(pickdata["PROGRESSIVE_ITEMS"])
|
PANEL_DOORS_BY_ROOM.update(pickdata["PANEL_DOORS_BY_ROOM"])
|
||||||
PROGRESSION_BY_ROOM.update(pickdata["PROGRESSION_BY_ROOM"])
|
PROGRESSIVE_ITEMS.update(pickdata["PROGRESSIVE_ITEMS"])
|
||||||
|
PROGRESSIVE_DOORS_BY_ROOM.update(pickdata["PROGRESSIVE_DOORS_BY_ROOM"])
|
||||||
|
PROGRESSIVE_PANELS_BY_ROOM.update(pickdata["PROGRESSIVE_PANELS_BY_ROOM"])
|
||||||
PAINTING_ENTRANCES = pickdata["PAINTING_ENTRANCES"]
|
PAINTING_ENTRANCES = pickdata["PAINTING_ENTRANCES"]
|
||||||
PAINTING_EXIT_ROOMS.update(pickdata["PAINTING_EXIT_ROOMS"])
|
PAINTING_EXIT_ROOMS.update(pickdata["PAINTING_EXIT_ROOMS"])
|
||||||
PAINTING_EXITS = pickdata["PAINTING_EXITS"]
|
PAINTING_EXITS = pickdata["PAINTING_EXITS"]
|
||||||
|
@ -111,6 +131,8 @@ def load_static_data_from_file():
|
||||||
DOOR_LOCATION_IDS.update(pickdata["DOOR_LOCATION_IDS"])
|
DOOR_LOCATION_IDS.update(pickdata["DOOR_LOCATION_IDS"])
|
||||||
DOOR_ITEM_IDS.update(pickdata["DOOR_ITEM_IDS"])
|
DOOR_ITEM_IDS.update(pickdata["DOOR_ITEM_IDS"])
|
||||||
DOOR_GROUP_ITEM_IDS.update(pickdata["DOOR_GROUP_ITEM_IDS"])
|
DOOR_GROUP_ITEM_IDS.update(pickdata["DOOR_GROUP_ITEM_IDS"])
|
||||||
|
PANEL_DOOR_ITEM_IDS.update(pickdata["PANEL_DOOR_ITEM_IDS"])
|
||||||
|
PANEL_GROUP_ITEM_IDS.update(pickdata["PANEL_GROUP_ITEM_IDS"])
|
||||||
PROGRESSIVE_ITEM_IDS.update(pickdata["PROGRESSIVE_ITEM_IDS"])
|
PROGRESSIVE_ITEM_IDS.update(pickdata["PROGRESSIVE_ITEM_IDS"])
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ from . import LingoTestBase
|
||||||
|
|
||||||
class TestRequiredRoomLogic(LingoTestBase):
|
class TestRequiredRoomLogic(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
"shuffle_colors": "false",
|
"shuffle_colors": "false",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ class TestRequiredRoomLogic(LingoTestBase):
|
||||||
|
|
||||||
class TestRequiredDoorLogic(LingoTestBase):
|
class TestRequiredDoorLogic(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
"shuffle_colors": "false",
|
"shuffle_colors": "false",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +78,8 @@ class TestRequiredDoorLogic(LingoTestBase):
|
||||||
|
|
||||||
class TestSimpleDoors(LingoTestBase):
|
class TestSimpleDoors(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "simple",
|
"shuffle_doors": "doors",
|
||||||
|
"group_doors": "true",
|
||||||
"shuffle_colors": "false",
|
"shuffle_colors": "false",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,3 +91,52 @@ class TestSimpleDoors(LingoTestBase):
|
||||||
self.assertTrue(self.multiworld.state.can_reach("Outside The Wanderer", "Region", self.player))
|
self.assertTrue(self.multiworld.state.can_reach("Outside The Wanderer", "Region", self.player))
|
||||||
self.assertTrue(self.multiworld.state.can_reach("Orange Tower Third Floor", "Region", self.player))
|
self.assertTrue(self.multiworld.state.can_reach("Orange Tower Third Floor", "Region", self.player))
|
||||||
|
|
||||||
|
|
||||||
|
class TestPanels(LingoTestBase):
|
||||||
|
options = {
|
||||||
|
"shuffle_doors": "panels"
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_requirement(self):
|
||||||
|
self.assertFalse(self.can_reach_location("Starting Room - HIDDEN"))
|
||||||
|
self.assertFalse(self.can_reach_location("Hidden Room - OPEN"))
|
||||||
|
self.assertFalse(self.can_reach_location("The Seeker - Achievement"))
|
||||||
|
|
||||||
|
self.collect_by_name("Starting Room - HIDDEN (Panel)")
|
||||||
|
self.assertTrue(self.can_reach_location("Starting Room - HIDDEN"))
|
||||||
|
self.assertFalse(self.can_reach_location("Hidden Room - OPEN"))
|
||||||
|
self.assertFalse(self.can_reach_location("The Seeker - Achievement"))
|
||||||
|
|
||||||
|
self.collect_by_name("Hidden Room - OPEN (Panel)")
|
||||||
|
self.assertTrue(self.can_reach_location("Starting Room - HIDDEN"))
|
||||||
|
self.assertTrue(self.can_reach_location("Hidden Room - OPEN"))
|
||||||
|
self.assertTrue(self.can_reach_location("The Seeker - Achievement"))
|
||||||
|
|
||||||
|
|
||||||
|
class TestGroupedPanels(LingoTestBase):
|
||||||
|
options = {
|
||||||
|
"shuffle_doors": "panels",
|
||||||
|
"group_doors": "true",
|
||||||
|
"shuffle_colors": "false",
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_requirement(self):
|
||||||
|
self.assertFalse(self.can_reach_location("Hub Room - SLAUGHTER"))
|
||||||
|
self.assertFalse(self.can_reach_location("Dread Hallway - DREAD"))
|
||||||
|
self.assertFalse(self.can_reach_location("The Tenacious - Achievement"))
|
||||||
|
|
||||||
|
self.collect_by_name("Tenacious Entrance Panels")
|
||||||
|
self.assertTrue(self.can_reach_location("Hub Room - SLAUGHTER"))
|
||||||
|
self.assertFalse(self.can_reach_location("Dread Hallway - DREAD"))
|
||||||
|
self.assertFalse(self.can_reach_location("The Tenacious - Achievement"))
|
||||||
|
|
||||||
|
self.collect_by_name("Outside The Agreeable - BLACK (Panel)")
|
||||||
|
self.assertTrue(self.can_reach_location("Hub Room - SLAUGHTER"))
|
||||||
|
self.assertTrue(self.can_reach_location("Dread Hallway - DREAD"))
|
||||||
|
self.assertFalse(self.can_reach_location("The Tenacious - Achievement"))
|
||||||
|
|
||||||
|
self.collect_by_name("The Tenacious - Black Palindromes (Panels)")
|
||||||
|
self.assertTrue(self.can_reach_location("Hub Room - SLAUGHTER"))
|
||||||
|
self.assertTrue(self.can_reach_location("Dread Hallway - DREAD"))
|
||||||
|
self.assertTrue(self.can_reach_location("The Tenacious - Achievement"))
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ from . import LingoTestBase
|
||||||
|
|
||||||
class TestMultiShuffleOptions(LingoTestBase):
|
class TestMultiShuffleOptions(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
"progressive_orange_tower": "true",
|
"progressive_orange_tower": "true",
|
||||||
"shuffle_colors": "true",
|
"shuffle_colors": "true",
|
||||||
"shuffle_paintings": "true",
|
"shuffle_paintings": "true",
|
||||||
|
@ -13,7 +13,7 @@ class TestMultiShuffleOptions(LingoTestBase):
|
||||||
|
|
||||||
class TestPanelsanity(LingoTestBase):
|
class TestPanelsanity(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
"progressive_orange_tower": "true",
|
"progressive_orange_tower": "true",
|
||||||
"location_checks": "insanity",
|
"location_checks": "insanity",
|
||||||
"shuffle_colors": "true"
|
"shuffle_colors": "true"
|
||||||
|
@ -22,7 +22,18 @@ class TestPanelsanity(LingoTestBase):
|
||||||
|
|
||||||
class TestAllPanelHunt(LingoTestBase):
|
class TestAllPanelHunt(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
|
"progressive_orange_tower": "true",
|
||||||
|
"shuffle_colors": "true",
|
||||||
|
"victory_condition": "level_2",
|
||||||
|
"level_2_requirement": "800",
|
||||||
|
"early_color_hallways": "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TestAllPanelHuntPanelsMode(LingoTestBase):
|
||||||
|
options = {
|
||||||
|
"shuffle_doors": "panels",
|
||||||
"progressive_orange_tower": "true",
|
"progressive_orange_tower": "true",
|
||||||
"shuffle_colors": "true",
|
"shuffle_colors": "true",
|
||||||
"victory_condition": "level_2",
|
"victory_condition": "level_2",
|
||||||
|
|
|
@ -3,7 +3,7 @@ from . import LingoTestBase
|
||||||
|
|
||||||
class TestProgressiveOrangeTower(LingoTestBase):
|
class TestProgressiveOrangeTower(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
"progressive_orange_tower": "true"
|
"progressive_orange_tower": "true"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ from . import LingoTestBase
|
||||||
|
|
||||||
class TestPanelHunt(LingoTestBase):
|
class TestPanelHunt(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
"location_checks": "insanity",
|
"location_checks": "insanity",
|
||||||
"victory_condition": "level_2",
|
"victory_condition": "level_2",
|
||||||
"level_2_requirement": "15"
|
"level_2_requirement": "15"
|
||||||
|
|
|
@ -18,7 +18,7 @@ class TestPilgrimageWithRoofAndPaintings(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"enable_pilgrimage": "true",
|
"enable_pilgrimage": "true",
|
||||||
"shuffle_colors": "false",
|
"shuffle_colors": "false",
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
"pilgrimage_allows_roof_access": "true",
|
"pilgrimage_allows_roof_access": "true",
|
||||||
"pilgrimage_allows_paintings": "true",
|
"pilgrimage_allows_paintings": "true",
|
||||||
"early_color_hallways": "false"
|
"early_color_hallways": "false"
|
||||||
|
@ -39,7 +39,7 @@ class TestPilgrimageNoRoofYesPaintings(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"enable_pilgrimage": "true",
|
"enable_pilgrimage": "true",
|
||||||
"shuffle_colors": "false",
|
"shuffle_colors": "false",
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
"pilgrimage_allows_roof_access": "false",
|
"pilgrimage_allows_roof_access": "false",
|
||||||
"pilgrimage_allows_paintings": "true",
|
"pilgrimage_allows_paintings": "true",
|
||||||
"early_color_hallways": "false"
|
"early_color_hallways": "false"
|
||||||
|
@ -62,7 +62,7 @@ class TestPilgrimageNoRoofNoPaintings(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"enable_pilgrimage": "true",
|
"enable_pilgrimage": "true",
|
||||||
"shuffle_colors": "false",
|
"shuffle_colors": "false",
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
"pilgrimage_allows_roof_access": "false",
|
"pilgrimage_allows_roof_access": "false",
|
||||||
"pilgrimage_allows_paintings": "false",
|
"pilgrimage_allows_paintings": "false",
|
||||||
"early_color_hallways": "false"
|
"early_color_hallways": "false"
|
||||||
|
@ -117,7 +117,7 @@ class TestPilgrimageYesRoofNoPaintings(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"enable_pilgrimage": "true",
|
"enable_pilgrimage": "true",
|
||||||
"shuffle_colors": "false",
|
"shuffle_colors": "false",
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
"pilgrimage_allows_roof_access": "true",
|
"pilgrimage_allows_roof_access": "true",
|
||||||
"pilgrimage_allows_paintings": "false",
|
"pilgrimage_allows_paintings": "false",
|
||||||
"early_color_hallways": "false"
|
"early_color_hallways": "false"
|
||||||
|
|
|
@ -3,7 +3,7 @@ from . import LingoTestBase
|
||||||
|
|
||||||
class TestComplexProgressiveHallwayRoom(LingoTestBase):
|
class TestComplexProgressiveHallwayRoom(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "complex"
|
"shuffle_doors": "doors"
|
||||||
}
|
}
|
||||||
|
|
||||||
def test_item(self):
|
def test_item(self):
|
||||||
|
@ -54,7 +54,8 @@ class TestComplexProgressiveHallwayRoom(LingoTestBase):
|
||||||
|
|
||||||
class TestSimpleHallwayRoom(LingoTestBase):
|
class TestSimpleHallwayRoom(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "simple"
|
"shuffle_doors": "doors",
|
||||||
|
"group_doors": "true",
|
||||||
}
|
}
|
||||||
|
|
||||||
def test_item(self):
|
def test_item(self):
|
||||||
|
@ -81,7 +82,7 @@ class TestSimpleHallwayRoom(LingoTestBase):
|
||||||
|
|
||||||
class TestProgressiveArtGallery(LingoTestBase):
|
class TestProgressiveArtGallery(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
"shuffle_colors": "false",
|
"shuffle_colors": "false",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,8 @@ class TestVanillaDoorsNormalSunwarps(LingoTestBase):
|
||||||
|
|
||||||
class TestSimpleDoorsNormalSunwarps(LingoTestBase):
|
class TestSimpleDoorsNormalSunwarps(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "simple",
|
"shuffle_doors": "doors",
|
||||||
|
"group_doors": "true",
|
||||||
"sunwarp_access": "normal"
|
"sunwarp_access": "normal"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +38,8 @@ class TestSimpleDoorsNormalSunwarps(LingoTestBase):
|
||||||
|
|
||||||
class TestSimpleDoorsDisabledSunwarps(LingoTestBase):
|
class TestSimpleDoorsDisabledSunwarps(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "simple",
|
"shuffle_doors": "doors",
|
||||||
|
"group_doors": "true",
|
||||||
"sunwarp_access": "disabled"
|
"sunwarp_access": "disabled"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,7 +58,8 @@ class TestSimpleDoorsDisabledSunwarps(LingoTestBase):
|
||||||
|
|
||||||
class TestSimpleDoorsUnlockSunwarps(LingoTestBase):
|
class TestSimpleDoorsUnlockSunwarps(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "simple",
|
"shuffle_doors": "doors",
|
||||||
|
"group_doors": "true",
|
||||||
"sunwarp_access": "unlock"
|
"sunwarp_access": "unlock"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +81,8 @@ class TestSimpleDoorsUnlockSunwarps(LingoTestBase):
|
||||||
|
|
||||||
class TestComplexDoorsNormalSunwarps(LingoTestBase):
|
class TestComplexDoorsNormalSunwarps(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
|
"group_doors": "false",
|
||||||
"sunwarp_access": "normal"
|
"sunwarp_access": "normal"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +100,8 @@ class TestComplexDoorsNormalSunwarps(LingoTestBase):
|
||||||
|
|
||||||
class TestComplexDoorsDisabledSunwarps(LingoTestBase):
|
class TestComplexDoorsDisabledSunwarps(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
|
"group_doors": "false",
|
||||||
"sunwarp_access": "disabled"
|
"sunwarp_access": "disabled"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +120,8 @@ class TestComplexDoorsDisabledSunwarps(LingoTestBase):
|
||||||
|
|
||||||
class TestComplexDoorsIndividualSunwarps(LingoTestBase):
|
class TestComplexDoorsIndividualSunwarps(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
|
"group_doors": "false",
|
||||||
"sunwarp_access": "individual"
|
"sunwarp_access": "individual"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +148,8 @@ class TestComplexDoorsIndividualSunwarps(LingoTestBase):
|
||||||
|
|
||||||
class TestComplexDoorsProgressiveSunwarps(LingoTestBase):
|
class TestComplexDoorsProgressiveSunwarps(LingoTestBase):
|
||||||
options = {
|
options = {
|
||||||
"shuffle_doors": "complex",
|
"shuffle_doors": "doors",
|
||||||
|
"group_doors": "false",
|
||||||
"sunwarp_access": "progressive"
|
"sunwarp_access": "progressive"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,22 @@ if old_generated.include? "door_groups" then
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if old_generated.include? "panel_doors" then
|
||||||
|
old_generated["panel_doors"].each do |room, panel_doors|
|
||||||
|
panel_doors.each do |name, id|
|
||||||
|
if id >= next_item_id then
|
||||||
|
next_item_id = id + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if old_generated.include? "panel_groups" then
|
||||||
|
old_generated["panel_groups"].each do |name, id|
|
||||||
|
if id >= next_item_id then
|
||||||
|
next_item_id = id + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
if old_generated.include? "progression" then
|
if old_generated.include? "progression" then
|
||||||
old_generated["progression"].each do |name, id|
|
old_generated["progression"].each do |name, id|
|
||||||
if id >= next_item_id then
|
if id >= next_item_id then
|
||||||
|
@ -82,6 +98,7 @@ if old_generated.include? "progression" then
|
||||||
end
|
end
|
||||||
|
|
||||||
door_groups = Set[]
|
door_groups = Set[]
|
||||||
|
panel_groups = Set[]
|
||||||
|
|
||||||
config = YAML.load_file(configpath)
|
config = YAML.load_file(configpath)
|
||||||
config.each do |room_name, room_data|
|
config.each do |room_name, room_data|
|
||||||
|
@ -163,6 +180,29 @@ config.each do |room_name, room_data|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if room_data.include? "panel_doors"
|
||||||
|
room_data["panel_doors"].each do |panel_door_name, panel_door|
|
||||||
|
unless old_generated.include? "panel_doors" and old_generated["panel_doors"].include? room_name and old_generated["panel_doors"][room_name].include? panel_door_name then
|
||||||
|
old_generated["panel_doors"] ||= {}
|
||||||
|
old_generated["panel_doors"][room_name] ||= {}
|
||||||
|
old_generated["panel_doors"][room_name][panel_door_name] = next_item_id
|
||||||
|
|
||||||
|
next_item_id += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if panel_door.include? "panel_group" and not panel_groups.include? panel_door["panel_group"] then
|
||||||
|
panel_groups.add(panel_door["panel_group"])
|
||||||
|
|
||||||
|
unless old_generated.include? "panel_groups" and old_generated["panel_groups"].include? panel_door["panel_group"] then
|
||||||
|
old_generated["panel_groups"] ||= {}
|
||||||
|
old_generated["panel_groups"][panel_door["panel_group"]] = next_item_id
|
||||||
|
|
||||||
|
next_item_id += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if room_data.include? "progression"
|
if room_data.include? "progression"
|
||||||
room_data["progression"].each do |progression_name, pdata|
|
room_data["progression"].each do |progression_name, pdata|
|
||||||
unless old_generated.include? "progression" and old_generated["progression"].include? progression_name then
|
unless old_generated.include? "progression" and old_generated["progression"].include? progression_name then
|
||||||
|
|
|
@ -6,8 +6,8 @@ import sys
|
||||||
sys.path.append(os.path.join("worlds", "lingo"))
|
sys.path.append(os.path.join("worlds", "lingo"))
|
||||||
sys.path.append(".")
|
sys.path.append(".")
|
||||||
sys.path.append("..")
|
sys.path.append("..")
|
||||||
from datatypes import Door, DoorType, EntranceType, Painting, Panel, Progression, Room, RoomAndDoor, RoomAndPanel,\
|
from datatypes import Door, DoorType, EntranceType, Painting, Panel, PanelDoor, Progression, Room, RoomAndDoor,\
|
||||||
RoomEntrance
|
RoomAndPanel, RoomAndPanelDoor, RoomEntrance
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import pickle
|
import pickle
|
||||||
|
@ -18,10 +18,12 @@ import Utils
|
||||||
ALL_ROOMS: List[Room] = []
|
ALL_ROOMS: List[Room] = []
|
||||||
DOORS_BY_ROOM: Dict[str, Dict[str, Door]] = {}
|
DOORS_BY_ROOM: Dict[str, Dict[str, Door]] = {}
|
||||||
PANELS_BY_ROOM: Dict[str, Dict[str, Panel]] = {}
|
PANELS_BY_ROOM: Dict[str, Dict[str, Panel]] = {}
|
||||||
|
PANEL_DOORS_BY_ROOM: Dict[str, Dict[str, PanelDoor]] = {}
|
||||||
PAINTINGS: Dict[str, Painting] = {}
|
PAINTINGS: Dict[str, Painting] = {}
|
||||||
|
|
||||||
PROGRESSIVE_ITEMS: List[str] = []
|
PROGRESSIVE_ITEMS: Set[str] = set()
|
||||||
PROGRESSION_BY_ROOM: Dict[str, Dict[str, Progression]] = {}
|
PROGRESSIVE_DOORS_BY_ROOM: Dict[str, Dict[str, Progression]] = {}
|
||||||
|
PROGRESSIVE_PANELS_BY_ROOM: Dict[str, Dict[str, Progression]] = {}
|
||||||
|
|
||||||
PAINTING_ENTRANCES: int = 0
|
PAINTING_ENTRANCES: int = 0
|
||||||
PAINTING_EXIT_ROOMS: Set[str] = set()
|
PAINTING_EXIT_ROOMS: Set[str] = set()
|
||||||
|
@ -37,8 +39,13 @@ PANEL_LOCATION_IDS: Dict[str, Dict[str, int]] = {}
|
||||||
DOOR_LOCATION_IDS: Dict[str, Dict[str, int]] = {}
|
DOOR_LOCATION_IDS: Dict[str, Dict[str, int]] = {}
|
||||||
DOOR_ITEM_IDS: Dict[str, Dict[str, int]] = {}
|
DOOR_ITEM_IDS: Dict[str, Dict[str, int]] = {}
|
||||||
DOOR_GROUP_ITEM_IDS: Dict[str, int] = {}
|
DOOR_GROUP_ITEM_IDS: Dict[str, int] = {}
|
||||||
|
PANEL_DOOR_ITEM_IDS: Dict[str, Dict[str, int]] = {}
|
||||||
|
PANEL_GROUP_ITEM_IDS: Dict[str, int] = {}
|
||||||
PROGRESSIVE_ITEM_IDS: Dict[str, int] = {}
|
PROGRESSIVE_ITEM_IDS: Dict[str, int] = {}
|
||||||
|
|
||||||
|
# This doesn't need to be stored in the datafile.
|
||||||
|
PANEL_DOOR_BY_PANEL_BY_ROOM: Dict[str, Dict[str, str]] = {}
|
||||||
|
|
||||||
|
|
||||||
def hash_file(path):
|
def hash_file(path):
|
||||||
md5 = hashlib.md5()
|
md5 = hashlib.md5()
|
||||||
|
@ -53,7 +60,7 @@ def hash_file(path):
|
||||||
|
|
||||||
def load_static_data(ll1_path, ids_path):
|
def load_static_data(ll1_path, ids_path):
|
||||||
global PAINTING_EXITS, SPECIAL_ITEM_IDS, PANEL_LOCATION_IDS, DOOR_LOCATION_IDS, DOOR_ITEM_IDS, \
|
global PAINTING_EXITS, SPECIAL_ITEM_IDS, PANEL_LOCATION_IDS, DOOR_LOCATION_IDS, DOOR_ITEM_IDS, \
|
||||||
DOOR_GROUP_ITEM_IDS, PROGRESSIVE_ITEM_IDS
|
DOOR_GROUP_ITEM_IDS, PROGRESSIVE_ITEM_IDS, PANEL_DOOR_ITEM_IDS, PANEL_GROUP_ITEM_IDS
|
||||||
|
|
||||||
# Load in all item and location IDs. These are broken up into groups based on the type of item/location.
|
# Load in all item and location IDs. These are broken up into groups based on the type of item/location.
|
||||||
with open(ids_path, "r") as file:
|
with open(ids_path, "r") as file:
|
||||||
|
@ -86,6 +93,17 @@ def load_static_data(ll1_path, ids_path):
|
||||||
for item_name, item_id in config["door_groups"].items():
|
for item_name, item_id in config["door_groups"].items():
|
||||||
DOOR_GROUP_ITEM_IDS[item_name] = item_id
|
DOOR_GROUP_ITEM_IDS[item_name] = item_id
|
||||||
|
|
||||||
|
if "panel_doors" in config:
|
||||||
|
for room_name, panel_doors in config["panel_doors"].items():
|
||||||
|
PANEL_DOOR_ITEM_IDS[room_name] = {}
|
||||||
|
|
||||||
|
for panel_door, item_id in panel_doors.items():
|
||||||
|
PANEL_DOOR_ITEM_IDS[room_name][panel_door] = item_id
|
||||||
|
|
||||||
|
if "panel_groups" in config:
|
||||||
|
for item_name, item_id in config["panel_groups"].items():
|
||||||
|
PANEL_GROUP_ITEM_IDS[item_name] = item_id
|
||||||
|
|
||||||
if "progression" in config:
|
if "progression" in config:
|
||||||
for item_name, item_id in config["progression"].items():
|
for item_name, item_id in config["progression"].items():
|
||||||
PROGRESSIVE_ITEM_IDS[item_name] = item_id
|
PROGRESSIVE_ITEM_IDS[item_name] = item_id
|
||||||
|
@ -147,6 +165,46 @@ def process_entrance(source_room, doors, room_obj):
|
||||||
room_obj.entrances.append(RoomEntrance(source_room, door, entrance_type))
|
room_obj.entrances.append(RoomEntrance(source_room, door, entrance_type))
|
||||||
|
|
||||||
|
|
||||||
|
def process_panel_door(room_name, panel_door_name, panel_door_data):
|
||||||
|
global PANEL_DOORS_BY_ROOM, PANEL_DOOR_BY_PANEL_BY_ROOM
|
||||||
|
|
||||||
|
panels: List[RoomAndPanel] = list()
|
||||||
|
for panel in panel_door_data["panels"]:
|
||||||
|
if isinstance(panel, dict):
|
||||||
|
panels.append(RoomAndPanel(panel["room"], panel["panel"]))
|
||||||
|
else:
|
||||||
|
panels.append(RoomAndPanel(room_name, panel))
|
||||||
|
|
||||||
|
for panel in panels:
|
||||||
|
PANEL_DOOR_BY_PANEL_BY_ROOM.setdefault(panel.room, {})[panel.panel] = RoomAndPanelDoor(room_name,
|
||||||
|
panel_door_name)
|
||||||
|
|
||||||
|
if "item_name" in panel_door_data:
|
||||||
|
item_name = panel_door_data["item_name"]
|
||||||
|
else:
|
||||||
|
panel_per_room = dict()
|
||||||
|
for panel in panels:
|
||||||
|
panel_room_name = room_name if panel.room is None else panel.room
|
||||||
|
panel_per_room.setdefault(panel_room_name, []).append(panel.panel)
|
||||||
|
|
||||||
|
room_strs = list()
|
||||||
|
for door_room_str, door_panels_str in panel_per_room.items():
|
||||||
|
room_strs.append(door_room_str + " - " + ", ".join(door_panels_str))
|
||||||
|
|
||||||
|
if len(panels) == 1:
|
||||||
|
item_name = f"{room_strs[0]} (Panel)"
|
||||||
|
else:
|
||||||
|
item_name = " and ".join(room_strs) + " (Panels)"
|
||||||
|
|
||||||
|
if "panel_group" in panel_door_data:
|
||||||
|
panel_group = panel_door_data["panel_group"]
|
||||||
|
else:
|
||||||
|
panel_group = None
|
||||||
|
|
||||||
|
panel_door_obj = PanelDoor(item_name, panel_group)
|
||||||
|
PANEL_DOORS_BY_ROOM[room_name][panel_door_name] = panel_door_obj
|
||||||
|
|
||||||
|
|
||||||
def process_panel(room_name, panel_name, panel_data):
|
def process_panel(room_name, panel_name, panel_data):
|
||||||
global PANELS_BY_ROOM
|
global PANELS_BY_ROOM
|
||||||
|
|
||||||
|
@ -227,13 +285,18 @@ def process_panel(room_name, panel_name, panel_data):
|
||||||
else:
|
else:
|
||||||
non_counting = False
|
non_counting = False
|
||||||
|
|
||||||
|
if room_name in PANEL_DOOR_BY_PANEL_BY_ROOM and panel_name in PANEL_DOOR_BY_PANEL_BY_ROOM[room_name]:
|
||||||
|
panel_door = PANEL_DOOR_BY_PANEL_BY_ROOM[room_name][panel_name]
|
||||||
|
else:
|
||||||
|
panel_door = None
|
||||||
|
|
||||||
if "location_name" in panel_data:
|
if "location_name" in panel_data:
|
||||||
location_name = panel_data["location_name"]
|
location_name = panel_data["location_name"]
|
||||||
else:
|
else:
|
||||||
location_name = None
|
location_name = None
|
||||||
|
|
||||||
panel_obj = Panel(required_rooms, required_doors, required_panels, colors, check, event, exclude_reduce,
|
panel_obj = Panel(required_rooms, required_doors, required_panels, colors, check, event, exclude_reduce,
|
||||||
achievement, non_counting, location_name)
|
achievement, non_counting, panel_door, location_name)
|
||||||
PANELS_BY_ROOM[room_name][panel_name] = panel_obj
|
PANELS_BY_ROOM[room_name][panel_name] = panel_obj
|
||||||
|
|
||||||
|
|
||||||
|
@ -325,7 +388,7 @@ def process_door(room_name, door_name, door_data):
|
||||||
painting_ids = []
|
painting_ids = []
|
||||||
|
|
||||||
door_type = DoorType.NORMAL
|
door_type = DoorType.NORMAL
|
||||||
if door_name.endswith(" Sunwarp"):
|
if room_name == "Sunwarps":
|
||||||
door_type = DoorType.SUNWARP
|
door_type = DoorType.SUNWARP
|
||||||
elif room_name == "Pilgrim Antechamber" and door_name == "Sun Painting":
|
elif room_name == "Pilgrim Antechamber" and door_name == "Sun Painting":
|
||||||
door_type = DoorType.SUN_PAINTING
|
door_type = DoorType.SUN_PAINTING
|
||||||
|
@ -404,11 +467,11 @@ def process_sunwarp(room_name, sunwarp_data):
|
||||||
SUNWARP_EXITS[sunwarp_data["dots"] - 1] = room_name
|
SUNWARP_EXITS[sunwarp_data["dots"] - 1] = room_name
|
||||||
|
|
||||||
|
|
||||||
def process_progression(room_name, progression_name, progression_doors):
|
def process_progressive_door(room_name, progression_name, progression_doors):
|
||||||
global PROGRESSIVE_ITEMS, PROGRESSION_BY_ROOM
|
global PROGRESSIVE_ITEMS, PROGRESSIVE_DOORS_BY_ROOM
|
||||||
|
|
||||||
# Progressive items are configured as a list of doors.
|
# Progressive items are configured as a list of doors.
|
||||||
PROGRESSIVE_ITEMS.append(progression_name)
|
PROGRESSIVE_ITEMS.add(progression_name)
|
||||||
|
|
||||||
progression_index = 1
|
progression_index = 1
|
||||||
for door in progression_doors:
|
for door in progression_doors:
|
||||||
|
@ -419,11 +482,31 @@ def process_progression(room_name, progression_name, progression_doors):
|
||||||
door_room = room_name
|
door_room = room_name
|
||||||
door_door = door
|
door_door = door
|
||||||
|
|
||||||
room_progressions = PROGRESSION_BY_ROOM.setdefault(door_room, {})
|
room_progressions = PROGRESSIVE_DOORS_BY_ROOM.setdefault(door_room, {})
|
||||||
room_progressions[door_door] = Progression(progression_name, progression_index)
|
room_progressions[door_door] = Progression(progression_name, progression_index)
|
||||||
progression_index += 1
|
progression_index += 1
|
||||||
|
|
||||||
|
|
||||||
|
def process_progressive_panel(room_name, progression_name, progression_panel_doors):
|
||||||
|
global PROGRESSIVE_ITEMS, PROGRESSIVE_PANELS_BY_ROOM
|
||||||
|
|
||||||
|
# Progressive items are configured as a list of panel doors.
|
||||||
|
PROGRESSIVE_ITEMS.add(progression_name)
|
||||||
|
|
||||||
|
progression_index = 1
|
||||||
|
for panel_door in progression_panel_doors:
|
||||||
|
if isinstance(panel_door, Dict):
|
||||||
|
panel_door_room = panel_door["room"]
|
||||||
|
panel_door_door = panel_door["panel_door"]
|
||||||
|
else:
|
||||||
|
panel_door_room = room_name
|
||||||
|
panel_door_door = panel_door
|
||||||
|
|
||||||
|
room_progressions = PROGRESSIVE_PANELS_BY_ROOM.setdefault(panel_door_room, {})
|
||||||
|
room_progressions[panel_door_door] = Progression(progression_name, progression_index)
|
||||||
|
progression_index += 1
|
||||||
|
|
||||||
|
|
||||||
def process_room(room_name, room_data):
|
def process_room(room_name, room_data):
|
||||||
global ALL_ROOMS
|
global ALL_ROOMS
|
||||||
|
|
||||||
|
@ -433,6 +516,12 @@ def process_room(room_name, room_data):
|
||||||
for source_room, doors in room_data["entrances"].items():
|
for source_room, doors in room_data["entrances"].items():
|
||||||
process_entrance(source_room, doors, room_obj)
|
process_entrance(source_room, doors, room_obj)
|
||||||
|
|
||||||
|
if "panel_doors" in room_data:
|
||||||
|
PANEL_DOORS_BY_ROOM[room_name] = dict()
|
||||||
|
|
||||||
|
for panel_door_name, panel_door_data in room_data["panel_doors"].items():
|
||||||
|
process_panel_door(room_name, panel_door_name, panel_door_data)
|
||||||
|
|
||||||
if "panels" in room_data:
|
if "panels" in room_data:
|
||||||
PANELS_BY_ROOM[room_name] = dict()
|
PANELS_BY_ROOM[room_name] = dict()
|
||||||
|
|
||||||
|
@ -454,8 +543,11 @@ def process_room(room_name, room_data):
|
||||||
process_sunwarp(room_name, sunwarp_data)
|
process_sunwarp(room_name, sunwarp_data)
|
||||||
|
|
||||||
if "progression" in room_data:
|
if "progression" in room_data:
|
||||||
for progression_name, progression_doors in room_data["progression"].items():
|
for progression_name, pdata in room_data["progression"].items():
|
||||||
process_progression(room_name, progression_name, progression_doors)
|
if "doors" in pdata:
|
||||||
|
process_progressive_door(room_name, progression_name, pdata["doors"])
|
||||||
|
if "panel_doors" in pdata:
|
||||||
|
process_progressive_panel(room_name, progression_name, pdata["panel_doors"])
|
||||||
|
|
||||||
ALL_ROOMS.append(room_obj)
|
ALL_ROOMS.append(room_obj)
|
||||||
|
|
||||||
|
@ -492,8 +584,10 @@ if __name__ == '__main__':
|
||||||
"ALL_ROOMS": ALL_ROOMS,
|
"ALL_ROOMS": ALL_ROOMS,
|
||||||
"DOORS_BY_ROOM": DOORS_BY_ROOM,
|
"DOORS_BY_ROOM": DOORS_BY_ROOM,
|
||||||
"PANELS_BY_ROOM": PANELS_BY_ROOM,
|
"PANELS_BY_ROOM": PANELS_BY_ROOM,
|
||||||
|
"PANEL_DOORS_BY_ROOM": PANEL_DOORS_BY_ROOM,
|
||||||
"PROGRESSIVE_ITEMS": PROGRESSIVE_ITEMS,
|
"PROGRESSIVE_ITEMS": PROGRESSIVE_ITEMS,
|
||||||
"PROGRESSION_BY_ROOM": PROGRESSION_BY_ROOM,
|
"PROGRESSIVE_DOORS_BY_ROOM": PROGRESSIVE_DOORS_BY_ROOM,
|
||||||
|
"PROGRESSIVE_PANELS_BY_ROOM": PROGRESSIVE_PANELS_BY_ROOM,
|
||||||
"PAINTING_ENTRANCES": PAINTING_ENTRANCES,
|
"PAINTING_ENTRANCES": PAINTING_ENTRANCES,
|
||||||
"PAINTING_EXIT_ROOMS": PAINTING_EXIT_ROOMS,
|
"PAINTING_EXIT_ROOMS": PAINTING_EXIT_ROOMS,
|
||||||
"PAINTING_EXITS": PAINTING_EXITS,
|
"PAINTING_EXITS": PAINTING_EXITS,
|
||||||
|
@ -506,6 +600,8 @@ if __name__ == '__main__':
|
||||||
"DOOR_LOCATION_IDS": DOOR_LOCATION_IDS,
|
"DOOR_LOCATION_IDS": DOOR_LOCATION_IDS,
|
||||||
"DOOR_ITEM_IDS": DOOR_ITEM_IDS,
|
"DOOR_ITEM_IDS": DOOR_ITEM_IDS,
|
||||||
"DOOR_GROUP_ITEM_IDS": DOOR_GROUP_ITEM_IDS,
|
"DOOR_GROUP_ITEM_IDS": DOOR_GROUP_ITEM_IDS,
|
||||||
|
"PANEL_DOOR_ITEM_IDS": PANEL_DOOR_ITEM_IDS,
|
||||||
|
"PANEL_GROUP_ITEM_IDS": PANEL_GROUP_ITEM_IDS,
|
||||||
"PROGRESSIVE_ITEM_IDS": PROGRESSIVE_ITEM_IDS,
|
"PROGRESSIVE_ITEM_IDS": PROGRESSIVE_ITEM_IDS,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,19 +33,23 @@ end
|
||||||
configured_rooms = Set["Menu"]
|
configured_rooms = Set["Menu"]
|
||||||
configured_doors = Set[]
|
configured_doors = Set[]
|
||||||
configured_panels = Set[]
|
configured_panels = Set[]
|
||||||
|
configured_panel_doors = Set[]
|
||||||
|
|
||||||
mentioned_rooms = Set[]
|
mentioned_rooms = Set[]
|
||||||
mentioned_doors = Set[]
|
mentioned_doors = Set[]
|
||||||
mentioned_panels = Set[]
|
mentioned_panels = Set[]
|
||||||
|
mentioned_panel_doors = Set[]
|
||||||
mentioned_sunwarp_entrances = Set[]
|
mentioned_sunwarp_entrances = Set[]
|
||||||
mentioned_sunwarp_exits = Set[]
|
mentioned_sunwarp_exits = Set[]
|
||||||
mentioned_paintings = Set[]
|
mentioned_paintings = Set[]
|
||||||
|
|
||||||
door_groups = {}
|
door_groups = {}
|
||||||
|
panel_groups = {}
|
||||||
|
|
||||||
directives = Set["entrances", "panels", "doors", "paintings", "sunwarps", "progression"]
|
directives = Set["entrances", "panels", "doors", "panel_doors", "paintings", "sunwarps", "progression"]
|
||||||
panel_directives = Set["id", "required_room", "required_door", "required_panel", "colors", "check", "exclude_reduce", "tag", "link", "subtag", "achievement", "copy_to_sign", "non_counting", "hunt", "location_name"]
|
panel_directives = Set["id", "required_room", "required_door", "required_panel", "colors", "check", "exclude_reduce", "tag", "link", "subtag", "achievement", "copy_to_sign", "non_counting", "hunt", "location_name"]
|
||||||
door_directives = Set["id", "painting_id", "panels", "item_name", "item_group", "location_name", "skip_location", "skip_item", "door_group", "include_reduce", "event", "warp_id"]
|
door_directives = Set["id", "painting_id", "panels", "item_name", "item_group", "location_name", "skip_location", "skip_item", "door_group", "include_reduce", "event", "warp_id"]
|
||||||
|
panel_door_directives = Set["panels", "item_name", "panel_group"]
|
||||||
painting_directives = Set["id", "enter_only", "exit_only", "orientation", "required_door", "required", "required_when_no_doors", "move", "req_blocked", "req_blocked_when_no_doors"]
|
painting_directives = Set["id", "enter_only", "exit_only", "orientation", "required_door", "required", "required_when_no_doors", "move", "req_blocked", "req_blocked_when_no_doors"]
|
||||||
|
|
||||||
non_counting = 0
|
non_counting = 0
|
||||||
|
@ -253,6 +257,43 @@ config.each do |room_name, room|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
(room["panel_doors"] || {}).each do |panel_door_name, panel_door|
|
||||||
|
configured_panel_doors.add("#{room_name} - #{panel_door_name}")
|
||||||
|
|
||||||
|
if panel_door.include?("panels")
|
||||||
|
panel_door["panels"].each do |panel|
|
||||||
|
if panel.kind_of? Hash then
|
||||||
|
other_room = panel.include?("room") ? panel["room"] : room_name
|
||||||
|
mentioned_panels.add("#{other_room} - #{panel["panel"]}")
|
||||||
|
else
|
||||||
|
other_room = panel.include?("room") ? panel["room"] : room_name
|
||||||
|
mentioned_panels.add("#{room_name} - #{panel}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
puts "#{room_name} - #{panel_door_name} :::: Missing panels field"
|
||||||
|
end
|
||||||
|
|
||||||
|
if panel_door.include?("panel_group")
|
||||||
|
panel_groups[panel_door["panel_group"]] ||= 0
|
||||||
|
panel_groups[panel_door["panel_group"]] += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
bad_subdirectives = []
|
||||||
|
panel_door.keys.each do |key|
|
||||||
|
unless panel_door_directives.include?(key) then
|
||||||
|
bad_subdirectives << key
|
||||||
|
end
|
||||||
|
end
|
||||||
|
unless bad_subdirectives.empty? then
|
||||||
|
puts "#{room_name} - #{panel_door_name} :::: Panel door has the following invalid subdirectives: #{bad_subdirectives.join(", ")}"
|
||||||
|
end
|
||||||
|
|
||||||
|
unless ids.include?("panel_doors") and ids["panel_doors"].include?(room_name) and ids["panel_doors"][room_name].include?(panel_door_name)
|
||||||
|
puts "#{room_name} - #{panel_door_name} :::: Panel door is missing an item ID"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
(room["paintings"] || []).each do |painting|
|
(room["paintings"] || []).each do |painting|
|
||||||
if painting.include?("id") and painting["id"].kind_of? String then
|
if painting.include?("id") and painting["id"].kind_of? String then
|
||||||
unless paintings.include? painting["id"] then
|
unless paintings.include? painting["id"] then
|
||||||
|
@ -327,12 +368,24 @@ config.each do |room_name, room|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
(room["progression"] || {}).each do |progression_name, door_list|
|
(room["progression"] || {}).each do |progression_name, pdata|
|
||||||
door_list.each do |door|
|
if pdata.include? "doors" then
|
||||||
if door.kind_of? Hash then
|
pdata["doors"].each do |door|
|
||||||
mentioned_doors.add("#{door["room"]} - #{door["door"]}")
|
if door.kind_of? Hash then
|
||||||
else
|
mentioned_doors.add("#{door["room"]} - #{door["door"]}")
|
||||||
mentioned_doors.add("#{room_name} - #{door}")
|
else
|
||||||
|
mentioned_doors.add("#{room_name} - #{door}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if pdata.include? "panel_doors" then
|
||||||
|
pdata["panel_doors"].each do |panel_door|
|
||||||
|
if panel_door.kind_of? Hash then
|
||||||
|
mentioned_panel_doors.add("#{panel_door["room"]} - #{panel_door["panel_door"]}")
|
||||||
|
else
|
||||||
|
mentioned_panel_doors.add("#{room_name} - #{panel_door}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -344,17 +397,22 @@ end
|
||||||
|
|
||||||
errored_rooms = mentioned_rooms - configured_rooms
|
errored_rooms = mentioned_rooms - configured_rooms
|
||||||
unless errored_rooms.empty? then
|
unless errored_rooms.empty? then
|
||||||
puts "The folloring rooms are mentioned but do not exist: " + errored_rooms.to_s
|
puts "The following rooms are mentioned but do not exist: " + errored_rooms.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
errored_panels = mentioned_panels - configured_panels
|
errored_panels = mentioned_panels - configured_panels
|
||||||
unless errored_panels.empty? then
|
unless errored_panels.empty? then
|
||||||
puts "The folloring panels are mentioned but do not exist: " + errored_panels.to_s
|
puts "The following panels are mentioned but do not exist: " + errored_panels.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
errored_doors = mentioned_doors - configured_doors
|
errored_doors = mentioned_doors - configured_doors
|
||||||
unless errored_doors.empty? then
|
unless errored_doors.empty? then
|
||||||
puts "The folloring doors are mentioned but do not exist: " + errored_doors.to_s
|
puts "The following doors are mentioned but do not exist: " + errored_doors.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
errored_panel_doors = mentioned_panel_doors - configured_panel_doors
|
||||||
|
unless errored_panel_doors.empty? then
|
||||||
|
puts "The following panel doors are mentioned but do not exist: " + errored_panel_doors.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
door_groups.each do |group,num|
|
door_groups.each do |group,num|
|
||||||
|
@ -367,6 +425,16 @@ door_groups.each do |group,num|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
panel_groups.each do |group,num|
|
||||||
|
if num == 1 then
|
||||||
|
puts "Panel group \"#{group}\" only has one panel in it"
|
||||||
|
end
|
||||||
|
|
||||||
|
unless ids.include?("panel_groups") and ids["panel_groups"].include?(group)
|
||||||
|
puts "#{group} :::: Panel group is missing an item ID"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
slashed_rooms = configured_rooms.select do |room|
|
slashed_rooms = configured_rooms.select do |room|
|
||||||
room.include? "/"
|
room.include? "/"
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue