yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
room_entrance.h
Go to the documentation of this file.
1#ifndef YAZE_APP_ZELDA3_DUNGEON_ROOM_ENTRANCE_H
2#define YAZE_APP_ZELDA3_DUNGEON_ROOM_ENTRANCE_H
3
4#include <array>
5#include <cstddef>
6#include <cstdint>
7#include <optional>
8#include <utility>
9#include <vector>
10
11#include "absl/status/status.h"
12#include "absl/strings/str_format.h"
13#include "rom/rom.h"
14#include "util/macro.h"
18
19namespace yaze {
20namespace zelda3 {
21
22// 0x14577 word value for each room
23constexpr int kEntranceRoom = 0x14813;
24
25// 8 bytes per room, HU, FU, HD, FD, HL, FL, HR, FR
26constexpr int kEntranceScrollEdge = 0x1491D; // 0x14681
27// Game loader: $02D9AB -> vertical $E8/$E6; $02D9B8 -> horizontal $E2/$E0.
28constexpr int kEntranceYScroll = 0x14E4F; // 2 bytes each entrance
29constexpr int kEntranceXScroll = 0x14D45; // 2 bytes each entrance
30constexpr int kEntranceYPosition = 0x14F59; // 0x14CBD 2bytes
31constexpr int kEntranceXPosition = 0x15063; // 0x14DC7 2bytes
32constexpr int kEntranceCameraYTrigger = 0x1516D; // 0x14ED1 2bytes
33constexpr int kEntranceCameraXTrigger = 0x15277; // 0x14FDB 2bytes
34
35constexpr int kEntranceBlockset = 0x15381; // 0x150E5 1byte
36constexpr int kEntranceFloor = 0x15406; // 0x1516A 1byte
37constexpr int kEntranceDungeon = 0x1548B; // 0x151EF 1byte (dungeon id)
38constexpr int kEntranceDoor = 0x15510; // 0x15274 1byte
39
40// 1 byte, ---b ---a b = bg2, a = need to check
41constexpr int kEntranceLadderBG = 0x15595; // 0x152F9
42constexpr int kEntrancescrolling = 0x1561A; // 0x1537E 1byte --h- --v-
43constexpr int kEntranceScrollQuadrant = 0x1569F; // 0x15403 1byte
44constexpr int kEntranceExit = 0x15724; // 0x15488 2byte word
45constexpr int kEntranceMusic = 0x1582E; // 0x15592
46
47using DungeonEntranceWriteRange = std::pair<uint32_t, uint32_t>;
48
49// One regular entrance is stored as 17 discontiguous records: eight words,
50// eight scalar bytes, and one eight-byte camera-boundary record. Keep this
51// layout shared by save validation, manifest preflight, and write prediction so
52// those safety surfaces cannot drift apart.
53inline std::vector<DungeonEntranceWriteRange> RegularDungeonEntranceWriteRanges(
54 const EntranceLayout& layout, int entrance_id) {
55 if (entrance_id < 0 || entrance_id >= kNumRegularDungeonEntrances) {
56 return {};
57 }
58 std::vector<DungeonEntranceWriteRange> ranges;
59 ranges.reserve(layout.tables.size());
60 for (const auto& [table_pc, record_width] : layout.tables) {
61 const uint32_t begin =
62 table_pc + static_cast<uint32_t>(entrance_id) * record_width;
63 ranges.emplace_back(begin, begin + record_width);
64 }
65 return ranges;
66}
67
68inline absl::StatusOr<std::vector<DungeonEntranceWriteRange>>
69RegularDungeonEntranceWriteRanges(const Rom& rom, int entrance_id) {
71 if (entrance_id < 0 || entrance_id >= kNumRegularDungeonEntrances) {
72 return absl::OutOfRangeError("Regular dungeon entrance ID is out of range");
73 }
74 return RegularDungeonEntranceWriteRanges(layout, entrance_id);
75}
76
77class RoomEntrance;
78
79absl::Status ValidateRegularDungeonEntranceForSave(const Rom& rom,
80 const RoomEntrance& entrance,
81 int entrance_id);
82
83constexpr int items_data_start = 0xDDE9; // save purpose
84constexpr int items_data_end = 0xE6B2; // save purpose
85constexpr int initial_equipement = 0x271A6;
86
87// item id you get instead if you already have that item
88constexpr int chests_backupitems = 0x3B528;
89constexpr int chests_yoffset = 0x4836C;
90constexpr int chests_xoffset = 0x4836C + (76 * 1);
91constexpr int chests_itemsgfx = 0x4836C + (76 * 2);
92constexpr int chests_itemswide = 0x4836C + (76 * 3);
93constexpr int chests_itemsproperties = 0x4836C + (76 * 4);
94constexpr int chests_sramaddress = 0x4836C + (76 * 5);
95constexpr int chests_sramvalue = 0x4836C + (76 * 7);
96constexpr int chests_msgid = 0x442DD;
97
98constexpr int dungeons_startrooms = 0x7939;
99constexpr int dungeons_endrooms = 0x792D;
100constexpr int dungeons_bossrooms = 0x10954; // short value
101
102// Bed Related Values (Starting location)
103constexpr int bedPositionX = 0x039A37; // short value
104constexpr int bedPositionY = 0x039A32; // short value
105
106// short value (on 2 different bytes)
107constexpr int bedPositionResetXLow = 0x02DE53;
108constexpr int bedPositionResetXHigh = 0x02DE58;
109
110// short value (on 2 different bytes)
111constexpr int bedPositionResetYLow = 0x02DE5D;
112constexpr int bedPositionResetYHigh = 0x02DE62;
113
114constexpr int bedSheetPositionX = 0x0480BD; // short value
115constexpr int bedSheetPositionY = 0x0480B8; // short value
116
121 public:
122 RoomEntrance() = default;
123 RoomEntrance(Rom* rom, uint8_t entrance_id, bool is_spawn_point = false)
125 if (rom == nullptr || !rom->is_loaded()) {
126 load_status_ = absl::FailedPreconditionError("ROM not loaded");
127 room_ = -1;
128 return;
129 }
130 if (is_spawn_point) {
131 // This combined array remains a read-only navigation view for existing
132 // UI code. Authoritative spawn persistence uses DungeonSpawnPoint, which
133 // has distinct door-tilemap and entrance-ID fields.
134 auto loaded_spawn = DungeonSpawnPoint::Load(*rom, entrance_id);
135 if (!loaded_spawn.ok()) {
136 load_status_ = loaded_spawn.status();
137 room_ = -1;
138 return;
139 }
140 const DungeonSpawnPoint& spawn = *loaded_spawn;
141 room_ = static_cast<int16_t>(spawn.room_id);
148 blockset_ = spawn.main_gfx;
149 music_ = spawn.song;
150 dungeon_id_ = spawn.dungeon_id;
151 floor_ = spawn.floor;
152 door_ = 0;
153 ladder_bg_ = spawn.layer;
156 exit_ = static_cast<int16_t>(spawn.overworld_door_tilemap);
165 return;
166 }
167
168 const auto layout = ResolveEntranceLayout(rom->vector());
169 if (!layout.ok() || entrance_id >= kNumRegularDungeonEntrances) {
170 load_status_ = !layout.ok()
171 ? layout.status()
172 : absl::OutOfRangeError(
173 "Regular dungeon entrance ID is out of range");
174 room_ = -1;
175 blockset_ = 0xFF;
176 return;
177 }
178 loaded_layout_kind_ = layout->kind;
179
180 room_ = static_cast<short>(
181 (rom->data()[layout->table(EntranceField::kRoom) + (entrance_id * 2) +
182 1]
183 << 8) +
184 rom->data()[layout->table(EntranceField::kRoom) + (entrance_id * 2)]);
185 y_position_ = static_cast<uint16_t>(
186 (rom->data()[layout->table(EntranceField::kYPosition) +
187 (entrance_id * 2) + 1]
188 << 8) +
189 rom->data()[layout->table(EntranceField::kYPosition) +
190 (entrance_id * 2)]);
191 x_position_ = static_cast<uint16_t>(
192 (rom->data()[layout->table(EntranceField::kXPosition) +
193 (entrance_id * 2) + 1]
194 << 8) +
195 rom->data()[layout->table(EntranceField::kXPosition) +
196 (entrance_id * 2)]);
197 camera_x_ = static_cast<uint16_t>(
198 (rom->data()[layout->table(EntranceField::kXScroll) +
199 (entrance_id * 2) + 1]
200 << 8) +
201 rom->data()[layout->table(EntranceField::kXScroll) +
202 (entrance_id * 2)]);
203 camera_y_ = static_cast<uint16_t>(
204 (rom->data()[layout->table(EntranceField::kYScroll) +
205 (entrance_id * 2) + 1]
206 << 8) +
207 rom->data()[layout->table(EntranceField::kYScroll) +
208 (entrance_id * 2)]);
209 camera_trigger_y_ = static_cast<uint16_t>(
210 (rom->data()[(layout->table(EntranceField::kCameraYTrigger) +
211 (entrance_id * 2)) +
212 1]
213 << 8) +
214 rom->data()[layout->table(EntranceField::kCameraYTrigger) +
215 (entrance_id * 2)]);
216 camera_trigger_x_ = static_cast<uint16_t>(
217 (rom->data()[(layout->table(EntranceField::kCameraXTrigger) +
218 (entrance_id * 2)) +
219 1]
220 << 8) +
221 rom->data()[layout->table(EntranceField::kCameraXTrigger) +
222 (entrance_id * 2)]);
223 blockset_ =
224 rom->data()[layout->table(EntranceField::kBlockset) + entrance_id];
225 music_ = rom->data()[layout->table(EntranceField::kMusic) + entrance_id];
227 rom->data()[layout->table(EntranceField::kDungeon) + entrance_id];
228 floor_ = rom->data()[layout->table(EntranceField::kFloor) + entrance_id];
229 door_ = rom->data()[layout->table(EntranceField::kDoor) + entrance_id];
230 ladder_bg_ =
231 rom->data()[layout->table(EntranceField::kLadderBG) + entrance_id];
232 scrolling_ =
233 rom->data()[layout->table(EntranceField::kScrolling) + entrance_id];
235 rom->data()[layout->table(EntranceField::kScrollQuadrant) +
236 entrance_id];
237 exit_ = static_cast<short>(
238 (rom->data()[layout->table(EntranceField::kExit) + (entrance_id * 2) +
239 1]
240 << 8) +
241 rom->data()[layout->table(EntranceField::kExit) + (entrance_id * 2)]);
242
244 rom->data()[layout->table(EntranceField::kScrollEdge) + 0 +
245 (entrance_id * 8)];
247 rom->data()[layout->table(EntranceField::kScrollEdge) + 1 +
248 (entrance_id * 8)];
250 rom->data()[layout->table(EntranceField::kScrollEdge) + 2 +
251 (entrance_id * 8)];
253 rom->data()[layout->table(EntranceField::kScrollEdge) + 3 +
254 (entrance_id * 8)];
256 rom->data()[layout->table(EntranceField::kScrollEdge) + 4 +
257 (entrance_id * 8)];
259 rom->data()[layout->table(EntranceField::kScrollEdge) + 5 +
260 (entrance_id * 8)];
262 rom->data()[layout->table(EntranceField::kScrollEdge) + 6 +
263 (entrance_id * 8)];
265 rom->data()[layout->table(EntranceField::kScrollEdge) + 7 +
266 (entrance_id * 8)];
267 }
268
269 const absl::Status& load_status() const { return load_status_; }
270 std::optional<EntranceLayoutKind> loaded_layout_kind() const {
271 return loaded_layout_kind_;
272 }
273 bool dirty() const { return dirty_; }
274 void MarkDirty() { dirty_ = true; }
275 void ClearDirty() { dirty_ = false; }
276 bool is_spawn_point() const { return is_spawn_point_; }
277
278 absl::Status Save(Rom* rom, int entrance_id, bool is_spawn_point = false) {
279 if (!rom || !rom->is_loaded()) {
280 return absl::FailedPreconditionError("ROM not loaded");
281 }
282 if (is_spawn_point) {
283 return absl::FailedPreconditionError(absl::StrFormat(
284 "Dungeon spawn point 0x%02X cannot be saved: spawn writes are "
285 "disabled through the legacy RoomEntrance model; use the dedicated "
286 "spawn ROM schema in DungeonSpawnPoint",
287 entrance_id));
288 }
289
290 // Deliberate defense in depth for direct callers outside the bulk editor
291 // preflight: reject model/ID mismatches before the first regular write.
293 ValidateRegularDungeonEntranceForSave(*rom, *this, entrance_id));
294 ASSIGN_OR_RETURN(auto resolved_layout,
296 const auto* layout = &resolved_layout;
298 layout->table(EntranceField::kRoom) + (entrance_id * 2), room_));
300 layout->table(EntranceField::kYPosition) + (entrance_id * 2),
301 y_position_));
303 layout->table(EntranceField::kXPosition) + (entrance_id * 2),
304 x_position_));
306 layout->table(EntranceField::kYScroll) + (entrance_id * 2), camera_y_));
308 layout->table(EntranceField::kXScroll) + (entrance_id * 2), camera_x_));
310 layout->table(EntranceField::kCameraXTrigger) + (entrance_id * 2),
313 layout->table(EntranceField::kCameraYTrigger) + (entrance_id * 2),
316 layout->table(EntranceField::kExit) + (entrance_id * 2), exit_));
318 rom->WriteByte(layout->table(EntranceField::kBlockset) + entrance_id,
319 (uint8_t)(blockset_ & 0xFF)));
321 rom->WriteByte(layout->table(EntranceField::kMusic) + entrance_id,
322 (uint8_t)(music_ & 0xFF)));
324 rom->WriteByte(layout->table(EntranceField::kDungeon) + entrance_id,
325 (uint8_t)(dungeon_id_ & 0xFF)));
327 rom->WriteByte(layout->table(EntranceField::kDoor) + entrance_id,
328 (uint8_t)(door_ & 0xFF)));
330 rom->WriteByte(layout->table(EntranceField::kFloor) + entrance_id,
331 (uint8_t)(floor_ & 0xFF)));
333 rom->WriteByte(layout->table(EntranceField::kLadderBG) + entrance_id,
334 (uint8_t)(ladder_bg_ & 0xFF)));
336 rom->WriteByte(layout->table(EntranceField::kScrolling) + entrance_id,
337 (uint8_t)(scrolling_ & 0xFF)));
339 layout->table(EntranceField::kScrollQuadrant) + entrance_id,
340 (uint8_t)(scroll_quadrant_ & 0xFF)));
342 layout->table(EntranceField::kScrollEdge) + 0 + (entrance_id * 8),
345 layout->table(EntranceField::kScrollEdge) + 1 + (entrance_id * 8),
348 layout->table(EntranceField::kScrollEdge) + 2 + (entrance_id * 8),
351 layout->table(EntranceField::kScrollEdge) + 3 + (entrance_id * 8),
354 layout->table(EntranceField::kScrollEdge) + 4 + (entrance_id * 8),
357 layout->table(EntranceField::kScrollEdge) + 5 + (entrance_id * 8),
360 layout->table(EntranceField::kScrollEdge) + 6 + (entrance_id * 8),
363 layout->table(EntranceField::kScrollEdge) + 7 + (entrance_id * 8),
365 ClearDirty();
366 return absl::OkStatus();
367 }
368
369 uint16_t entrance_id_ = 0;
370 uint16_t x_position_ = 0;
371 uint16_t y_position_ = 0;
372 uint16_t camera_x_ = 0;
373 uint16_t camera_y_ = 0;
374 uint16_t camera_trigger_x_ = 0;
375 uint16_t camera_trigger_y_ = 0;
376
377 int16_t room_ = 0;
378 uint8_t blockset_ = 0;
379 uint8_t floor_ = 0;
380 uint8_t dungeon_id_ = 0;
381 uint8_t ladder_bg_ = 0;
382 uint8_t scrolling_ = 0;
383 uint8_t scroll_quadrant_ = 0;
384 int16_t exit_ = 0;
385 uint8_t music_ = 0;
386 uint8_t door_ = 0;
387
396
397 private:
398 absl::Status load_status_;
399 std::optional<EntranceLayoutKind> loaded_layout_kind_;
400 bool dirty_ = false;
401 bool is_spawn_point_ = false;
402};
403
404inline absl::StatusOr<std::vector<DungeonEntranceWriteRange>>
406 const Rom& rom,
407 const std::array<RoomEntrance, kNumDungeonEntranceSlots>& entrances) {
408 ASSIGN_OR_RETURN(auto layout, ResolveEntranceLayout(rom.vector()));
409 std::vector<DungeonEntranceWriteRange> ranges;
410 for (int entrance_id = 0; entrance_id < kNumRegularDungeonEntrances;
411 ++entrance_id) {
412 const auto& entrance = entrances[kNumDungeonSpawnPoints + entrance_id];
413 if (!entrance.dirty()) {
414 continue;
415 }
416 auto entrance_ranges =
417 RegularDungeonEntranceWriteRanges(layout, entrance_id);
418 ranges.insert(ranges.end(), entrance_ranges.begin(), entrance_ranges.end());
419 }
420 return ranges;
421}
422
424 const Rom& rom, const RoomEntrance& entrance, int entrance_id) {
425 if (entrance_id < 0 || entrance_id >= kNumRegularDungeonEntrances) {
426 return absl::OutOfRangeError(
427 absl::StrFormat("Regular dungeon entrance ID %d is outside [0, %d)",
428 entrance_id, kNumRegularDungeonEntrances));
429 }
430 if (entrance.is_spawn_point()) {
431 return absl::InvalidArgumentError(absl::StrFormat(
432 "Regular dungeon entrance 0x%02X is marked as a spawn point",
433 entrance_id));
434 }
435 if (entrance.entrance_id_ != static_cast<uint16_t>(entrance_id)) {
436 return absl::InvalidArgumentError(absl::StrFormat(
437 "Regular dungeon entrance model ID 0x%02X does not match requested "
438 "save ID 0x%02X",
439 static_cast<int>(entrance.entrance_id_), entrance_id));
440 }
441 RETURN_IF_ERROR(entrance.load_status());
442 ASSIGN_OR_RETURN(auto layout, ResolveEntranceLayout(rom.vector()));
443 if (entrance.loaded_layout_kind().has_value() &&
444 *entrance.loaded_layout_kind() != layout.kind) {
445 return absl::FailedPreconditionError(
446 "Dungeon entrance layout changed since load; reload entrances");
447 }
448 if (entrance.room_ < 0 || entrance.room_ >= kNumberOfRooms) {
449 return absl::OutOfRangeError(absl::StrFormat(
450 "Regular dungeon entrance 0x%02X room ID %d is outside [0, %d)",
451 entrance_id, entrance.room_, kNumberOfRooms));
452 }
453
454 for (const auto& [begin, end] :
455 RegularDungeonEntranceWriteRanges(layout, entrance_id)) {
456 if (end > rom.size()) {
457 return absl::FailedPreconditionError(absl::StrFormat(
458 "Regular dungeon entrance 0x%02X write range "
459 "0x%06X-0x%06X exceeds ROM size 0x%X",
460 entrance_id, begin, end, static_cast<uint32_t>(rom.size())));
461 }
462 }
463 return absl::OkStatus();
464}
465
467 const Rom& rom,
468 const std::array<RoomEntrance, kNumDungeonEntranceSlots>& entrances,
469 bool dirty_only = true) {
471 for (int entrance_id = 0; entrance_id < kNumRegularDungeonEntrances;
472 ++entrance_id) {
473 const auto& entrance = entrances[kNumDungeonSpawnPoints + entrance_id];
474 if (dirty_only && !entrance.dirty()) {
475 continue;
476 }
478 ValidateRegularDungeonEntranceForSave(rom, entrance, entrance_id));
479 }
480 return absl::OkStatus();
481}
482
484 const std::array<RoomEntrance, kNumDungeonEntranceSlots>& entrances,
485 bool dirty_only = true) {
486 for (int spawn_id = 0; spawn_id < kNumDungeonSpawnPoints; ++spawn_id) {
487 if (dirty_only && !entrances[spawn_id].dirty()) {
488 continue;
489 }
490 return absl::FailedPreconditionError(absl::StrFormat(
491 "Dungeon spawn point 0x%02X is scheduled for save through the legacy "
492 "RoomEntrance model; use the dedicated DungeonSpawnPoint model",
493 spawn_id));
494 }
495 return absl::OkStatus();
496}
497
498inline absl::Status SaveAllDungeonEntrances(
499 Rom* rom, std::array<RoomEntrance, kNumDungeonEntranceSlots>& entrances,
500 bool dirty_only = true) {
501 if (!rom || !rom->is_loaded()) {
502 return absl::FailedPreconditionError("ROM not loaded");
503 }
504
505 // The combined RoomEntrance array remains a read-only navigation view for
506 // spawn slots. Reject dirty legacy views before writing any regular record;
507 // authoritative spawn saves use SaveAllDungeonSpawnPoints separately.
509 RejectUnsupportedDungeonSpawnPointSaves(entrances, dirty_only));
510
511 // Validate every participating regular record before the first write.
513 ValidateRegularDungeonEntrancesForSave(*rom, entrances, dirty_only));
514
515 for (int entrance_id = 0; entrance_id < kNumRegularDungeonEntrances;
516 ++entrance_id) {
517 auto& entrance = entrances[kNumDungeonSpawnPoints + entrance_id];
518 if (dirty_only && !entrance.dirty()) {
519 continue;
520 }
521 RETURN_IF_ERROR(entrance.Save(rom, entrance_id, false));
522 }
523
524 return absl::OkStatus();
525}
526
527} // namespace zelda3
528} // namespace yaze
529
530#endif // YAZE_APP_ZELDA3_DUNGEON_ROOM_ENTRANCE_H
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:49
absl::Status WriteByte(int addr, uint8_t value)
Definition rom.cc:853
const auto & vector() const
Definition rom.h:205
auto data() const
Definition rom.h:201
auto size() const
Definition rom.h:200
absl::Status WriteShort(int addr, uint16_t value)
Definition rom.cc:897
bool is_loaded() const
Definition rom.h:187
std::array< uint8_t, 8 > camera_scroll_boundaries
static absl::StatusOr< DungeonSpawnPoint > Load(const Rom &rom, int spawn_id)
Dungeon Room Entrance or Spawn Point.
absl::Status Save(Rom *rom, int entrance_id, bool is_spawn_point=false)
RoomEntrance(Rom *rom, uint8_t entrance_id, bool is_spawn_point=false)
std::optional< EntranceLayoutKind > loaded_layout_kind_
std::optional< EntranceLayoutKind > loaded_layout_kind() const
const absl::Status & load_status() const
#define ASSIGN_OR_RETURN(type_variable_name, expression)
Definition macro.h:62
constexpr int bedPositionResetXLow
constexpr int bedSheetPositionX
constexpr int kEntranceCameraXTrigger
constexpr int kEntranceRoom
constexpr int dungeons_startrooms
constexpr int kEntranceDoor
constexpr int kEntranceXScroll
constexpr int bedPositionResetXHigh
constexpr int items_data_start
constexpr int bedPositionResetYHigh
absl::Status ValidateRegularDungeonEntranceForSave(const Rom &rom, const RoomEntrance &entrance, int entrance_id)
constexpr int bedPositionResetYLow
absl::StatusOr< std::vector< DungeonEntranceWriteRange > > CollectDirtyRegularDungeonEntranceWriteRanges(const Rom &rom, const std::array< RoomEntrance, kNumDungeonEntranceSlots > &entrances)
constexpr int bedPositionY
constexpr int initial_equipement
constexpr int kEntranceExit
constexpr int kNumRegularDungeonEntrances
constexpr int chests_msgid
constexpr int chests_itemsgfx
constexpr int chests_sramvalue
constexpr int chests_backupitems
constexpr int chests_xoffset
constexpr int kEntranceFloor
constexpr int bedPositionX
std::vector< DungeonEntranceWriteRange > RegularDungeonEntranceWriteRanges(const EntranceLayout &layout, int entrance_id)
constexpr int kEntranceCameraYTrigger
constexpr int kEntranceBlockset
constexpr int kEntranceXPosition
constexpr int kEntranceLadderBG
constexpr int dungeons_endrooms
constexpr int kEntranceMusic
constexpr int chests_itemsproperties
absl::Status RejectUnsupportedDungeonSpawnPointSaves(const std::array< RoomEntrance, kNumDungeonEntranceSlots > &entrances, bool dirty_only=true)
absl::Status SaveAllDungeonEntrances(Rom *rom, std::array< RoomEntrance, kNumDungeonEntranceSlots > &entrances, bool dirty_only=true)
constexpr int kNumDungeonSpawnPoints
absl::Status ValidateRegularDungeonEntrancesForSave(const Rom &rom, const std::array< RoomEntrance, kNumDungeonEntranceSlots > &entrances, bool dirty_only=true)
constexpr int chests_sramaddress
constexpr int kNumberOfRooms
std::pair< uint32_t, uint32_t > DungeonEntranceWriteRange
constexpr int kEntranceScrollEdge
constexpr int kEntranceDungeon
constexpr int dungeons_bossrooms
constexpr int kEntranceScrollQuadrant
constexpr int kEntrancescrolling
constexpr int chests_yoffset
absl::StatusOr< EntranceLayout > ResolveEntranceLayout(std::span< const uint8_t > data)
constexpr int kEntranceYScroll
constexpr int chests_itemswide
constexpr int items_data_end
constexpr int bedSheetPositionY
constexpr int kEntranceYPosition
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22
std::array< EntranceTable, static_cast< size_t >(EntranceField::kCount)> tables