2023-11-08 23:35:12 +00:00
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
|
|
|
|
from BaseClasses import CollectionState
|
2024-03-15 08:26:00 +00:00
|
|
|
from .datatypes import RoomAndDoor
|
2023-11-25 12:09:08 +00:00
|
|
|
from .player_logic import AccessRequirements, LingoPlayerLogic, PlayerLocation
|
2024-03-15 08:26:00 +00:00
|
|
|
from .static_logic import PROGRESSION_BY_ROOM, PROGRESSIVE_ITEMS
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
if TYPE_CHECKING:
|
|
|
|
from . import LingoWorld
|
|
|
|
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
def lingo_can_use_entrance(state: CollectionState, room: str, door: RoomAndDoor, world: "LingoWorld",
|
2023-11-08 23:35:12 +00:00
|
|
|
player_logic: LingoPlayerLogic):
|
|
|
|
if door is None:
|
|
|
|
return True
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
effective_room = room if door.room is None else door.room
|
|
|
|
return _lingo_can_open_door(state, effective_room, door.door, world, player_logic)
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
def lingo_can_use_location(state: CollectionState, location: PlayerLocation, world: "LingoWorld",
|
2023-11-08 23:35:12 +00:00
|
|
|
player_logic: LingoPlayerLogic):
|
2023-11-25 12:09:08 +00:00
|
|
|
return _lingo_can_satisfy_requirements(state, location.access, world, player_logic)
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
def lingo_can_use_mastery_location(state: CollectionState, world: "LingoWorld", player_logic: LingoPlayerLogic):
|
|
|
|
satisfied_count = 0
|
|
|
|
for access_req in player_logic.mastery_reqs:
|
|
|
|
if _lingo_can_satisfy_requirements(state, access_req, world, player_logic):
|
|
|
|
satisfied_count += 1
|
|
|
|
return satisfied_count >= world.options.mastery_achievements.value
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
def lingo_can_use_level_2_location(state: CollectionState, world: "LingoWorld", player_logic: LingoPlayerLogic):
|
|
|
|
counted_panels = 0
|
|
|
|
state.update_reachable_regions(world.player)
|
|
|
|
for region in state.reachable_regions[world.player]:
|
|
|
|
for access_req, panel_count in player_logic.counting_panel_reqs.get(region.name, []):
|
|
|
|
if _lingo_can_satisfy_requirements(state, access_req, world, player_logic):
|
|
|
|
counted_panels += panel_count
|
|
|
|
if counted_panels >= world.options.level_2_requirement.value - 1:
|
|
|
|
return True
|
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
|
|
|
# THE MASTER has to be handled separately, because it has special access rules.
|
|
|
|
if state.can_reach("Orange Tower Seventh Floor", "Region", world.player)\
|
|
|
|
and lingo_can_use_mastery_location(state, world, player_logic):
|
|
|
|
counted_panels += 1
|
|
|
|
if counted_panels >= world.options.level_2_requirement.value - 1:
|
|
|
|
return True
|
2023-11-25 12:09:08 +00:00
|
|
|
return False
|
2023-11-08 23:35:12 +00:00
|
|
|
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
def _lingo_can_satisfy_requirements(state: CollectionState, access: AccessRequirements, world: "LingoWorld",
|
|
|
|
player_logic: LingoPlayerLogic):
|
|
|
|
for req_room in access.rooms:
|
2023-11-10 19:19:05 +00:00
|
|
|
if not state.can_reach(req_room, "Region", world.player):
|
2023-11-08 23:35:12 +00:00
|
|
|
return False
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
for req_door in access.doors:
|
|
|
|
if not _lingo_can_open_door(state, req_door.room, req_door.door, world, player_logic):
|
2023-11-08 23:35:12 +00:00
|
|
|
return False
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
if len(access.colors) > 0 and world.options.shuffle_colors:
|
|
|
|
for color in access.colors:
|
2023-11-08 23:35:12 +00:00
|
|
|
if not state.has(color.capitalize(), world.player):
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
def _lingo_can_open_door(state: CollectionState, room: str, door: str, world: "LingoWorld",
|
|
|
|
player_logic: LingoPlayerLogic):
|
|
|
|
"""
|
|
|
|
Determines whether a door can be opened
|
|
|
|
"""
|
|
|
|
if door not in player_logic.item_by_door.get(room, {}):
|
|
|
|
return _lingo_can_satisfy_requirements(state, player_logic.door_reqs[room][door], world, player_logic)
|
|
|
|
|
|
|
|
item_name = player_logic.item_by_door[room][door]
|
|
|
|
if item_name in PROGRESSIVE_ITEMS:
|
|
|
|
progression = PROGRESSION_BY_ROOM[room][door]
|
|
|
|
return state.has(item_name, world.player, progression.index)
|
|
|
|
|
|
|
|
return state.has(item_name, world.player)
|
|
|
|
|
|
|
|
|
|
|
|
def make_location_lambda(location: PlayerLocation, world: "LingoWorld", player_logic: LingoPlayerLogic):
|
|
|
|
if location.name == player_logic.mastery_location:
|
|
|
|
return lambda state: lingo_can_use_mastery_location(state, world, player_logic)
|
|
|
|
|
|
|
|
if world.options.level_2_requirement > 1\
|
|
|
|
and (location.name == "Second Room - ANOTHER TRY" or location.name == player_logic.level_2_location):
|
|
|
|
return lambda state: lingo_can_use_level_2_location(state, world, player_logic)
|
2023-11-08 23:35:12 +00:00
|
|
|
|
2023-11-25 12:09:08 +00:00
|
|
|
return lambda state: lingo_can_use_location(state, location, world, player_logic)
|