3#include "absl/status/status.h"
4#include "absl/strings/str_format.h"
18 : base_ptr(base), index_mask(mask), id_offset(offset) {}
24 if (object_id >= 0xF80) {
28 }
else if (object_id >= 0x100) {
43 const int id = object_id;
44 if ((
id >= 0x03 &&
id <= 0x04) ||
45 (
id >= 0x63 &&
id <= 0x64) ||
47 id == 0x0C ||
id == 0x0D ||
id == 0x10 ||
id == 0x11 ||
id == 0x14 ||
48 id == 0x15 ||
id == 0x18 ||
id == 0x19 ||
id == 0x1C ||
id == 0x1D ||
51 id == 0x0E ||
id == 0x0F ||
id == 0x12 ||
id == 0x13 ||
id == 0x16 ||
52 id == 0x17 ||
id == 0x1A ||
id == 0x1B ||
id == 0x1E ||
id == 0x1F) {
61 static_cast<int>(rhs));
66 static_cast<int>(rhs));
71 static_cast<int>(rhs));
75 return static_cast<ObjectOption>(~static_cast<int>(option));
87 if (
rom_ ==
nullptr) {
89 if (
id_ == 0x001 ||
id_ == 0x002 ||
id_ == 0x061 ||
id_ == 0x062 ||
90 (
id_ >= 0x100 &&
id_ <= 0x103)) {
91 LOG_DEBUG(
"RoomObject",
"EnsureTilesLoaded: obj=0x%03X ROM is NULL!",
99 if (parser_status.ok()) {
102 if (
id_ == 0x001 ||
id_ == 0x002 ||
id_ == 0x061 ||
id_ == 0x062 ||
103 (
id_ >= 0x100 &&
id_ <= 0x103)) {
105 "EnsureTilesLoaded: obj=0x%03X loaded %zu tiles via parser",
112 if (
id_ == 0x001 ||
id_ == 0x002 ||
id_ == 0x061 ||
id_ == 0x062 ||
113 (
id_ >= 0x100 &&
id_ <= 0x103)) {
115 "EnsureTilesLoaded: obj=0x%03X parser failed: %s, trying legacy",
116 id_, std::string(parser_status.message()).c_str());
123 SubtypeTableInfo sti = GetSubtypeTable(
id_);
125 int index = ((
id_ - sti.id_offset) & sti.index_mask);
126 int tile_ptr = sti.base_ptr + (index * 2);
129 if (tile_ptr < 0 || tile_ptr + 1 >= (
int)
rom_->
size()) {
131 LOG_DEBUG(
"RoomObject",
"Tile pointer out of bounds for object %04X",
id_);
137 int tile_rel = (int16_t)((rom_data[tile_ptr + 1] << 8) + rom_data[tile_ptr]);
142 if (pos < 0 || pos + 7 >= (
int)
rom_->
size()) {
144 LOG_DEBUG(
"RoomObject",
"Tile data position out of bounds for object %04X",
152 uint16_t w0 = (uint16_t)(rom_data[pos] | (rom_data[pos + 1] << 8));
153 uint16_t w1 = (uint16_t)(rom_data[pos + 2] | (rom_data[pos + 3] << 8));
154 uint16_t w2 = (uint16_t)(rom_data[pos + 4] | (rom_data[pos + 5] << 8));
155 uint16_t w3 = (uint16_t)(rom_data[pos + 6] | (rom_data[pos + 7] << 8));
187 if (
rom_ ==
nullptr) {
188 return absl::InvalidArgumentError(
"ROM is null");
194 return result.status();
197 tiles_ = std::move(result.value());
199 return absl::OkStatus();
208 return absl::FailedPreconditionError(
"No tiles loaded for object");
211 return std::span<const gfx::TileInfo>(
tiles_.data(),
tiles_.size());
219 if (index < 0 || index >=
static_cast<int>(
tiles_.size())) {
220 return absl::OutOfRangeError(absl::StrFormat(
221 "Tile index %d out of range (0-%d)", index,
tiles_.size() - 1));
274 id = (b3 & 0x3F) | 0x100;
275 x = ((b2 & 0xF0) >> 4) | ((b1 & 0x03) << 4);
276 y = ((b2 & 0x0F) << 2) | ((b3 & 0xC0) >> 6);
279 "Type2: b1=%02X b2=%02X b3=%02X -> id=%04X x=%d y=%d size=%d", b1,
284 else if (b3 >= 0xF8) {
285 id = (
static_cast<uint16_t
>(b3) << 4) | 0x80 |
286 ((
static_cast<uint16_t
>(b2 & 0x03) << 2) + (b1 & 0x03));
287 x = (b1 & 0xFC) >> 2;
288 y = (b2 & 0xFC) >> 2;
289 size = ((b1 & 0x03) << 2) | (b2 & 0x03);
291 "Type3: b1=%02X b2=%02X b3=%02X -> id=%04X x=%d y=%d size=%d", b1,
297 x = (b1 & 0xFC) >> 2;
298 y = (b2 & 0xFC) >> 2;
299 size = ((b1 & 0x03) << 2) | (b2 & 0x03);
301 "Type1: b1=%02X b2=%02X b3=%02X -> id=%04X x=%d y=%d size=%d", b1,
306 obj.RefreshDerivedFlagsFromId();
315 if (
id_ >= 0x100 &&
id_ < 0x200) {
317 bytes.
b1 = 0xFC | ((
x_ & 0x30) >> 4);
318 bytes.
b2 = ((
x_ & 0x0F) << 4) | ((
y_ & 0x3C) >> 2);
319 bytes.
b3 = ((
y_ & 0x03) << 6) | (
id_ & 0x3F);
320 }
else if (
id_ >= 0xF00) {
322 bytes.
b1 = (
x_ << 2) | (
id_ & 0x03);
323 bytes.
b2 = (
y_ << 2) | ((
id_ >> 2) & 0x03);
324 bytes.
b3 = (
id_ >> 4) & 0xFF;
327 uint8_t clamped_size =
size_ > 15 ? 15 :
size_;
328 bytes.
b1 = (
x_ << 2) | ((clamped_size >> 2) & 0x03);
329 bytes.
b2 = (
y_ << 2) | (clamped_size & 0x03);
330 bytes.
b3 =
static_cast<uint8_t
>(
id_);
Direct ROM parser for dungeon objects.
absl::StatusOr< std::vector< gfx::TileInfo > > ParseObject(int16_t object_id)
Parse object data directly from ROM.
absl::StatusOr< const gfx::TileInfo * > GetTile(int index) const
static RoomObject DecodeObjectFromBytes(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t layer)
std::vector< gfx::TileInfo > tiles_
ObjectBytes EncodeObjectToBytes() const
void RefreshDerivedFlagsFromId()
static int DetermineObjectType(uint8_t b1, uint8_t b3)
absl::Status LoadTilesWithParser()
absl::StatusOr< std::span< const gfx::TileInfo > > GetTiles() const
void InvalidateTileCache()
RoomObject(int16_t id, uint8_t x, uint8_t y, uint8_t size, uint8_t layer=0)
#define LOG_DEBUG(category, format,...)
TileInfo WordToTileInfo(uint16_t word)
bool IsAllBgsObjectId(int object_id)
SubtypeTableInfo GetSubtypeTable(int object_id)
constexpr int kRoomObjectSubtype3
ObjectOption operator|(ObjectOption lhs, ObjectOption rhs)
ObjectOption operator^(ObjectOption lhs, ObjectOption rhs)
constexpr int kRoomObjectSubtype1
constexpr int kRoomObjectSubtype2
constexpr int kRoomObjectTileAddress
ObjectOption operator~(ObjectOption option)
ObjectOption operator&(ObjectOption lhs, ObjectOption rhs)
SubtypeTableInfo(int base, int mask, int offset=0)