5#include "absl/status/status.h"
6#include "absl/strings/str_format.h"
18 return type == DoorType::NormalDoor || type == DoorType::NormalDoorLower;
26 case DoorDirection::North:
27 case DoorDirection::West:
29 case DoorDirection::South:
30 case DoorDirection::East:
48 const auto direction =
49 static_cast<DoorDirection
>(
static_cast<unsigned>(source.
direction) ^ 1);
50 const uint8_t position =
52 const auto [byte1, byte2] =
54 return Door::FromRomBytes(byte1, byte2);
58 if (door.
type != type) {
60 door.
byte2 =
static_cast<uint8_t
>(type);
67 const std::vector<Door>& second) {
68 if (first.size() != second.size()) {
71 for (
size_t i = 0; i < first.size(); ++i) {
72 const auto& a = first[i];
73 const auto& b = second[i];
74 if (a.position != b.position || a.type != b.type ||
75 a.direction != b.direction || a.byte1 != b.byte1 ||
91 return absl::InvalidArgumentError(
"Source room is outside the room table");
93 if (
static_cast<unsigned>(door.direction) > 3 || door.position >= 12) {
94 return absl::InvalidArgumentError(
"Door has an invalid direction or slot");
96 if (!IsOrdinaryDoor(door.type)) {
97 return absl::FailedPreconditionError(
98 "Reciprocal authoring supports normal upper or lower doors only");
100 if (!IsOuterDoor(door)) {
101 return absl::FailedPreconditionError(
102 "This door is on an internal room seam, not an adjacent-room wall");
108 const int column = source_room_id & 0x0F;
109 const int row = (source_room_id & 0xFF) >> 4;
110 int target_room_id = -1;
111 switch (door.direction) {
112 case DoorDirection::North:
114 target_room_id = source_room_id - 16;
117 case DoorDirection::South:
119 target_room_id = source_room_id + 16;
122 case DoorDirection::West:
124 target_room_id = source_room_id - 1;
127 case DoorDirection::East:
129 target_room_id = source_room_id + 1;
134 return absl::FailedPreconditionError(
135 "No adjacent room exists at this room-table boundary");
137 return target_room_id;
144 return absl::InvalidArgumentError(
"Selected source room changed");
148 return absl::InvalidArgumentError(
"Invalid connection layer");
150 const auto& source_doors = source.
GetDoors();
152 return absl::InvalidArgumentError(
"Selected source door no longer exists");
157 if (target.
id() != target_room_id || source.
rom() != target.
rom()) {
158 return absl::InvalidArgumentError(
159 "Target must be the adjacent room in the same ROM");
161 for (
size_t i = 0; i < source_doors.size(); ++i) {
163 SharesOuterLane(source_door, source_doors[i])) {
164 return absl::FailedPreconditionError(
165 "Source passage contains another door or control marker");
170 ? DoorType::NormalDoor
171 : DoorType::NormalDoorLower;
172 const Door return_door = ReturnDoor(source_door, type);
173 const auto& target_doors = target.
GetDoors();
174 std::optional<size_t> target_index;
175 for (
size_t i = 0; i < target_doors.size(); ++i) {
176 if (!SharesOuterLane(return_door, target_doors[i])) {
179 if (target_index || target_doors[i].position != return_door.position ||
180 !IsOrdinaryDoor(target_doors[i].type)) {
181 return absl::FailedPreconditionError(
182 "Return passage contains conflicting doors or control markers");
186 const bool creates_return = !target_index.has_value();
187 if (creates_return &&
190 return absl::ResourceExhaustedError(absl::StrFormat(
191 "Room 0x%03X has no free door slot (maximum %d)", target_room_id,
206 if (creates_return) {
static std::pair< uint8_t, uint8_t > EncodeDoorBytes(uint8_t position, DoorType type, DoorDirection direction)
Encode door data for ROM storage.
const std::vector< Door > & GetDoors() const
#define ASSIGN_OR_RETURN(type_variable_name, expression)
bool IsOrdinaryDoor(DoorType type)
Door ReturnDoor(const Door &source, DoorType type)
bool IsOuterDoor(const Door &door)
void SetLayer(Door &door, DoorType type)
bool SharesOuterLane(const Door &first, const Door &second)
Editors are the view controllers for the application.
bool SameDungeonDoors(const std::vector< Door > &first, const std::vector< Door > &second)
absl::StatusOr< int > DungeonConnectionTargetRoom(int source_room_id, const Door &door)
absl::StatusOr< DungeonConnectionPlan > PlanDungeonDoorConnection(const zelda3::Room &source, const zelda3::Room &target, const DungeonConnectionRequest &request)
DoorType
Door types from ALTTP.
constexpr int GetDungeonLimitMax(DungeonLimit limit)
constexpr int kNumberOfRooms
DoorDirection
Door direction on room walls.
std::vector< zelda3::Room::Door > target_after
DungeonConnectionRequest request
std::vector< zelda3::Room::Door > target_before
std::vector< zelda3::Room::Door > source_before
std::vector< zelda3::Room::Door > source_after
DungeonConnectionLayer layer
Represents a door in a dungeon room.
DoorType type
Door type (determines appearance/behavior)
DoorDirection direction
Which wall the door is on.
uint8_t position
Encoded position (5-bit, 0-31)
uint8_t byte2
Original ROM byte 2 (type + direction)