From 44d2d6811a4911bcbd173b0cdc19c93472ecba6b Mon Sep 17 00:00:00 2001 From: Miepee Date: Fri, 3 Oct 2025 10:50:43 +0200 Subject: [PATCH 1/3] Fusion: Support shuffling Open Hatch type --- src/mars_patcher/mf/door_locks.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/mars_patcher/mf/door_locks.py b/src/mars_patcher/mf/door_locks.py index 36d3f9d..4f78039 100644 --- a/src/mars_patcher/mf/door_locks.py +++ b/src/mars_patcher/mf/door_locks.py @@ -66,6 +66,11 @@ 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. } HatchSlot = Annotated[int, "0 <= value <= 5"] @@ -108,10 +113,11 @@ 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 = 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 @@ -119,14 +125,23 @@ def factory() -> dict: 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 not (3 <= door_type <= 4): # 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 == 3): + 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 == 3: + upper_bytes = door_properties & 0xF0 + door_properties = upper_bytes + 4 + door_type = 4 + rom.write_8(door_addr, door_properties) + # Load room's BG1 and clipdata if not already loaded area_room = (area, room) room_entry = loaded_rooms.get(area_room) From 4e11ca2f865d3604c10b7d0ddca2917d68de1fb3 Mon Sep 17 00:00:00 2001 From: Miepee Date: Mon, 6 Oct 2025 20:56:19 +0200 Subject: [PATCH 2/3] also exclude cathedral <-> c. save access --- src/mars_patcher/mf/door_locks.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/mars_patcher/mf/door_locks.py b/src/mars_patcher/mf/door_locks.py index 4f78039..293aa0a 100644 --- a/src/mars_patcher/mf/door_locks.py +++ b/src/mars_patcher/mf/door_locks.py @@ -71,6 +71,14 @@ class HatchLock(Enum): 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"] From 5de00155d3726455f6c33234a7c8ac4e7ec1fb90 Mon Sep 17 00:00:00 2001 From: Miepee Date: Tue, 7 Oct 2025 18:42:10 +0200 Subject: [PATCH 3/3] Address review commments --- src/mars_patcher/constants/door_types.py | 13 +++++++++++++ src/mars_patcher/mf/door_locks.py | 20 +++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 src/mars_patcher/constants/door_types.py diff --git a/src/mars_patcher/constants/door_types.py b/src/mars_patcher/constants/door_types.py new file mode 100644 index 0000000..32dca3f --- /dev/null +++ b/src/mars_patcher/constants/door_types.py @@ -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.""" diff --git a/src/mars_patcher/mf/door_locks.py b/src/mars_patcher/mf/door_locks.py index 293aa0a..474cbff 100644 --- a/src/mars_patcher/mf/door_locks.py +++ b/src/mars_patcher/mf/door_locks.py @@ -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 from mars_patcher.mf.auto_generated_types import MarsschemamfDoorlocksItem from mars_patcher.mf.constants.game_data import hatch_lock_event_count, hatch_lock_events @@ -122,7 +123,7 @@ def factory() -> dict: for door in range(256): door_addr = area_addr + door * 0xC door_properties = rom.read_8(door_addr) - door_type = door_properties & 0xF + door_type = DoorType(door_properties & 0xF) # Check if at end of list if door_properties == 0: @@ -135,20 +136,25 @@ def factory() -> dict: # Skip excluded doors and doors that aren't lockable/open hatches lock = door_locks.get((area, door)) - if (area, door) in EXCLUDED_DOORS or not (3 <= door_type <= 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 == 3): + 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 == 3: - upper_bytes = door_properties & 0xF0 - door_properties = upper_bytes + 4 - door_type = 4 + 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)