Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/mars_patcher/constants/door_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from enum import IntEnum, auto


class DoorType(IntEnum):
AREA_CONNECTION = 1
NO_HATCH = auto()
OPEN_HATCH = auto()
LOCKABLE_HATCH = auto()

REMOVE_MOTHERSHIP = auto()
"""Zero Mission only."""
SET_MOTHERSHIP = auto()
"""Zero Mission only."""
41 changes: 35 additions & 6 deletions src/mars_patcher/mf/door_locks.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from typing import Annotated, TypedDict

from mars_patcher.common_types import AreaId, AreaRoomPair, RoomId
from mars_patcher.constants.door_types import DoorType
from mars_patcher.constants.game_data import area_doors_ptrs, minimap_graphics
from mars_patcher.constants.minimap_tiles import ColoredDoor, Content, Edge
from mars_patcher.mf.auto_generated_types import MarsschemamfDoorlocksItem
Expand Down Expand Up @@ -68,6 +69,19 @@ class HatchLock(Enum):

EXCLUDED_DOORS = {
(0, 0xB4), # Restricted lab escape
(2, 0x71), # Cathedral -> Ripper Tower. Excluded to prevent more than 6 hatches in that room.
(
5,
0x38,
), # Arctic Containment -> Ripper Road. Excluded to prevent more than 6 hatches in that room.
(
2,
0x1D,
), # Cathedral (Before Destruction) -> C. Save Access. Excluded to prevent more than 6 hatches.
(
2,
0x69,
), # Cathedral (After Destruction) -> C. Save Access. Excluded to prevent more than 6 hatches.
}

HatchSlot = Annotated[int, "0 <= value <= 5"]
Expand Down Expand Up @@ -110,25 +124,40 @@ def factory() -> dict:
area_addr = rom.read_ptr(doors_ptrs + area * 4)
for door in range(256):
door_addr = area_addr + door * 0xC
door_type = rom.read_8(door_addr)
door_properties = rom.read_8(door_addr)
door_type = DoorType(door_properties & 0xF)

# Check if at end of list
if door_type == 0:
if door_properties == 0:
break

# Skip doors that mage marks as deleted
room = rom.read_8(door_addr + 1)
if room == 0xFF:
continue

# Skip excluded doors and doors that aren't lockable hatches
# Skip excluded doors and doors that aren't lockable/open hatches
lock = door_locks.get((area, door))
if (area, door) in EXCLUDED_DOORS or door_type & 0xF != 4:
if (area, door) in EXCLUDED_DOORS or door_type not in [
DoorType.OPEN_HATCH,
DoorType.LOCKABLE_HATCH,
]:
# Don't log the error if door is open and JSON says to change to open.
if lock is not None and not (lock is HatchLock.OPEN and door_type & 0xF == 3):
logging.error(f"Area {area} door {door} cannot have its lock changed")
if lock is not None and not (
lock is HatchLock.OPEN and door_type == DoorType.OPEN_HATCH
):
logging.error(
f"Area {area} door {door} type {door_type} cannot have its lock changed"
)
continue

# If the door type is an "Open Hatch" door, modify it to a lockable one
if door_type == DoorType.OPEN_HATCH:
upper_bits = door_properties & 0xF0
door_properties = upper_bits | 4
rom.write_8(door_addr, door_properties)
door_type = DoorType.LOCKABLE_HATCH

# Load room's BG1 and clipdata if not already loaded
area_room = (area, room)
room_entry = loaded_rooms.get(area_room)
Expand Down