6#include "absl/strings/str_format.h"
42 const int room_base_x = (room_id & 0x0F) * 0x200;
43 const int room_base_y = (room_id >> 4) * 0x200;
45 const int camera_x = std::clamp(AlignDown8(
static_cast<int>(player_x) - 0x78),
46 room_base_x, room_base_x + 0x100);
47 const int camera_y = std::clamp(AlignDown8(
static_cast<int>(player_y) - 0x68),
48 room_base_y + 0x10, room_base_y + 0x110);
50 const int page_x = camera_x >> 8;
51 const bool right_half = camera_x - room_base_x >= 0x100;
52 const int page_y = camera_y >> 8;
53 const bool lower_half = camera_y - room_base_y >= 0x100;
56 derived.
camera_x =
static_cast<uint16_t
>(camera_x);
57 derived.
camera_y =
static_cast<uint16_t
>(camera_y);
58 derived.
trigger_x =
static_cast<uint16_t
>((camera_x - room_base_x) + 0x7F);
59 derived.
trigger_y =
static_cast<uint16_t
>((camera_y - room_base_y) + 0x77);
61 static_cast<uint8_t
>(page_y),
62 static_cast<uint8_t
>(lower_half ? page_y - 1 : page_y),
63 static_cast<uint8_t
>(page_y),
64 static_cast<uint8_t
>(lower_half ? page_y : page_y + 1),
65 static_cast<uint8_t
>(page_x),
66 static_cast<uint8_t
>(right_half ? page_x - 1 : page_x),
67 static_cast<uint8_t
>(page_x),
68 static_cast<uint8_t
>(right_half ? page_x : page_x + 1),
70 const int local_x =
static_cast<int>(player_x) - room_base_x;
71 const int local_y =
static_cast<int>(player_y) - room_base_y;
72 derived.
quadrant =
static_cast<uint8_t
>((local_x >= 0x100 ? 0x10 : 0) |
73 (local_y >= 0x100 ? 0x02 : 0));
83 validation.
errors.push_back(absl::StrFormat(
84 "Room 0x%X is outside the dungeon room table.", state.
room_id));
88 const int room_base_x = (state.
room_id & 0x0F) * 0x200;
89 const int room_base_y = (state.
room_id >> 4) * 0x200;
92 if (player_x < room_base_x || player_x > room_base_x + 0x1FF) {
94 validation.
errors.push_back(absl::StrFormat(
95 "Player X 0x%04X is outside room X range 0x%04X-0x%04X.", player_x,
96 room_base_x, room_base_x + 0x1FF));
98 if (player_y < room_base_y || player_y > room_base_y + 0x1FF) {
100 validation.
errors.push_back(absl::StrFormat(
101 "Player Y 0x%04X is outside room Y range 0x%04X-0x%04X.", player_y,
102 room_base_y, room_base_y + 0x1FF));
106 validation.
errors.push_back(
107 absl::StrFormat(
"Camera X 0x%04X is outside room range 0x%04X-0x%04X.",
108 state.
camera_x, room_base_x, room_base_x + 0x100));
110 if (state.
camera_y < room_base_y + 0x10 ||
111 state.
camera_y > room_base_y + 0x110) {
112 validation.
errors.push_back(absl::StrFormat(
113 "Camera Y 0x%04X is outside room range 0x%04X-0x%04X.", state.
camera_y,
114 room_base_y + 0x10, room_base_y + 0x110));
117 validation.
errors.push_back(
118 "Camera coordinates must be aligned to an 8-pixel boundary.");
121 validation.
errors.push_back(absl::StrFormat(
122 "Camera trigger X 0x%04X is outside safe range 0x007F-0x017F.",
126 validation.
errors.push_back(absl::StrFormat(
127 "Camera trigger Y 0x%04X is outside safe range 0x0087-0x0187.",
130 for (
size_t index = 0; index < 4; ++index) {
132 validation.
errors.push_back(
133 absl::StrFormat(
"Vertical boundary %zu (0x%02X) exceeds page 0x25.",
137 for (
size_t index = 4; index < state.
boundaries.size(); ++index) {
139 validation.
errors.push_back(
140 absl::StrFormat(
"Horizontal boundary %zu (0x%02X) exceeds page 0x1F.",
151 "Camera scroll differs (current %04X,%04X; derived %04X,%04X).",
159 "Camera triggers differ (current %04X,%04X; derived %04X,%04X).",
166 "Camera boundary pages differ from the player-derived values.");
172 state.
room_id == kSpecialQuadrantRoom
173 ?
"Quadrant differs from the ordinary-room formula; room 0x104 "
174 "is a known vanilla exception and will be preserved."
175 : absl::StrFormat(
"Quadrant differs (current %02X; derived %02X).",
186 repaired.
camera_x = derived.camera_x;
187 repaired.
camera_y = derived.camera_y;
191 if (state.
room_id != kSpecialQuadrantRoom) {
192 repaired.
quadrant = derived.quadrant;
201 .room_id = entrance.
room_,
214 .dirty = entrance.
dirty(),
231 .dirty = spawn.
dirty(),
237 if (entrance ==
nullptr) {
253 RestoreDirtyState(state.
dirty, entrance);
258 if (spawn ==
nullptr) {
267 RestoreDirtyState(state.
dirty, spawn);
uint16_t camera_trigger_x
std::array< uint8_t, 8 > camera_scroll_boundaries
uint16_t horizontal_scroll
uint16_t camera_trigger_y
Dungeon Room Entrance or Spawn Point.
uint8_t camera_boundary_fw_
uint8_t camera_boundary_qe_
uint8_t camera_boundary_fe_
uint8_t camera_boundary_fs_
uint8_t camera_boundary_qs_
uint8_t camera_boundary_qw_
uint16_t camera_trigger_y_
uint8_t camera_boundary_fn_
uint16_t camera_trigger_x_
uint8_t camera_boundary_qn_
void RestoreDirtyState(bool dirty, zelda3::RoomEntrance *entrance)
int AlignDown8(int value)
constexpr int kSpecialQuadrantRoom
Editors are the view controllers for the application.
DungeonEntranceCameraState CaptureDungeonSpawnCamera(const zelda3::DungeonSpawnPoint &spawn)
DungeonEntranceCameraState BuildRepairedDungeonEntranceCamera(const DungeonEntranceCameraState &state)
DungeonEntranceCameraDerived DeriveDungeonEntranceCamera(int room_id, uint16_t player_x, uint16_t player_y)
void ApplyDungeonSpawnCameraState(const DungeonEntranceCameraState &state, zelda3::DungeonSpawnPoint *spawn)
DungeonEntranceCameraValidation ValidateDungeonEntranceCamera(const DungeonEntranceCameraState &state)
DungeonEntranceCameraState CaptureDungeonEntranceCamera(const zelda3::RoomEntrance &entrance)
void ApplyDungeonEntranceCameraState(const DungeonEntranceCameraState &state, zelda3::RoomEntrance *entrance)
constexpr int kRoomCensusRoomCount
std::array< uint8_t, 8 > boundaries
DungeonEntranceRecordKind kind
std::array< uint8_t, 8 > boundaries
std::vector< std::string > differences
bool has_repairable_difference
bool quadrant_repair_safe
std::vector< std::string > errors
DungeonEntranceCameraDerived expected