2024-02-15 23:19:54 +00:00
|
|
|
from enum import Enum
|
2023-11-25 12:09:08 +00:00
|
|
|
from typing import Dict, List, NamedTuple, Optional, Set, Tuple, TYPE_CHECKING
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2024-05-04 06:40:17 +00:00
|
|
|
from Options import OptionError
|
2024-05-19 22:56:24 +00:00
|
|
|
from .datatypes import Door, DoorType, Painting, RoomAndDoor, RoomAndPanel
|
Lingo: The Pilgrim Update (#2884)
* An option was added to enable or disable the pilgrimage, and it defaults to disabled. When disabled, the client will prevent you from performing a pilgrimage (i.e. the yellow border will not appear when you enter the 1 sunwarp). The sun painting is added to the item pool when pilgrimage is disabled, as otherwise there is no way into the Pilgrim Antechamber. Inversely, the sun painting is no longer in the item pool when pilgrimage is enabled (even if door shuffle is on), requiring you to perform a pilgrimage to get to that room.
* The canonical pilgrimage has been deprecated. Instead, there is logic for determining whether a pilgrimage is possible.
* Two options were added that allow the player to decide whether paintings and/or Crossroads - Roof Access are permitted during the pilgrimage. Both default to disabled. These options apply both to logical expectations in the generator, and are also enforced by the game client.
* An option was added to control how sunwarps are accessed. The default is for them to always be accessible, like in the base game. It is also possible to disable them entirely (which is not possible when pilgrimage is enabled), or lock them behind items similar to door shuffle. It can either be one item that unlocks all sunwarps at the same time, six progressive items that unlock the sunwarps from 1 to 6, or six individual items that unlock the sunwarps in any order. This option is independent from door shuffle.
* An option was added that shuffles sunwarps. This acts similarly to painting shuffle. The 12 sunwarps are re-ordered and re-paired. Sunwarps that were previously entrances or exits do not need to stay entrances or exits. Performing a pilgrimage requires proceeding through the sunwarps in the new order, rather than the original one.
* Pilgrimage was added as a win condition. It requires you to solve the blue PILGRIM panel in the Pilgrim Antechamber.
2024-04-18 16:45:33 +00:00
|
|
|
from .items import ALL_ITEM_TABLE, ItemType
|
2023-11-08 23:35:12 +00:00
|
|
|
from .locations import ALL_LOCATION_TABLE, LocationClassification
|
Lingo: The Pilgrim Update (#2884)
* An option was added to enable or disable the pilgrimage, and it defaults to disabled. When disabled, the client will prevent you from performing a pilgrimage (i.e. the yellow border will not appear when you enter the 1 sunwarp). The sun painting is added to the item pool when pilgrimage is disabled, as otherwise there is no way into the Pilgrim Antechamber. Inversely, the sun painting is no longer in the item pool when pilgrimage is enabled (even if door shuffle is on), requiring you to perform a pilgrimage to get to that room.
* The canonical pilgrimage has been deprecated. Instead, there is logic for determining whether a pilgrimage is possible.
* Two options were added that allow the player to decide whether paintings and/or Crossroads - Roof Access are permitted during the pilgrimage. Both default to disabled. These options apply both to logical expectations in the generator, and are also enforced by the game client.
* An option was added to control how sunwarps are accessed. The default is for them to always be accessible, like in the base game. It is also possible to disable them entirely (which is not possible when pilgrimage is enabled), or lock them behind items similar to door shuffle. It can either be one item that unlocks all sunwarps at the same time, six progressive items that unlock the sunwarps from 1 to 6, or six individual items that unlock the sunwarps in any order. This option is independent from door shuffle.
* An option was added that shuffles sunwarps. This acts similarly to painting shuffle. The 12 sunwarps are re-ordered and re-paired. Sunwarps that were previously entrances or exits do not need to stay entrances or exits. Performing a pilgrimage requires proceeding through the sunwarps in the new order, rather than the original one.
* Pilgrimage was added as a win condition. It requires you to solve the blue PILGRIM panel in the Pilgrim Antechamber.
2024-04-18 16:45:33 +00:00
|
|
|
from .options import LocationChecks, ShuffleDoors, SunwarpAccess, VictoryCondition
|
2024-03-15 08:26:00 +00:00
|
|
|
from .static_logic import DOORS_BY_ROOM, PAINTINGS, PAINTING_ENTRANCES, PAINTING_EXITS, \
|
2024-07-26 08:53:11 +00:00
|
|
|
PANELS_BY_ROOM, REQUIRED_PAINTING_ROOMS, REQUIRED_PAINTING_WHEN_NO_DOORS_ROOMS, PROGRESSIVE_DOORS_BY_ROOM, \
|
|
|
|
PANEL_DOORS_BY_ROOM, PROGRESSIVE_PANELS_BY_ROOM, SUNWARP_ENTRANCES, SUNWARP_EXITS
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
if TYPE_CHECKING:
|
|
|
|
from . import LingoWorld
|
|
|
|
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
class AccessRequirements:
|
|
|
|
rooms: Set[str]
|
|
|
|
doors: Set[RoomAndDoor]
|
|
|
|
colors: Set[str]
|
2024-07-26 08:53:11 +00:00
|
|
|
items: Set[str]
|
|
|
|
progression: Dict[str, int]
|
2024-06-03 08:51:27 +00:00
|
|
|
the_master: bool
|
2024-07-24 12:34:51 +00:00
|
|
|
postgame: bool
|
2023-11-25 12:09:08 +00:00
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
self.rooms = set()
|
|
|
|
self.doors = set()
|
|
|
|
self.colors = set()
|
2024-07-26 08:53:11 +00:00
|
|
|
self.items = set()
|
|
|
|
self.progression = dict()
|
2024-06-03 08:51:27 +00:00
|
|
|
self.the_master = False
|
2024-07-24 12:34:51 +00:00
|
|
|
self.postgame = False
|
2023-11-25 12:09:08 +00:00
|
|
|
|
|
|
|
def merge(self, other: "AccessRequirements"):
|
|
|
|
self.rooms |= other.rooms
|
|
|
|
self.doors |= other.doors
|
|
|
|
self.colors |= other.colors
|
2024-07-26 08:53:11 +00:00
|
|
|
self.items |= other.items
|
2024-06-03 08:51:27 +00:00
|
|
|
self.the_master |= other.the_master
|
2024-07-24 12:34:51 +00:00
|
|
|
self.postgame |= other.postgame
|
2023-11-25 12:09:08 +00:00
|
|
|
|
2024-07-26 08:53:11 +00:00
|
|
|
for progression, index in other.progression.items():
|
|
|
|
if progression not in self.progression or index > self.progression[progression]:
|
|
|
|
self.progression[progression] = index
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
def __str__(self):
|
2024-07-26 08:53:11 +00:00
|
|
|
return f"AccessRequirements(rooms={self.rooms}, doors={self.doors}, colors={self.colors}, items={self.items}," \
|
|
|
|
f" progression={self.progression}), the_master={self.the_master}, postgame={self.postgame}"
|
2023-11-25 12:09:08 +00:00
|
|
|
|
|
|
|
|
2023-11-08 23:35:12 +00:00
|
|
|
class PlayerLocation(NamedTuple):
|
|
|
|
name: str
|
2023-11-25 12:09:08 +00:00
|
|
|
code: Optional[int]
|
|
|
|
access: AccessRequirements
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
|
2024-02-15 23:19:54 +00:00
|
|
|
class ProgressiveItemBehavior(Enum):
|
|
|
|
DISABLE = 1
|
|
|
|
SPLIT = 2
|
|
|
|
PROGRESSIVE = 3
|
|
|
|
|
|
|
|
|
|
|
|
def should_split_progression(progression_name: str, world: "LingoWorld") -> ProgressiveItemBehavior:
|
|
|
|
if progression_name == "Progressive Orange Tower":
|
|
|
|
if world.options.progressive_orange_tower:
|
|
|
|
return ProgressiveItemBehavior.PROGRESSIVE
|
|
|
|
else:
|
|
|
|
return ProgressiveItemBehavior.SPLIT
|
|
|
|
elif progression_name == "Progressive Colorful":
|
|
|
|
if world.options.progressive_colorful:
|
|
|
|
return ProgressiveItemBehavior.PROGRESSIVE
|
|
|
|
else:
|
|
|
|
return ProgressiveItemBehavior.SPLIT
|
|
|
|
|
|
|
|
return ProgressiveItemBehavior.PROGRESSIVE
|
|
|
|
|
|
|
|
|
2023-11-08 23:35:12 +00:00
|
|
|
class LingoPlayerLogic:
|
|
|
|
"""
|
|
|
|
Defines logic after a player's options have been applied
|
|
|
|
"""
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
item_by_door: Dict[str, Dict[str, str]]
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
locations_by_room: Dict[str, List[PlayerLocation]]
|
|
|
|
real_locations: List[str]
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
event_loc_to_item: Dict[str, str]
|
|
|
|
real_items: List[str]
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
victory_condition: str
|
|
|
|
mastery_location: str
|
|
|
|
level_2_location: str
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
painting_mapping: Dict[str, str]
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
forced_good_item: str
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
panel_reqs: Dict[str, Dict[str, AccessRequirements]]
|
|
|
|
door_reqs: Dict[str, Dict[str, AccessRequirements]]
|
|
|
|
mastery_reqs: List[AccessRequirements]
|
|
|
|
counting_panel_reqs: Dict[str, List[Tuple[AccessRequirements, int]]]
|
|
|
|
|
Lingo: The Pilgrim Update (#2884)
* An option was added to enable or disable the pilgrimage, and it defaults to disabled. When disabled, the client will prevent you from performing a pilgrimage (i.e. the yellow border will not appear when you enter the 1 sunwarp). The sun painting is added to the item pool when pilgrimage is disabled, as otherwise there is no way into the Pilgrim Antechamber. Inversely, the sun painting is no longer in the item pool when pilgrimage is enabled (even if door shuffle is on), requiring you to perform a pilgrimage to get to that room.
* The canonical pilgrimage has been deprecated. Instead, there is logic for determining whether a pilgrimage is possible.
* Two options were added that allow the player to decide whether paintings and/or Crossroads - Roof Access are permitted during the pilgrimage. Both default to disabled. These options apply both to logical expectations in the generator, and are also enforced by the game client.
* An option was added to control how sunwarps are accessed. The default is for them to always be accessible, like in the base game. It is also possible to disable them entirely (which is not possible when pilgrimage is enabled), or lock them behind items similar to door shuffle. It can either be one item that unlocks all sunwarps at the same time, six progressive items that unlock the sunwarps from 1 to 6, or six individual items that unlock the sunwarps in any order. This option is independent from door shuffle.
* An option was added that shuffles sunwarps. This acts similarly to painting shuffle. The 12 sunwarps are re-ordered and re-paired. Sunwarps that were previously entrances or exits do not need to stay entrances or exits. Performing a pilgrimage requires proceeding through the sunwarps in the new order, rather than the original one.
* Pilgrimage was added as a win condition. It requires you to solve the blue PILGRIM panel in the Pilgrim Antechamber.
2024-04-18 16:45:33 +00:00
|
|
|
sunwarp_mapping: List[int]
|
|
|
|
sunwarp_entrances: List[str]
|
|
|
|
sunwarp_exits: List[str]
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
def add_location(self, room: str, name: str, code: Optional[int], panels: List[RoomAndPanel], world: "LingoWorld"):
|
|
|
|
"""
|
|
|
|
Creates a location. This function determines the access requirements for the location by combining and
|
|
|
|
flattening the requirements for each of the given panels.
|
|
|
|
"""
|
|
|
|
access_reqs = AccessRequirements()
|
|
|
|
for panel in panels:
|
|
|
|
if panel.room is not None and panel.room != room:
|
|
|
|
access_reqs.rooms.add(panel.room)
|
|
|
|
|
|
|
|
panel_room = room if panel.room is None else panel.room
|
|
|
|
sub_access_reqs = self.calculate_panel_requirements(panel_room, panel.panel, world)
|
|
|
|
access_reqs.merge(sub_access_reqs)
|
|
|
|
|
|
|
|
self.locations_by_room.setdefault(room, []).append(PlayerLocation(name, code, access_reqs))
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
def set_door_item(self, room: str, door: str, item: str):
|
2023-11-25 12:09:08 +00:00
|
|
|
self.item_by_door.setdefault(room, {})[door] = item
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
def handle_non_grouped_door(self, room_name: str, door_data: Door, world: "LingoWorld"):
|
2024-07-26 08:53:11 +00:00
|
|
|
if room_name in PROGRESSIVE_DOORS_BY_ROOM and door_data.name in PROGRESSIVE_DOORS_BY_ROOM[room_name]:
|
|
|
|
progression_name = PROGRESSIVE_DOORS_BY_ROOM[room_name][door_data.name].item_name
|
2024-02-15 23:19:54 +00:00
|
|
|
progression_handling = should_split_progression(progression_name, world)
|
|
|
|
|
|
|
|
if progression_handling == ProgressiveItemBehavior.SPLIT:
|
2023-11-08 23:35:12 +00:00
|
|
|
self.set_door_item(room_name, door_data.name, door_data.item_name)
|
2024-02-15 23:19:54 +00:00
|
|
|
self.real_items.append(door_data.item_name)
|
|
|
|
elif progression_handling == ProgressiveItemBehavior.PROGRESSIVE:
|
2024-07-26 08:53:11 +00:00
|
|
|
progressive_item_name = PROGRESSIVE_DOORS_BY_ROOM[room_name][door_data.name].item_name
|
2023-11-08 23:35:12 +00:00
|
|
|
self.set_door_item(room_name, door_data.name, progressive_item_name)
|
2023-11-25 12:09:08 +00:00
|
|
|
self.real_items.append(progressive_item_name)
|
2023-11-08 23:35:12 +00:00
|
|
|
else:
|
|
|
|
self.set_door_item(room_name, door_data.name, door_data.item_name)
|
Lingo: The Pilgrim Update (#2884)
* An option was added to enable or disable the pilgrimage, and it defaults to disabled. When disabled, the client will prevent you from performing a pilgrimage (i.e. the yellow border will not appear when you enter the 1 sunwarp). The sun painting is added to the item pool when pilgrimage is disabled, as otherwise there is no way into the Pilgrim Antechamber. Inversely, the sun painting is no longer in the item pool when pilgrimage is enabled (even if door shuffle is on), requiring you to perform a pilgrimage to get to that room.
* The canonical pilgrimage has been deprecated. Instead, there is logic for determining whether a pilgrimage is possible.
* Two options were added that allow the player to decide whether paintings and/or Crossroads - Roof Access are permitted during the pilgrimage. Both default to disabled. These options apply both to logical expectations in the generator, and are also enforced by the game client.
* An option was added to control how sunwarps are accessed. The default is for them to always be accessible, like in the base game. It is also possible to disable them entirely (which is not possible when pilgrimage is enabled), or lock them behind items similar to door shuffle. It can either be one item that unlocks all sunwarps at the same time, six progressive items that unlock the sunwarps from 1 to 6, or six individual items that unlock the sunwarps in any order. This option is independent from door shuffle.
* An option was added that shuffles sunwarps. This acts similarly to painting shuffle. The 12 sunwarps are re-ordered and re-paired. Sunwarps that were previously entrances or exits do not need to stay entrances or exits. Performing a pilgrimage requires proceeding through the sunwarps in the new order, rather than the original one.
* Pilgrimage was added as a win condition. It requires you to solve the blue PILGRIM panel in the Pilgrim Antechamber.
2024-04-18 16:45:33 +00:00
|
|
|
self.real_items.append(door_data.item_name)
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
def __init__(self, world: "LingoWorld"):
|
2023-11-25 12:09:08 +00:00
|
|
|
self.item_by_door = {}
|
|
|
|
self.locations_by_room = {}
|
|
|
|
self.real_locations = []
|
|
|
|
self.event_loc_to_item = {}
|
|
|
|
self.real_items = []
|
|
|
|
self.victory_condition = ""
|
|
|
|
self.mastery_location = ""
|
|
|
|
self.level_2_location = ""
|
|
|
|
self.painting_mapping = {}
|
|
|
|
self.forced_good_item = ""
|
|
|
|
self.panel_reqs = {}
|
|
|
|
self.door_reqs = {}
|
|
|
|
self.mastery_reqs = []
|
|
|
|
self.counting_panel_reqs = {}
|
Lingo: The Pilgrim Update (#2884)
* An option was added to enable or disable the pilgrimage, and it defaults to disabled. When disabled, the client will prevent you from performing a pilgrimage (i.e. the yellow border will not appear when you enter the 1 sunwarp). The sun painting is added to the item pool when pilgrimage is disabled, as otherwise there is no way into the Pilgrim Antechamber. Inversely, the sun painting is no longer in the item pool when pilgrimage is enabled (even if door shuffle is on), requiring you to perform a pilgrimage to get to that room.
* The canonical pilgrimage has been deprecated. Instead, there is logic for determining whether a pilgrimage is possible.
* Two options were added that allow the player to decide whether paintings and/or Crossroads - Roof Access are permitted during the pilgrimage. Both default to disabled. These options apply both to logical expectations in the generator, and are also enforced by the game client.
* An option was added to control how sunwarps are accessed. The default is for them to always be accessible, like in the base game. It is also possible to disable them entirely (which is not possible when pilgrimage is enabled), or lock them behind items similar to door shuffle. It can either be one item that unlocks all sunwarps at the same time, six progressive items that unlock the sunwarps from 1 to 6, or six individual items that unlock the sunwarps in any order. This option is independent from door shuffle.
* An option was added that shuffles sunwarps. This acts similarly to painting shuffle. The 12 sunwarps are re-ordered and re-paired. Sunwarps that were previously entrances or exits do not need to stay entrances or exits. Performing a pilgrimage requires proceeding through the sunwarps in the new order, rather than the original one.
* Pilgrimage was added as a win condition. It requires you to solve the blue PILGRIM panel in the Pilgrim Antechamber.
2024-04-18 16:45:33 +00:00
|
|
|
self.sunwarp_mapping = []
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
door_shuffle = world.options.shuffle_doors
|
|
|
|
color_shuffle = world.options.shuffle_colors
|
|
|
|
painting_shuffle = world.options.shuffle_paintings
|
|
|
|
location_checks = world.options.location_checks
|
|
|
|
victory_condition = world.options.victory_condition
|
|
|
|
early_color_hallways = world.options.early_color_hallways
|
|
|
|
|
2024-07-26 08:53:11 +00:00
|
|
|
if location_checks == LocationChecks.option_reduced:
|
|
|
|
if door_shuffle == ShuffleDoors.option_doors:
|
|
|
|
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.")
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
# Create door items, where needed.
|
Lingo: The Pilgrim Update (#2884)
* An option was added to enable or disable the pilgrimage, and it defaults to disabled. When disabled, the client will prevent you from performing a pilgrimage (i.e. the yellow border will not appear when you enter the 1 sunwarp). The sun painting is added to the item pool when pilgrimage is disabled, as otherwise there is no way into the Pilgrim Antechamber. Inversely, the sun painting is no longer in the item pool when pilgrimage is enabled (even if door shuffle is on), requiring you to perform a pilgrimage to get to that room.
* The canonical pilgrimage has been deprecated. Instead, there is logic for determining whether a pilgrimage is possible.
* Two options were added that allow the player to decide whether paintings and/or Crossroads - Roof Access are permitted during the pilgrimage. Both default to disabled. These options apply both to logical expectations in the generator, and are also enforced by the game client.
* An option was added to control how sunwarps are accessed. The default is for them to always be accessible, like in the base game. It is also possible to disable them entirely (which is not possible when pilgrimage is enabled), or lock them behind items similar to door shuffle. It can either be one item that unlocks all sunwarps at the same time, six progressive items that unlock the sunwarps from 1 to 6, or six individual items that unlock the sunwarps in any order. This option is independent from door shuffle.
* An option was added that shuffles sunwarps. This acts similarly to painting shuffle. The 12 sunwarps are re-ordered and re-paired. Sunwarps that were previously entrances or exits do not need to stay entrances or exits. Performing a pilgrimage requires proceeding through the sunwarps in the new order, rather than the original one.
* Pilgrimage was added as a win condition. It requires you to solve the blue PILGRIM panel in the Pilgrim Antechamber.
2024-04-18 16:45:33 +00:00
|
|
|
door_groups: Set[str] = set()
|
|
|
|
for room_name, room_data in DOORS_BY_ROOM.items():
|
|
|
|
for door_name, door_data in room_data.items():
|
|
|
|
if door_data.skip_item is False and door_data.event is False:
|
2024-07-26 08:53:11 +00:00
|
|
|
if door_data.type == DoorType.NORMAL and door_shuffle == ShuffleDoors.option_doors:
|
|
|
|
if door_data.door_group is not None and world.options.group_doors:
|
2023-11-08 23:35:12 +00:00
|
|
|
# Grouped doors are handled differently if shuffle doors is on simple.
|
2024-03-21 15:46:53 +00:00
|
|
|
self.set_door_item(room_name, door_name, door_data.door_group)
|
Lingo: The Pilgrim Update (#2884)
* An option was added to enable or disable the pilgrimage, and it defaults to disabled. When disabled, the client will prevent you from performing a pilgrimage (i.e. the yellow border will not appear when you enter the 1 sunwarp). The sun painting is added to the item pool when pilgrimage is disabled, as otherwise there is no way into the Pilgrim Antechamber. Inversely, the sun painting is no longer in the item pool when pilgrimage is enabled (even if door shuffle is on), requiring you to perform a pilgrimage to get to that room.
* The canonical pilgrimage has been deprecated. Instead, there is logic for determining whether a pilgrimage is possible.
* Two options were added that allow the player to decide whether paintings and/or Crossroads - Roof Access are permitted during the pilgrimage. Both default to disabled. These options apply both to logical expectations in the generator, and are also enforced by the game client.
* An option was added to control how sunwarps are accessed. The default is for them to always be accessible, like in the base game. It is also possible to disable them entirely (which is not possible when pilgrimage is enabled), or lock them behind items similar to door shuffle. It can either be one item that unlocks all sunwarps at the same time, six progressive items that unlock the sunwarps from 1 to 6, or six individual items that unlock the sunwarps in any order. This option is independent from door shuffle.
* An option was added that shuffles sunwarps. This acts similarly to painting shuffle. The 12 sunwarps are re-ordered and re-paired. Sunwarps that were previously entrances or exits do not need to stay entrances or exits. Performing a pilgrimage requires proceeding through the sunwarps in the new order, rather than the original one.
* Pilgrimage was added as a win condition. It requires you to solve the blue PILGRIM panel in the Pilgrim Antechamber.
2024-04-18 16:45:33 +00:00
|
|
|
door_groups.add(door_data.door_group)
|
2023-11-08 23:35:12 +00:00
|
|
|
else:
|
|
|
|
self.handle_non_grouped_door(room_name, door_data, world)
|
Lingo: The Pilgrim Update (#2884)
* An option was added to enable or disable the pilgrimage, and it defaults to disabled. When disabled, the client will prevent you from performing a pilgrimage (i.e. the yellow border will not appear when you enter the 1 sunwarp). The sun painting is added to the item pool when pilgrimage is disabled, as otherwise there is no way into the Pilgrim Antechamber. Inversely, the sun painting is no longer in the item pool when pilgrimage is enabled (even if door shuffle is on), requiring you to perform a pilgrimage to get to that room.
* The canonical pilgrimage has been deprecated. Instead, there is logic for determining whether a pilgrimage is possible.
* Two options were added that allow the player to decide whether paintings and/or Crossroads - Roof Access are permitted during the pilgrimage. Both default to disabled. These options apply both to logical expectations in the generator, and are also enforced by the game client.
* An option was added to control how sunwarps are accessed. The default is for them to always be accessible, like in the base game. It is also possible to disable them entirely (which is not possible when pilgrimage is enabled), or lock them behind items similar to door shuffle. It can either be one item that unlocks all sunwarps at the same time, six progressive items that unlock the sunwarps from 1 to 6, or six individual items that unlock the sunwarps in any order. This option is independent from door shuffle.
* An option was added that shuffles sunwarps. This acts similarly to painting shuffle. The 12 sunwarps are re-ordered and re-paired. Sunwarps that were previously entrances or exits do not need to stay entrances or exits. Performing a pilgrimage requires proceeding through the sunwarps in the new order, rather than the original one.
* Pilgrimage was added as a win condition. It requires you to solve the blue PILGRIM panel in the Pilgrim Antechamber.
2024-04-18 16:45:33 +00:00
|
|
|
elif door_data.type == DoorType.SUNWARP:
|
|
|
|
if world.options.sunwarp_access == SunwarpAccess.option_unlock:
|
|
|
|
self.set_door_item(room_name, door_name, "Sunwarps")
|
|
|
|
door_groups.add("Sunwarps")
|
|
|
|
elif world.options.sunwarp_access == SunwarpAccess.option_individual:
|
|
|
|
self.set_door_item(room_name, door_name, door_data.item_name)
|
|
|
|
self.real_items.append(door_data.item_name)
|
|
|
|
elif world.options.sunwarp_access == SunwarpAccess.option_progressive:
|
|
|
|
self.set_door_item(room_name, door_name, "Progressive Pilgrimage")
|
|
|
|
self.real_items.append("Progressive Pilgrimage")
|
|
|
|
elif door_data.type == DoorType.SUN_PAINTING:
|
|
|
|
if not world.options.enable_pilgrimage:
|
|
|
|
self.set_door_item(room_name, door_name, door_data.item_name)
|
|
|
|
self.real_items.append(door_data.item_name)
|
|
|
|
|
|
|
|
self.real_items += door_groups
|
2024-07-26 08:53:11 +00:00
|
|
|
|
|
|
|
# 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
|
|
|
|
|
Lingo: The Pilgrim Update (#2884)
* An option was added to enable or disable the pilgrimage, and it defaults to disabled. When disabled, the client will prevent you from performing a pilgrimage (i.e. the yellow border will not appear when you enter the 1 sunwarp). The sun painting is added to the item pool when pilgrimage is disabled, as otherwise there is no way into the Pilgrim Antechamber. Inversely, the sun painting is no longer in the item pool when pilgrimage is enabled (even if door shuffle is on), requiring you to perform a pilgrimage to get to that room.
* The canonical pilgrimage has been deprecated. Instead, there is logic for determining whether a pilgrimage is possible.
* Two options were added that allow the player to decide whether paintings and/or Crossroads - Roof Access are permitted during the pilgrimage. Both default to disabled. These options apply both to logical expectations in the generator, and are also enforced by the game client.
* An option was added to control how sunwarps are accessed. The default is for them to always be accessible, like in the base game. It is also possible to disable them entirely (which is not possible when pilgrimage is enabled), or lock them behind items similar to door shuffle. It can either be one item that unlocks all sunwarps at the same time, six progressive items that unlock the sunwarps from 1 to 6, or six individual items that unlock the sunwarps in any order. This option is independent from door shuffle.
* An option was added that shuffles sunwarps. This acts similarly to painting shuffle. The 12 sunwarps are re-ordered and re-paired. Sunwarps that were previously entrances or exits do not need to stay entrances or exits. Performing a pilgrimage requires proceeding through the sunwarps in the new order, rather than the original one.
* Pilgrimage was added as a win condition. It requires you to solve the blue PILGRIM panel in the Pilgrim Antechamber.
2024-04-18 16:45:33 +00:00
|
|
|
# Create color items, if needed.
|
|
|
|
if color_shuffle:
|
|
|
|
self.real_items += [name for name, item in ALL_ITEM_TABLE.items() if item.type == ItemType.COLOR]
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
# Handle the victory condition. Victory conditions other than the chosen one become regular checks, so we need
|
|
|
|
# to prevent the actual victory condition from becoming a check.
|
2023-11-25 12:09:08 +00:00
|
|
|
self.mastery_location = "Orange Tower Seventh Floor - THE MASTER"
|
|
|
|
self.level_2_location = "Second Room - LEVEL 2"
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
if victory_condition == VictoryCondition.option_the_end:
|
2023-11-25 12:09:08 +00:00
|
|
|
self.victory_condition = "Orange Tower Seventh Floor - THE END"
|
2024-07-24 12:34:51 +00:00
|
|
|
self.add_location("Ending Area", "The End (Solved)", None, [], world)
|
2023-11-25 12:09:08 +00:00
|
|
|
self.event_loc_to_item["The End (Solved)"] = "Victory"
|
2023-11-08 23:35:12 +00:00
|
|
|
elif victory_condition == VictoryCondition.option_the_master:
|
2023-11-25 12:09:08 +00:00
|
|
|
self.victory_condition = "Orange Tower Seventh Floor - THE MASTER"
|
|
|
|
self.mastery_location = "Orange Tower Seventh Floor - Mastery Achievements"
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
self.add_location("Orange Tower Seventh Floor", self.mastery_location, None, [], world)
|
|
|
|
self.event_loc_to_item[self.mastery_location] = "Victory"
|
2023-11-08 23:35:12 +00:00
|
|
|
elif victory_condition == VictoryCondition.option_level_2:
|
2023-11-25 12:09:08 +00:00
|
|
|
self.victory_condition = "Second Room - LEVEL 2"
|
|
|
|
self.level_2_location = "Second Room - Unlock Level 2"
|
|
|
|
|
|
|
|
self.add_location("Second Room", self.level_2_location, None, [RoomAndPanel("Second Room", "LEVEL 2")],
|
|
|
|
world)
|
|
|
|
self.event_loc_to_item[self.level_2_location] = "Victory"
|
|
|
|
|
|
|
|
if world.options.level_2_requirement == 1:
|
2024-05-04 06:40:17 +00:00
|
|
|
raise OptionError("The Level 2 requirement must be at least 2 when LEVEL 2 is the victory condition.")
|
Lingo: The Pilgrim Update (#2884)
* An option was added to enable or disable the pilgrimage, and it defaults to disabled. When disabled, the client will prevent you from performing a pilgrimage (i.e. the yellow border will not appear when you enter the 1 sunwarp). The sun painting is added to the item pool when pilgrimage is disabled, as otherwise there is no way into the Pilgrim Antechamber. Inversely, the sun painting is no longer in the item pool when pilgrimage is enabled (even if door shuffle is on), requiring you to perform a pilgrimage to get to that room.
* The canonical pilgrimage has been deprecated. Instead, there is logic for determining whether a pilgrimage is possible.
* Two options were added that allow the player to decide whether paintings and/or Crossroads - Roof Access are permitted during the pilgrimage. Both default to disabled. These options apply both to logical expectations in the generator, and are also enforced by the game client.
* An option was added to control how sunwarps are accessed. The default is for them to always be accessible, like in the base game. It is also possible to disable them entirely (which is not possible when pilgrimage is enabled), or lock them behind items similar to door shuffle. It can either be one item that unlocks all sunwarps at the same time, six progressive items that unlock the sunwarps from 1 to 6, or six individual items that unlock the sunwarps in any order. This option is independent from door shuffle.
* An option was added that shuffles sunwarps. This acts similarly to painting shuffle. The 12 sunwarps are re-ordered and re-paired. Sunwarps that were previously entrances or exits do not need to stay entrances or exits. Performing a pilgrimage requires proceeding through the sunwarps in the new order, rather than the original one.
* Pilgrimage was added as a win condition. It requires you to solve the blue PILGRIM panel in the Pilgrim Antechamber.
2024-04-18 16:45:33 +00:00
|
|
|
elif victory_condition == VictoryCondition.option_pilgrimage:
|
|
|
|
self.victory_condition = "Pilgrim Antechamber - PILGRIM"
|
|
|
|
self.add_location("Pilgrim Antechamber", "PILGRIM (Solved)", None,
|
|
|
|
[RoomAndPanel("Pilgrim Antechamber", "PILGRIM")], world)
|
|
|
|
self.event_loc_to_item["PILGRIM (Solved)"] = "Victory"
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2024-07-24 12:34:51 +00:00
|
|
|
# Create events for each achievement panel, so that we can determine when THE MASTER is accessible.
|
|
|
|
for room_name, room_data in PANELS_BY_ROOM.items():
|
|
|
|
for panel_name, panel_data in room_data.items():
|
|
|
|
if panel_data.achievement:
|
|
|
|
access_req = AccessRequirements()
|
|
|
|
access_req.merge(self.calculate_panel_requirements(room_name, panel_name, world))
|
|
|
|
access_req.rooms.add(room_name)
|
|
|
|
|
|
|
|
self.mastery_reqs.append(access_req)
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
# Create groups of counting panel access requirements for the LEVEL 2 check.
|
|
|
|
self.create_panel_hunt_events(world)
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
# Instantiate all real locations.
|
|
|
|
location_classification = LocationClassification.normal
|
|
|
|
if location_checks == LocationChecks.option_reduced:
|
|
|
|
location_classification = LocationClassification.reduced
|
|
|
|
elif location_checks == LocationChecks.option_insanity:
|
|
|
|
location_classification = LocationClassification.insanity
|
|
|
|
|
2024-07-26 08:53:11 +00:00
|
|
|
if door_shuffle == ShuffleDoors.option_doors and not early_color_hallways:
|
2024-05-02 07:52:16 +00:00
|
|
|
location_classification |= LocationClassification.small_sphere_one
|
|
|
|
|
2023-11-08 23:35:12 +00:00
|
|
|
for location_name, location_data in ALL_LOCATION_TABLE.items():
|
2023-11-25 12:09:08 +00:00
|
|
|
if location_name != self.victory_condition:
|
2024-05-02 07:52:16 +00:00
|
|
|
if not (location_classification & location_data.classification):
|
2023-11-08 23:35:12 +00:00
|
|
|
continue
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
self.add_location(location_data.room, location_name, location_data.code, location_data.panels, world)
|
|
|
|
self.real_locations.append(location_name)
|
2023-11-08 23:35:12 +00:00
|
|
|
|
Lingo: The Pilgrim Update (#2884)
* An option was added to enable or disable the pilgrimage, and it defaults to disabled. When disabled, the client will prevent you from performing a pilgrimage (i.e. the yellow border will not appear when you enter the 1 sunwarp). The sun painting is added to the item pool when pilgrimage is disabled, as otherwise there is no way into the Pilgrim Antechamber. Inversely, the sun painting is no longer in the item pool when pilgrimage is enabled (even if door shuffle is on), requiring you to perform a pilgrimage to get to that room.
* The canonical pilgrimage has been deprecated. Instead, there is logic for determining whether a pilgrimage is possible.
* Two options were added that allow the player to decide whether paintings and/or Crossroads - Roof Access are permitted during the pilgrimage. Both default to disabled. These options apply both to logical expectations in the generator, and are also enforced by the game client.
* An option was added to control how sunwarps are accessed. The default is for them to always be accessible, like in the base game. It is also possible to disable them entirely (which is not possible when pilgrimage is enabled), or lock them behind items similar to door shuffle. It can either be one item that unlocks all sunwarps at the same time, six progressive items that unlock the sunwarps from 1 to 6, or six individual items that unlock the sunwarps in any order. This option is independent from door shuffle.
* An option was added that shuffles sunwarps. This acts similarly to painting shuffle. The 12 sunwarps are re-ordered and re-paired. Sunwarps that were previously entrances or exits do not need to stay entrances or exits. Performing a pilgrimage requires proceeding through the sunwarps in the new order, rather than the original one.
* Pilgrimage was added as a win condition. It requires you to solve the blue PILGRIM panel in the Pilgrim Antechamber.
2024-04-18 16:45:33 +00:00
|
|
|
if world.options.enable_pilgrimage and world.options.sunwarp_access == SunwarpAccess.option_disabled:
|
2024-05-04 06:40:17 +00:00
|
|
|
raise OptionError("Sunwarps cannot be disabled when pilgrimage is enabled.")
|
Lingo: The Pilgrim Update (#2884)
* An option was added to enable or disable the pilgrimage, and it defaults to disabled. When disabled, the client will prevent you from performing a pilgrimage (i.e. the yellow border will not appear when you enter the 1 sunwarp). The sun painting is added to the item pool when pilgrimage is disabled, as otherwise there is no way into the Pilgrim Antechamber. Inversely, the sun painting is no longer in the item pool when pilgrimage is enabled (even if door shuffle is on), requiring you to perform a pilgrimage to get to that room.
* The canonical pilgrimage has been deprecated. Instead, there is logic for determining whether a pilgrimage is possible.
* Two options were added that allow the player to decide whether paintings and/or Crossroads - Roof Access are permitted during the pilgrimage. Both default to disabled. These options apply both to logical expectations in the generator, and are also enforced by the game client.
* An option was added to control how sunwarps are accessed. The default is for them to always be accessible, like in the base game. It is also possible to disable them entirely (which is not possible when pilgrimage is enabled), or lock them behind items similar to door shuffle. It can either be one item that unlocks all sunwarps at the same time, six progressive items that unlock the sunwarps from 1 to 6, or six individual items that unlock the sunwarps in any order. This option is independent from door shuffle.
* An option was added that shuffles sunwarps. This acts similarly to painting shuffle. The 12 sunwarps are re-ordered and re-paired. Sunwarps that were previously entrances or exits do not need to stay entrances or exits. Performing a pilgrimage requires proceeding through the sunwarps in the new order, rather than the original one.
* Pilgrimage was added as a win condition. It requires you to solve the blue PILGRIM panel in the Pilgrim Antechamber.
2024-04-18 16:45:33 +00:00
|
|
|
|
|
|
|
if world.options.shuffle_sunwarps:
|
|
|
|
if world.options.sunwarp_access == SunwarpAccess.option_disabled:
|
2024-05-04 06:40:17 +00:00
|
|
|
raise OptionError("Sunwarps cannot be shuffled if they are disabled.")
|
Lingo: The Pilgrim Update (#2884)
* An option was added to enable or disable the pilgrimage, and it defaults to disabled. When disabled, the client will prevent you from performing a pilgrimage (i.e. the yellow border will not appear when you enter the 1 sunwarp). The sun painting is added to the item pool when pilgrimage is disabled, as otherwise there is no way into the Pilgrim Antechamber. Inversely, the sun painting is no longer in the item pool when pilgrimage is enabled (even if door shuffle is on), requiring you to perform a pilgrimage to get to that room.
* The canonical pilgrimage has been deprecated. Instead, there is logic for determining whether a pilgrimage is possible.
* Two options were added that allow the player to decide whether paintings and/or Crossroads - Roof Access are permitted during the pilgrimage. Both default to disabled. These options apply both to logical expectations in the generator, and are also enforced by the game client.
* An option was added to control how sunwarps are accessed. The default is for them to always be accessible, like in the base game. It is also possible to disable them entirely (which is not possible when pilgrimage is enabled), or lock them behind items similar to door shuffle. It can either be one item that unlocks all sunwarps at the same time, six progressive items that unlock the sunwarps from 1 to 6, or six individual items that unlock the sunwarps in any order. This option is independent from door shuffle.
* An option was added that shuffles sunwarps. This acts similarly to painting shuffle. The 12 sunwarps are re-ordered and re-paired. Sunwarps that were previously entrances or exits do not need to stay entrances or exits. Performing a pilgrimage requires proceeding through the sunwarps in the new order, rather than the original one.
* Pilgrimage was added as a win condition. It requires you to solve the blue PILGRIM panel in the Pilgrim Antechamber.
2024-04-18 16:45:33 +00:00
|
|
|
|
|
|
|
self.sunwarp_mapping = list(range(0, 12))
|
|
|
|
world.random.shuffle(self.sunwarp_mapping)
|
|
|
|
|
|
|
|
sunwarp_rooms = SUNWARP_ENTRANCES + SUNWARP_EXITS
|
|
|
|
self.sunwarp_entrances = [sunwarp_rooms[i] for i in self.sunwarp_mapping[0:6]]
|
|
|
|
self.sunwarp_exits = [sunwarp_rooms[i] for i in self.sunwarp_mapping[6:12]]
|
|
|
|
else:
|
|
|
|
self.sunwarp_entrances = SUNWARP_ENTRANCES
|
|
|
|
self.sunwarp_exits = SUNWARP_EXITS
|
Lingo: Fix entrance checking being broken on default settings (#2506)
The most serious issue this PR addresses is that entrances that use doors without items (a small subset of doors when door shuffle is on, but *every* door when door shuffle is off, which is the default) underestimate the requirements needed to use that entrance. The logic would calculate the panels needed to open the door, but would neglect to keep track of the rooms those panels were in, meaning that doors would be considered openable if you had the colors needed to solve a panel that's in a room you have no access to.
Another issue is that, previously, logic would always consider the "ANOTHER TRY" panel accessible for the purposes of the LEVEL 2 panel hunt. This could result in seeds where the player is expected to have exactly the correct number of solves to reach LEVEL 2, but in reality is short by one because ANOTHER TRY itself is not revealed until the panel hunt is complete. This change marks ANOTHER TRY as non-counting, because even though it is technically a counting panel in-game, it can never contribute to the LEVEL 2 panel hunt. This issue could also apply to THE MASTER, since it is the only other counting panel with special access rules, although it is much less likely. This change adds special handling for counting THE MASTER. These issues were possible to manifest whenever the LEVEL 2 panel hunt was enabled, which it is by default.
Smaller logic issues also fixed in this PR:
* The Orange Tower Basement MASTERY panel was marked as requiring the mastery doors to be opened, when it was actually possible to get it without them by using a painting to get into the room.
* The Pilgrim Room painting item was incorrectly being marked as a filler item, despite it being progression.
* There has been another update to the game that adds connections between areas that were previously not connected. These changes were additive, which is why they are not critical.
* The panel stacks in the rhyme room now require both colours on each panel.
2023-12-10 18:15:42 +00:00
|
|
|
|
2023-11-08 23:35:12 +00:00
|
|
|
# Create the paintings mapping, if painting shuffle is on.
|
|
|
|
if painting_shuffle:
|
|
|
|
# Shuffle paintings until we get something workable.
|
|
|
|
workable_paintings = False
|
|
|
|
for i in range(0, 20):
|
|
|
|
workable_paintings = self.randomize_paintings(world)
|
|
|
|
if workable_paintings:
|
|
|
|
break
|
|
|
|
|
|
|
|
if not workable_paintings:
|
|
|
|
raise Exception("This Lingo world was unable to generate a workable painting mapping after 20 "
|
|
|
|
"iterations. This is very unlikely to happen on its own, and probably indicates some "
|
|
|
|
"kind of logic error.")
|
|
|
|
|
2024-07-26 08:53:11 +00:00
|
|
|
if door_shuffle == ShuffleDoors.option_doors and location_checks != LocationChecks.option_insanity \
|
2024-03-03 07:20:37 +00:00
|
|
|
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
|
|
|
|
# only three checks. In a multiplayer situation, this can be frustrating for the player because they are
|
|
|
|
# more likely to be stuck in the starting room for a long time. To remedy this, we will force a useful item
|
|
|
|
# onto the GOOD LUCK check under these circumstances. The goal is to expand sphere 1 to at least four
|
|
|
|
# checks (and likely more than that).
|
|
|
|
#
|
|
|
|
# Note: A very low LEVEL 2 requirement would naturally expand sphere 1 to four checks, but this is a very
|
|
|
|
# uncommon configuration, so we will ignore it and force a good item anyway.
|
|
|
|
|
|
|
|
# Starting Room - Back Right Door gives access to OPEN and DEAD END.
|
|
|
|
# Starting Room - Exit Door gives access to OPEN and TRACE.
|
2023-11-08 23:35:12 +00:00
|
|
|
good_item_options: List[str] = ["Starting Room - Back Right Door", "Second Room - Exit Door"]
|
|
|
|
|
Lingo: The Pilgrim Update (#2884)
* An option was added to enable or disable the pilgrimage, and it defaults to disabled. When disabled, the client will prevent you from performing a pilgrimage (i.e. the yellow border will not appear when you enter the 1 sunwarp). The sun painting is added to the item pool when pilgrimage is disabled, as otherwise there is no way into the Pilgrim Antechamber. Inversely, the sun painting is no longer in the item pool when pilgrimage is enabled (even if door shuffle is on), requiring you to perform a pilgrimage to get to that room.
* The canonical pilgrimage has been deprecated. Instead, there is logic for determining whether a pilgrimage is possible.
* Two options were added that allow the player to decide whether paintings and/or Crossroads - Roof Access are permitted during the pilgrimage. Both default to disabled. These options apply both to logical expectations in the generator, and are also enforced by the game client.
* An option was added to control how sunwarps are accessed. The default is for them to always be accessible, like in the base game. It is also possible to disable them entirely (which is not possible when pilgrimage is enabled), or lock them behind items similar to door shuffle. It can either be one item that unlocks all sunwarps at the same time, six progressive items that unlock the sunwarps from 1 to 6, or six individual items that unlock the sunwarps in any order. This option is independent from door shuffle.
* An option was added that shuffles sunwarps. This acts similarly to painting shuffle. The 12 sunwarps are re-ordered and re-paired. Sunwarps that were previously entrances or exits do not need to stay entrances or exits. Performing a pilgrimage requires proceeding through the sunwarps in the new order, rather than the original one.
* Pilgrimage was added as a win condition. It requires you to solve the blue PILGRIM panel in the Pilgrim Antechamber.
2024-04-18 16:45:33 +00:00
|
|
|
if not color_shuffle:
|
2024-07-26 08:53:11 +00:00
|
|
|
if not world.options.enable_pilgrimage:
|
|
|
|
# HOT CRUST and THIS.
|
|
|
|
good_item_options.append("Pilgrim Room - Sun Painting")
|
|
|
|
|
|
|
|
if world.options.group_doors:
|
2024-03-03 07:20:37 +00:00
|
|
|
# WELCOME BACK, CLOCKWISE, and DRAWL + RUNS.
|
|
|
|
good_item_options.append("Welcome Back Doors")
|
|
|
|
else:
|
|
|
|
# WELCOME BACK and CLOCKWISE.
|
|
|
|
good_item_options.append("Welcome Back Area - Shortcut to Starting Room")
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2024-07-26 08:53:11 +00:00
|
|
|
if world.options.group_doors:
|
2024-03-03 07:20:37 +00:00
|
|
|
# Color hallways access (NOTE: reconsider when sunwarp shuffling exists).
|
|
|
|
good_item_options.append("Rhyme Room Doors")
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2024-03-03 07:20:37 +00:00
|
|
|
# When painting shuffle is off, most Starting Room paintings give color hallways access. The Wondrous's
|
|
|
|
# painting does not, but it gives access to SHRINK and WELCOME BACK.
|
2024-03-15 08:26:00 +00:00
|
|
|
for painting_obj in PAINTINGS.values():
|
|
|
|
if not painting_obj.enter_only or painting_obj.required_door is None\
|
|
|
|
or painting_obj.room != "Starting Room":
|
2023-11-08 23:35:12 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
# If painting shuffle is on, we only want to consider paintings that actually go somewhere.
|
2024-03-03 07:20:37 +00:00
|
|
|
#
|
|
|
|
# NOTE: This does not guarantee that there will be any checks on the other side.
|
2023-11-25 12:09:08 +00:00
|
|
|
if painting_shuffle and painting_obj.id not in self.painting_mapping.keys():
|
2023-11-08 23:35:12 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
pdoor = DOORS_BY_ROOM[painting_obj.required_door.room][painting_obj.required_door.door]
|
|
|
|
good_item_options.append(pdoor.item_name)
|
|
|
|
|
|
|
|
# Copied from The Witness -- remove any plandoed items from the possible good items set.
|
|
|
|
for v in world.multiworld.plando_items[world.player]:
|
|
|
|
if v.get("from_pool", True):
|
|
|
|
for item_key in {"item", "items"}:
|
|
|
|
if item_key in v:
|
|
|
|
if type(v[item_key]) is str:
|
|
|
|
if v[item_key] in good_item_options:
|
|
|
|
good_item_options.remove(v[item_key])
|
|
|
|
elif type(v[item_key]) is dict:
|
|
|
|
for item, weight in v[item_key].items():
|
|
|
|
if weight and item in good_item_options:
|
|
|
|
good_item_options.remove(item)
|
|
|
|
else:
|
|
|
|
# Other type of iterable
|
|
|
|
for item in v[item_key]:
|
|
|
|
if item in good_item_options:
|
|
|
|
good_item_options.remove(item)
|
|
|
|
|
|
|
|
if len(good_item_options) > 0:
|
2023-11-25 12:09:08 +00:00
|
|
|
self.forced_good_item = world.random.choice(good_item_options)
|
|
|
|
self.real_items.remove(self.forced_good_item)
|
|
|
|
self.real_locations.remove("Second Room - Good Luck")
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
def randomize_paintings(self, world: "LingoWorld") -> bool:
|
2023-11-25 12:09:08 +00:00
|
|
|
self.painting_mapping.clear()
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2023-11-10 19:07:56 +00:00
|
|
|
# First, assign mappings to the required-exit paintings. We ensure that req-blocked paintings do not lead to
|
|
|
|
# required paintings.
|
|
|
|
req_exits = []
|
|
|
|
required_painting_rooms = REQUIRED_PAINTING_ROOMS
|
2024-07-26 08:53:11 +00:00
|
|
|
if world.options.shuffle_doors != ShuffleDoors.option_doors:
|
2023-11-10 19:07:56 +00:00
|
|
|
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]
|
2024-05-19 22:56:24 +00:00
|
|
|
|
|
|
|
def is_req_enterable(painting_id: str, painting: Painting) -> bool:
|
|
|
|
if painting.exit_only or painting.disable or painting.req_blocked\
|
|
|
|
or painting.room in required_painting_rooms:
|
|
|
|
return False
|
|
|
|
|
|
|
|
if world.options.shuffle_doors == ShuffleDoors.option_none:
|
|
|
|
if painting.req_blocked_when_no_doors:
|
|
|
|
return False
|
|
|
|
|
|
|
|
# Special case for the paintings in Color Hunt and Champion's Rest. These are req blocked when not on
|
|
|
|
# doors mode, and when sunwarps are disabled or sunwarp shuffle is on and the Color Hunt sunwarp is not
|
|
|
|
# an exit. This is because these two rooms would then be inaccessible without roof access, and we can't
|
|
|
|
# hide the Owl Hallway entrance behind roof access.
|
|
|
|
if painting.room in ["Color Hunt", "Champion's Rest"]:
|
|
|
|
if world.options.sunwarp_access == SunwarpAccess.option_disabled\
|
|
|
|
or (world.options.shuffle_sunwarps and "Color Hunt" not in self.sunwarp_exits):
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
req_enterable = [painting_id for painting_id, painting in PAINTINGS.items()
|
|
|
|
if is_req_enterable(painting_id, painting)]
|
2023-11-10 19:07:56 +00:00
|
|
|
req_exits += [painting_id for painting_id, painting in PAINTINGS.items()
|
|
|
|
if painting.exit_only and painting.required]
|
|
|
|
req_entrances = world.random.sample(req_enterable, len(req_exits))
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
self.painting_mapping = dict(zip(req_entrances, req_exits))
|
2023-11-10 19:07:56 +00:00
|
|
|
|
|
|
|
# Next, determine the rest of the exit paintings.
|
2023-11-08 23:35:12 +00:00
|
|
|
exitable = [painting_id for painting_id, painting in PAINTINGS.items()
|
2023-11-10 19:07:56 +00:00
|
|
|
if not painting.enter_only and not painting.disable and painting_id not in req_exits and
|
|
|
|
painting_id not in req_entrances]
|
|
|
|
nonreq_exits = world.random.sample(exitable, PAINTING_EXITS - len(req_exits))
|
|
|
|
chosen_exits = req_exits + nonreq_exits
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2023-11-10 19:07:56 +00:00
|
|
|
# Determine the rest of the entrance paintings.
|
2023-11-08 23:35:12 +00:00
|
|
|
enterable = [painting_id for painting_id, painting in PAINTINGS.items()
|
2023-11-10 19:07:56 +00:00
|
|
|
if not painting.exit_only and not painting.disable and painting_id not in chosen_exits and
|
|
|
|
painting_id not in req_entrances]
|
|
|
|
chosen_entrances = world.random.sample(enterable, PAINTING_ENTRANCES - len(req_entrances))
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2023-11-10 19:07:56 +00:00
|
|
|
# Assign one entrance to each non-required exit, to ensure that the total number of exits is achieved.
|
|
|
|
for warp_exit in nonreq_exits:
|
2023-11-08 23:35:12 +00:00
|
|
|
warp_enter = world.random.choice(chosen_entrances)
|
|
|
|
chosen_entrances.remove(warp_enter)
|
2023-11-25 12:09:08 +00:00
|
|
|
self.painting_mapping[warp_enter] = warp_exit
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2023-11-10 19:07:56 +00:00
|
|
|
# Assign each of the remaining entrances to any required or non-required exit.
|
2023-11-08 23:35:12 +00:00
|
|
|
for warp_enter in chosen_entrances:
|
|
|
|
warp_exit = world.random.choice(chosen_exits)
|
2023-11-25 12:09:08 +00:00
|
|
|
self.painting_mapping[warp_enter] = warp_exit
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
# The Eye Wall painting is unique in that it is both double-sided and also enter only (because it moves).
|
|
|
|
# There is only one eligible double-sided exit painting, which is the vanilla exit for this warp. If the
|
|
|
|
# exit painting is an entrance in the shuffle, we will disable the Eye Wall painting. Otherwise, Eye Wall
|
|
|
|
# is forced to point to the vanilla exit.
|
2023-11-25 12:09:08 +00:00
|
|
|
if "eye_painting_2" not in self.painting_mapping.keys():
|
|
|
|
self.painting_mapping["eye_painting"] = "eye_painting_2"
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
# Just for sanity's sake, ensure that all required painting rooms are accessed.
|
|
|
|
for painting_id, painting in PAINTINGS.items():
|
2023-11-25 12:09:08 +00:00
|
|
|
if painting_id not in self.painting_mapping.values() \
|
2023-11-10 19:07:56 +00:00
|
|
|
and (painting.required or (painting.required_when_no_doors and
|
2024-07-26 08:53:11 +00:00
|
|
|
world.options.shuffle_doors != ShuffleDoors.option_doors)):
|
2023-11-08 23:35:12 +00:00
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
2023-11-25 12:09:08 +00:00
|
|
|
|
|
|
|
def calculate_panel_requirements(self, room: str, panel: str, world: "LingoWorld"):
|
|
|
|
"""
|
|
|
|
Calculate and return the access requirements for solving a given panel. The goal is to eliminate recursion in
|
|
|
|
the access rule function by collecting the rooms, doors, and colors needed by this panel and any panel required
|
|
|
|
by this panel. Memoization is used so that no panel is evaluated more than once.
|
|
|
|
"""
|
|
|
|
if panel not in self.panel_reqs.setdefault(room, {}):
|
|
|
|
access_reqs = AccessRequirements()
|
|
|
|
panel_object = PANELS_BY_ROOM[room][panel]
|
|
|
|
|
2024-07-26 08:53:11 +00:00
|
|
|
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)
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
for req_room in panel_object.required_rooms:
|
|
|
|
access_reqs.rooms.add(req_room)
|
|
|
|
|
|
|
|
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]
|
2024-07-26 08:53:11 +00:00
|
|
|
if door_object.event or world.options.shuffle_doors != ShuffleDoors.option_doors:
|
2023-11-25 12:09:08 +00:00
|
|
|
sub_access_reqs = self.calculate_door_requirements(
|
|
|
|
room if req_door.room is None else req_door.room, req_door.door, world)
|
|
|
|
access_reqs.merge(sub_access_reqs)
|
|
|
|
else:
|
|
|
|
access_reqs.doors.add(RoomAndDoor(room if req_door.room is None else req_door.room, req_door.door))
|
|
|
|
|
|
|
|
for color in panel_object.colors:
|
|
|
|
access_reqs.colors.add(color)
|
|
|
|
|
|
|
|
for req_panel in panel_object.required_panels:
|
|
|
|
if req_panel.room is not None and req_panel.room != room:
|
|
|
|
access_reqs.rooms.add(req_panel.room)
|
|
|
|
|
|
|
|
sub_access_reqs = self.calculate_panel_requirements(room if req_panel.room is None else req_panel.room,
|
|
|
|
req_panel.panel, world)
|
|
|
|
access_reqs.merge(sub_access_reqs)
|
|
|
|
|
2024-06-03 08:51:27 +00:00
|
|
|
if panel == "THE MASTER":
|
|
|
|
access_reqs.the_master = True
|
|
|
|
|
2024-07-24 12:34:51 +00:00
|
|
|
# Evil python magic (so sayeth NewSoupVi): this checks victory_condition against the panel's location name
|
|
|
|
# override if it exists, or the auto-generated location name if it's None.
|
|
|
|
if self.victory_condition == (panel_object.location_name or f"{room} - {panel}"):
|
|
|
|
access_reqs.postgame = True
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
self.panel_reqs[room][panel] = access_reqs
|
|
|
|
|
|
|
|
return self.panel_reqs[room][panel]
|
|
|
|
|
|
|
|
def calculate_door_requirements(self, room: str, door: str, world: "LingoWorld"):
|
|
|
|
"""
|
|
|
|
Similar to calculate_panel_requirements, but for event doors.
|
|
|
|
"""
|
|
|
|
if door not in self.door_reqs.setdefault(room, {}):
|
|
|
|
access_reqs = AccessRequirements()
|
|
|
|
door_object = DOORS_BY_ROOM[room][door]
|
|
|
|
|
|
|
|
for req_panel in door_object.panels:
|
Lingo: Fix entrance checking being broken on default settings (#2506)
The most serious issue this PR addresses is that entrances that use doors without items (a small subset of doors when door shuffle is on, but *every* door when door shuffle is off, which is the default) underestimate the requirements needed to use that entrance. The logic would calculate the panels needed to open the door, but would neglect to keep track of the rooms those panels were in, meaning that doors would be considered openable if you had the colors needed to solve a panel that's in a room you have no access to.
Another issue is that, previously, logic would always consider the "ANOTHER TRY" panel accessible for the purposes of the LEVEL 2 panel hunt. This could result in seeds where the player is expected to have exactly the correct number of solves to reach LEVEL 2, but in reality is short by one because ANOTHER TRY itself is not revealed until the panel hunt is complete. This change marks ANOTHER TRY as non-counting, because even though it is technically a counting panel in-game, it can never contribute to the LEVEL 2 panel hunt. This issue could also apply to THE MASTER, since it is the only other counting panel with special access rules, although it is much less likely. This change adds special handling for counting THE MASTER. These issues were possible to manifest whenever the LEVEL 2 panel hunt was enabled, which it is by default.
Smaller logic issues also fixed in this PR:
* The Orange Tower Basement MASTERY panel was marked as requiring the mastery doors to be opened, when it was actually possible to get it without them by using a painting to get into the room.
* The Pilgrim Room painting item was incorrectly being marked as a filler item, despite it being progression.
* There has been another update to the game that adds connections between areas that were previously not connected. These changes were additive, which is why they are not critical.
* The panel stacks in the rhyme room now require both colours on each panel.
2023-12-10 18:15:42 +00:00
|
|
|
panel_room = room if req_panel.room is None else req_panel.room
|
|
|
|
access_reqs.rooms.add(panel_room)
|
|
|
|
sub_access_reqs = self.calculate_panel_requirements(panel_room, req_panel.panel, world)
|
2023-11-25 12:09:08 +00:00
|
|
|
access_reqs.merge(sub_access_reqs)
|
|
|
|
|
|
|
|
self.door_reqs[room][door] = access_reqs
|
|
|
|
|
|
|
|
return self.door_reqs[room][door]
|
|
|
|
|
|
|
|
def create_panel_hunt_events(self, world: "LingoWorld"):
|
|
|
|
"""
|
|
|
|
Creates the event locations/items used for determining access to the LEVEL 2 panel. Instead of creating an event
|
|
|
|
for every single counting panel in the game, we try to coalesce panels with identical access rules into the same
|
|
|
|
event. Right now, this means the following:
|
|
|
|
|
|
|
|
When color shuffle is off, panels in a room with no extra access requirements (room, door, or other panel) are
|
|
|
|
all coalesced into one event.
|
|
|
|
|
|
|
|
When color shuffle is on, single-colored panels (including white) in a room are combined into one event per
|
|
|
|
color. Multicolored panels and panels with any extra access requirements are not coalesced, and will each
|
|
|
|
receive their own event.
|
|
|
|
"""
|
|
|
|
for room_name, room_data in PANELS_BY_ROOM.items():
|
|
|
|
unhindered_panels_by_color: dict[Optional[str], int] = {}
|
|
|
|
|
|
|
|
for panel_name, panel_data in room_data.items():
|
2024-06-03 08:51:27 +00:00
|
|
|
# We won't count non-counting panels.
|
|
|
|
if panel_data.non_counting:
|
2023-11-25 12:09:08 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
# We won't coalesce any panels that have requirements beyond colors. To simplify things for now, we will
|
2024-07-26 08:53:11 +00:00
|
|
|
# only coalesce single-color panels. Chains/stacks/combo puzzles will be separate. Panel door locked
|
|
|
|
# puzzles will be separate if panels mode is on. THE MASTER has special access rules and is handled
|
|
|
|
# separately.
|
2023-11-25 12:09:08 +00:00
|
|
|
if len(panel_data.required_panels) > 0 or len(panel_data.required_doors) > 0\
|
|
|
|
or len(panel_data.required_rooms) > 0\
|
2024-06-03 08:51:27 +00:00
|
|
|
or (world.options.shuffle_colors and len(panel_data.colors) > 1)\
|
2024-07-26 08:53:11 +00:00
|
|
|
or (world.options.shuffle_doors == ShuffleDoors.option_panels
|
|
|
|
and panel_data.panel_door is not None)\
|
2024-06-03 08:51:27 +00:00
|
|
|
or panel_name == "THE MASTER":
|
2023-11-25 12:09:08 +00:00
|
|
|
self.counting_panel_reqs.setdefault(room_name, []).append(
|
|
|
|
(self.calculate_panel_requirements(room_name, panel_name, world), 1))
|
|
|
|
else:
|
|
|
|
if len(panel_data.colors) == 0 or not world.options.shuffle_colors:
|
|
|
|
color = None
|
|
|
|
else:
|
|
|
|
color = panel_data.colors[0]
|
|
|
|
|
|
|
|
unhindered_panels_by_color[color] = unhindered_panels_by_color.get(color, 0) + 1
|
|
|
|
|
|
|
|
for color, panel_count in unhindered_panels_by_color.items():
|
|
|
|
access_reqs = AccessRequirements()
|
|
|
|
if color is not None:
|
|
|
|
access_reqs.colors.add(color)
|
|
|
|
|
|
|
|
self.counting_panel_reqs.setdefault(room_name, []).append((access_reqs, panel_count))
|