532 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
538 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
544 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
550 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
556 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
562 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
568 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
574 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
580 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
586 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
592 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
598 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
604 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
610 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
616 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
622 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
628 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
634 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
640 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
646 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
653 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
659 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
665 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
671 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
677 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
683 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
689 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
695 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
701 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
707 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
713 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
719 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
725 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
731 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
737 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
743 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
749 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
755 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
761 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
767 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
773 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
779 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
785 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
791 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
797 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
803 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
809 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
815 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
821 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
827 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
833 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
839 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
845 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
851 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
857 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
863 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
874 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
881 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
889 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
896 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
903 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
910 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
917 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
924 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
931 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
942 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
949 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
956 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
963 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
970 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
977 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
984 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
991 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
998 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1005 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1016 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1023 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1030 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1037 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1048 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1055 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1062 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1069 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1080 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1087 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1094 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1101 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1108 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1115 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1122 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1129 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1136 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1143 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1150 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1157 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1164 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1171 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1179 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1186 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1194 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1202 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1210 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1218 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1220 obj, bg, tiles, state);
1227 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1235 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1243 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1251 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1259 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1267 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1269 obj, bg, tiles, state);
1275 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1277 obj, bg, tiles, state);
1283 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1291 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1299 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1309 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1319 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1320 if (obj.
id_ == 0xFB1) {
1321 self->DrawBigChest(obj, bg, tiles, state);
1333 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1343 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1348 auto ensure_index = [
this](
size_t index) {
1352 std::span<const gfx::TileInfo> tiles,
1364 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1372 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1379 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1387 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1395 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1403 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1412 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1420 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1428 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1436 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1444 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1452 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1460 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1468 std::span<const gfx::TileInfo> tiles,
const DungeonState* state) {
1479 std::span<const gfx::TileInfo> tiles,
1504 LOG_DEBUG(
"ObjectDrawer",
"DrawDoor: idx=%d type=%d dir=%d pos=%d",
1505 door_index,
static_cast<int>(door.
type),
1509 LOG_DEBUG(
"ObjectDrawer",
"DrawDoor: SKIPPED - rom=%p loaded=%d gfx=%p",
1515 auto& bitmap = bg1.
bitmap();
1516 if (!bitmap.is_active() || bitmap.width() == 0) {
1518 "DrawDoor: SKIPPED - bitmap not active or zero width");
1528 int door_height = dims.height_tiles;
1530 LOG_DEBUG(
"ObjectDrawer",
"DrawDoor: tile_pos=(%d,%d) dims=%dx%d", tile_x,
1531 tile_y, door_width, door_height);
1533 constexpr int kRoomDrawObjectDataBase = 0x1B52;
1534 constexpr int kDoorwayReplacementDoorGfxBase = 0x1A02;
1535 constexpr int kExplodingWallTilemapPositionBase = 0x19DE;
1536 constexpr int kExplodingWallOpenReplacementType = 0x54;
1537 constexpr int kNorthCurtainClosedOffset = 0x078A;
1538 const auto& rom_data =
rom_->
data();
1541 int start_tile_x,
int start_tile_y,
1542 int width,
int height,
int tile_data_addr) {
1543 auto& bitmap = target.
bitmap();
1546 const int bitmap_width = bitmap.width();
1549 for (
int dx = 0; dx < width; dx++) {
1550 for (
int dy = 0; dy < height; dy++) {
1551 const int addr = tile_data_addr + (tile_idx * 2);
1552 const uint16_t tile_word = rom_data[addr] | (rom_data[addr + 1] << 8);
1554 const int pixel_x = (start_tile_x + dx) * 8;
1555 const int pixel_y = (start_tile_y + dy) * 8;
1561 const uint8_t priority = tile_info.over_ ? 1 : 0;
1562 const auto& bitmap_data = bitmap.vector();
1563 for (
int py = 0; py < 8; py++) {
1564 const int dest_y = pixel_y + py;
1565 if (dest_y < 0 || dest_y >= bitmap.height()) {
1568 for (
int px = 0; px < 8; px++) {
1569 const int dest_x = pixel_x + px;
1570 if (dest_x < 0 || dest_x >= bitmap_width) {
1573 const int dest_index = dest_y * bitmap_width + dest_x;
1574 if (dest_index >= 0 &&
1575 dest_index <
static_cast<int>(coverage_buffer.size())) {
1576 coverage_buffer[dest_index] = 1;
1578 if (dest_index <
static_cast<int>(bitmap_data.size()) &&
1579 bitmap_data[dest_index] != 255) {
1580 priority_buffer[dest_index] = priority;
1591 int start_tile_y,
int width,
int height,
1592 uint16_t tile_word) {
1593 auto& bitmap = target.
bitmap();
1596 const int bitmap_width = bitmap.width();
1599 for (
int dx = 0; dx < width; dx++) {
1600 for (
int dy = 0; dy < height; dy++) {
1601 const int pixel_x = (start_tile_x + dx) * 8;
1602 const int pixel_y = (start_tile_y + dy) * 8;
1608 const uint8_t priority = tile_info.over_ ? 1 : 0;
1609 const auto& bitmap_data = bitmap.vector();
1610 for (
int py = 0; py < 8; py++) {
1611 const int dest_y = pixel_y + py;
1612 if (dest_y < 0 || dest_y >= bitmap.height()) {
1615 for (
int px = 0; px < 8; px++) {
1616 const int dest_x = pixel_x + px;
1617 if (dest_x < 0 || dest_x >= bitmap_width) {
1620 const int dest_index = dest_y * bitmap_width + dest_x;
1621 if (dest_index >= 0 &&
1622 dest_index <
static_cast<int>(coverage_buffer.size())) {
1623 coverage_buffer[dest_index] = 1;
1625 if (dest_index <
static_cast<int>(bitmap_data.size()) &&
1626 bitmap_data[dest_index] != 255) {
1627 priority_buffer[dest_index] = priority;
1635 auto tilemap_offset_to_tile_coords = [](uint16_t offset) {
1636 return std::pair<int, int>{
static_cast<int>((offset % 0x80) / 2),
1637 static_cast<int>(offset / 0x80) - 4};
1639 const int position_index = std::min<int>(door.
position & 0x0F, 11);
1641 auto resolve_render_type = [](
DoorDirection render_direction,
1643 switch (render_type) {
1671 int start_tile_y,
DoorType render_type) ->
bool {
1672 int offset_table_addr = 0;
1673 switch (render_direction) {
1689 resolve_render_type(render_direction, render_type);
1690 const int render_type_value =
static_cast<int>(resolved_type);
1691 const int type_index = render_type_value / 2;
1692 const int table_entry_addr = offset_table_addr + (type_index * 2);
1693 if (table_entry_addr + 1 >=
static_cast<int>(
rom_->
size())) {
1697 const uint16_t tile_offset =
1698 rom_data[table_entry_addr] | (rom_data[table_entry_addr + 1] << 8);
1699 const int tile_data_addr = kRoomDrawObjectDataBase + tile_offset;
1701 const int data_size = dims.width_tiles * dims.height_tiles * 2;
1702 if (tile_data_addr < 0 ||
1703 tile_data_addr + data_size >
static_cast<int>(
rom_->
size())) {
1707 draw_from_object_data(target, start_tile_x, start_tile_y, dims.width_tiles,
1708 dims.height_tiles, tile_data_addr);
1717 "DrawDoor: closed exploding wall intentionally draws nothing");
1724 const int tile_data_addr =
1725 kRoomDrawObjectDataBase + kNorthCurtainClosedOffset;
1726 const int data_size = 16 * 2;
1727 if (tile_data_addr < 0 ||
1728 tile_data_addr + data_size >
static_cast<int>(
rom_->
size())) {
1733 draw_from_object_data(bg1, tile_x, tile_y, 4, 4,
1740 const int replacement_type_addr =
1741 kDoorwayReplacementDoorGfxBase +
static_cast<int>(door.
type);
1742 if (replacement_type_addr < 0 ||
1743 replacement_type_addr >=
static_cast<int>(
rom_->
size())) {
1749 const int replacement_type = rom_data[replacement_type_addr];
1750 const int table_entry_addr =
kDoorGfxUp + replacement_type;
1751 if (table_entry_addr < 0 ||
1752 table_entry_addr + 1 >=
static_cast<int>(
rom_->
size())) {
1758 const uint16_t tile_offset =
1759 rom_data[table_entry_addr] | (rom_data[table_entry_addr + 1] << 8);
1760 const int tile_data_addr = kRoomDrawObjectDataBase + tile_offset;
1761 const int data_size = 16 * 2;
1762 if (tile_data_addr < 0 ||
1763 tile_data_addr + data_size >
static_cast<int>(
rom_->
size())) {
1769 draw_from_object_data(bg1, tile_x, tile_y, 4, 4,
1776 const int position_index = std::min<int>(door.
position & 0x0F, 5);
1777 const int tilemap_entry_addr =
1778 kExplodingWallTilemapPositionBase + (position_index * 2);
1779 if (tilemap_entry_addr < 0 ||
1780 tilemap_entry_addr + 1 >=
static_cast<int>(
rom_->
size())) {
1786 const uint16_t tilemap_offset =
1787 rom_data[tilemap_entry_addr] | (rom_data[tilemap_entry_addr + 1] << 8);
1788 const auto explosion_tile_coords =
1789 tilemap_offset_to_tile_coords(tilemap_offset);
1790 const int explosion_tile_x = explosion_tile_coords.first;
1791 const int explosion_tile_y = explosion_tile_coords.second;
1793 auto draw_exploding_wall_segment = [&](
int table_entry_addr,
1794 int segment_tile_y) ->
bool {
1795 if (table_entry_addr < 0 ||
1796 table_entry_addr + 1 >=
static_cast<int>(
rom_->
size())) {
1800 const uint16_t tile_offset =
1801 rom_data[table_entry_addr] | (rom_data[table_entry_addr + 1] << 8);
1802 const int tile_data_addr = kRoomDrawObjectDataBase + tile_offset;
1803 constexpr int kFillWordIndex = 12;
1804 const int min_data_size = (kFillWordIndex + 1) * 2;
1805 if (tile_data_addr < 0 ||
1806 tile_data_addr + min_data_size >
static_cast<int>(
rom_->
size())) {
1810 draw_from_object_data(bg1, explosion_tile_x, segment_tile_y,
1811 2, 6, tile_data_addr);
1812 const uint16_t fill_word =
1813 rom_data[tile_data_addr + (kFillWordIndex * 2)] |
1814 (rom_data[tile_data_addr + (kFillWordIndex * 2) + 1] << 8);
1815 draw_repeated_tile(bg1, explosion_tile_x + 2, segment_tile_y,
1820 const int south_table_entry_addr =
1822 const int north_table_entry_addr =
1823 kDoorGfxUp + kExplodingWallOpenReplacementType;
1824 if (!draw_exploding_wall_segment(south_table_entry_addr,
1825 explosion_tile_y) ||
1826 !draw_exploding_wall_segment(north_table_entry_addr,
1827 explosion_tile_y + 6)) {
1845 const int counterpart_tile_x =
1847 const int counterpart_tile_y =
1849 (void)draw_table_door(bg1, counterpart_direction, counterpart_tile_x,
1850 counterpart_tile_y, door.
type);
1853 const bool drew_current =
1854 draw_table_door(bg1, door.
direction, tile_x, tile_y, door.
type);
1855 if (!drew_current) {
1857 "DrawDoor: INVALID ADDRESS - falling back to indicator");
1864 "DrawDoor: type=%s dir=%s pos=%d at tile(%d,%d) size=%dx%d",
1867 door.
position, tile_x, tile_y, door_width, door_height);