16namespace draw_routines {
20constexpr int kThievesTownEastAtticRoomId = 0x65;
24 return tiles[index % tiles.size()];
28 int h, std::span<const gfx::TileInfo> tiles,
29 size_t start_index = 0) {
33 size_t index = start_index;
34 for (
int x = 0; x < w; ++x) {
35 for (
int y = 0; y < h; ++y) {
43 int h, std::span<const gfx::TileInfo> tiles,
44 size_t start_index = 0) {
48 size_t index = start_index;
49 for (
int y = 0; y < h; ++y) {
50 for (
int x = 0; x < w; ++x) {
60 columns, 3, ctx.
tiles, start_index);
65 ctx.
tiles, start_index);
70 ctx.
tiles, start_index);
80 if (ctx.
tiles.size() < 64)
90 std::span<const gfx::TileInfo> tiles) {
95 std::span<const gfx::TileInfo> tiles) {
104 return object_id == 0x0130 || object_id == 0x0131 || object_id == 0x0F9B ||
109 return object_id >= 0x0F9E && object_id <= 0x0FA1;
113 return object_id >= 0x0FA6 && object_id <= 0x0FA9;
117 return object_id == 0x0FA8 || object_id == 0x0FA9;
124 if (ctx.
tiles.size() < 8)
141 constexpr size_t kSpanTiles = 40;
142 const bool use_open_tiles = ctx.
state !=
nullptr &&
144 ctx.
tiles.size() >= kSpanTiles * 2;
145 const size_t start_index = use_open_tiles ? kSpanTiles : 0;
146 if (ctx.
tiles.size() < start_index + kSpanTiles)
154 if (index >= ctx.
tiles.size())
162 size_t start_index,
int columns) {
163 for (
int x = 0; x < columns; ++x) {
164 for (
int y = 0; y < 3; ++y) {
171 size_t start_index) {
179 size_t start_index) {
190 0x3C15, 0x3C15, 0x3C15};
193 std::array<gfx::TileInfo, 3> fill_tiles;
194 for (
size_t i = 0; i < fill_tiles.size(); ++i) {
196 if (ctx.
rom !=
nullptr) {
198 static_cast<int>(i * 2));
211 for (
int x = 0; x < column_count; ++x) {
214 for (
int y = 1; y < height - 1; ++y) {
219 ctx.
object.
y_ + height - 1, fill_tiles[2]);
226 for (
int i = 0; i < direction; ++i) {
237 size_t start_index,
int fill_width) {
240 for (
int i = 0; i < fill_width; ++i) {
244 const int left_cap_x = 1 + fill_width;
247 for (
int i = 0; i < 4; ++i) {
251 const int right_cap_x = left_cap_x + 5;
254 for (
int i = 0; i < fill_width; ++i) {
267 if (!is_open && ctx.
state) {
274 size_t start_index = is_open && ctx.
tiles.size() >= 32 ? 16 : 0;
275 for (
int x = 0; x < 4; ++x) {
276 for (
int y = 0; y < 4; ++y) {
279 ctx.
tiles[start_index +
static_cast<size_t>(x * 4 + y)]);
285 size_t start_index = 0;
286 if (is_open && ctx.
object.
id_ == 0xF99 && ctx.
tiles.size() >= 8) {
289 if (ctx.
tiles.size() < start_index + 4) {
294 ctx.
tiles[start_index]);
296 ctx.
tiles[start_index + 1]);
298 ctx.
tiles[start_index + 2]);
317 if (ctx.
tiles.size() >= 1) {
329 if (!result.ok() || !result.value() || result.value()->IsEmpty()) {
331 if (ctx.
tiles.size() >= 1) {
338 const auto& custom_obj = *result.value();
340 for (
const auto& entry : custom_obj.tiles) {
343 uint8_t lo =
static_cast<uint8_t
>(entry.tile_data & 0xFF);
344 uint8_t hi =
static_cast<uint8_t
>((entry.tile_data >> 8) & 0xFF);
349 int draw_x = ctx.
object.
x_ + entry.rel_x;
350 int draw_y = ctx.
object.
y_ + entry.rel_y;
363 if (ctx.
tiles.size() >= 2) {
368 if (ctx.
tiles.size() >
static_cast<size_t>(tile_index)) {
370 ctx.
tiles[tile_index]);
378 if (ctx.
tiles.empty()) {
390 if (ctx.
tiles.size() >= 4) {
407 if (ctx.
tiles.size() >=
static_cast<size_t>(width * height)) {
408 for (
int y = 0; y < height; ++y) {
409 for (
int x = 0; x < width; ++x) {
412 ctx.
tiles[y * width + x]);
426 Draw1x3NRightwards(ctx, 6, 0);
431 Draw1x3NRightwards(ctx, 6, 0);
437 Draw1x3NRightwards(ctx, 8, 0);
443 if (ctx.
tiles.size() < 8)
452 if (ctx.
tiles.size() < 48)
467 if (ctx.
tiles.size() < 16)
481 if (ctx.
tiles.size() < 84)
484 constexpr std::array<int, 14> kSourceColumns = {
485 0, 1, 1, 2, 3, 4, 5, 5, 4, 3, 2, 1, 1, 0,
487 for (
int y = 0; y < 14; ++y) {
488 for (
int x = 0; x < 14; ++x) {
490 if (x >= 7 && x <= 12) {
492 }
else if (x == 13) {
504 if (ctx.
tiles.size() < 26)
507 auto write = [&](
int dx,
int dy,
size_t tile_index,
508 bool force_horizontal_mirror =
false,
509 bool toggle_horizontal_mirror =
false) {
511 if (force_horizontal_mirror) {
513 }
else if (toggle_horizontal_mirror) {
521 for (
int section = 0; section < 6; ++section) {
522 const int x = section * 2;
528 write(x + 2, 2, 1,
true);
533 for (
int row = 0; row < 3; ++row) {
534 const size_t wall_tile =
static_cast<size_t>(2 + row);
535 const size_t center_tile =
static_cast<size_t>(5 + row);
536 const int y = 3 + row;
538 for (
int x : {0, 2, 10, 12}) {
539 write(x, y, wall_tile);
541 for (
int x : {1, 3, 11, 13}) {
542 write(x, y, wall_tile,
true);
544 for (
int x : {4, 6, 8}) {
545 write(x, y, center_tile);
547 for (
int x : {5, 7, 9}) {
548 write(x, y, center_tile,
true);
555 write(13, 0, 8,
true);
556 write(13, 1, 8,
true);
558 write(13, 2, 9,
true);
562 for (
int row = 0; row < 4; ++row) {
563 const int y = 10 + row;
564 write(3, y,
static_cast<size_t>(10 + row));
565 write(10, y,
static_cast<size_t>(10 + row),
568 write(4, y,
static_cast<size_t>(14 + row));
569 write(9, y,
static_cast<size_t>(14 + row),
572 write(5, y,
static_cast<size_t>(18 + row));
573 write(8, y,
static_cast<size_t>(18 + row),
576 write(6, y,
static_cast<size_t>(22 + row));
577 write(7, y,
static_cast<size_t>(22 + row),
588 if (ctx.
tiles.empty())
592 for (
int x = 0; x < 3; ++x) {
595 TileAtWrapped(ctx.
tiles,
static_cast<size_t>(x)));
599 for (
int y = 1; y <= 3; ++y) {
600 for (
int x = 0; x < 3; ++x) {
603 TileAtWrapped(ctx.
tiles,
static_cast<size_t>(3 + x)));
608 for (
int x = 0; x < 3; ++x) {
611 TileAtWrapped(ctx.
tiles,
static_cast<size_t>(6 + x)));
618 if (ctx.
tiles.empty())
620 Draw1x3NRightwards(ctx, 4, 0, 0);
621 Draw1x3NRightwards(ctx, 4, 12, 3);
634 if (ctx.
tiles.size() < 32)
636 Draw4x4ColumnMajor(ctx, 0, 0, 0);
637 Draw4x4ColumnMajor(ctx, 0, 2, 0);
638 Draw4x4ColumnMajor(ctx, 0, 6, 16);
647 if (ctx.
state !=
nullptr &&
651 DrawFloorLightGrid(ctx);
656 DrawFloorLightGrid(ctx);
661 Draw4x4ColumnMajor(ctx, 0, 0, 0);
672 if (ctx.
tiles.empty())
674 Draw1x3NRightwards(ctx, 3, 0, 0);
675 Draw1x3NRightwards(ctx, 3, 9, 3);
681 if (ctx.
tiles.empty())
684 Draw4x4ColumnMajor(ctx, 2, 0, 0);
685 Draw4x4ColumnMajor(ctx, 0, 4, 16);
686 Draw4x4ColumnMajor(ctx, 4, 4, 16);
692 if (ctx.
tiles.size() < 4)
707 if (ctx.
tiles.size() < 16)
711 for (
int x = 0; x < 4; ++x) {
712 for (
int y = 0; y < 4; ++y) {
721 if (ctx.
tiles.size() < 12)
725 for (
int x = 0; x < 4; ++x) {
726 for (
int y = 0; y < 3; ++y) {
738 ctx.
tiles.size() < 2) {
742 constexpr std::array<int, 3> kTopRows = {0, 3, 6};
743 constexpr std::array<int, 3> kBottomRows = {1, 4, 7};
744 for (
int col = 0; col < 3; ++col) {
745 const int x = ctx.
object.
x_ + col * 2;
746 for (
int row : kTopRows) {
750 for (
int row : kBottomRows) {
765 if (ctx.
tiles.empty())
769 const int middle_columns = (size + 1) * 2;
771 Draw1x5Column(ctx, 0, 0);
772 for (
int i = 0; i < middle_columns; ++i) {
773 Draw1x5Column(ctx, 1 + i, 5);
775 Draw1x5Column(ctx, 1 + middle_columns, 10);
781 if (ctx.
tiles.empty())
785 const int middle_columns = (size + 1) * 2;
789 for (
int i = 0; i < middle_columns; ++i) {
812 "Draw4x4BlocksIn4x4SuperSquare: obj=0x%03X pos=(%d,%d) size=0x%02X "
813 "tiles=%zu size_x=%d size_y=%d",
815 ctx.
tiles.size(), size_x, size_y);
817 if (ctx.
tiles.empty()) {
819 "Draw4x4BlocksIn4x4SuperSquare: SKIPPING - no tiles loaded!");
824 const auto& tile = ctx.
tiles[0];
826 "Draw4x4BlocksIn4x4SuperSquare: tile[0] id=%d palette=%d", tile.id_,
829 for (
int sy = 0; sy < size_y; ++sy) {
830 for (
int sx = 0; sx < size_x; ++sx) {
832 int base_x = ctx.
object.
x_ + (sx * 4);
833 int base_y = ctx.
object.
y_ + (sy * 4);
836 for (
int y = 0; y < 4; ++y) {
837 for (
int x = 0; x < 4; ++x) {
852 if (ctx.
tiles.empty())
855 const auto& tile = ctx.
tiles[0];
856 for (
int sy = 0; sy < size_y; ++sy) {
857 for (
int sx = 0; sx < size_x; ++sx) {
858 int base_x = ctx.
object.
x_ + (sx * 3);
859 int base_y = ctx.
object.
y_ + (sy * 3);
861 for (
int y = 0; y < 3; ++y) {
862 for (
int x = 0; x < 3; ++x) {
878 if (ctx.
tiles.empty())
880 if (ctx.
tiles.size() < 8) {
887 for (
int sy = 0; sy < size_y; ++sy) {
888 for (
int sx = 0; sx < size_x; ++sx) {
889 int base_x = ctx.
object.
x_ + (sx * 4);
890 int base_y = ctx.
object.
y_ + (sy * 4);
904 if (ctx.
tiles.size() < 8) {
909 for (
int sy = 0; sy < size_y; ++sy) {
910 for (
int sx = 0; sx < size_x; ++sx) {
911 int base_x = ctx.
object.
x_ + (sx * 4);
912 int base_y = ctx.
object.
y_ + (sy * 4);
925 if (ctx.
tiles.size() < 8) {
930 for (
int sy = 0; sy < size_y; ++sy) {
931 for (
int sx = 0; sx < size_x; ++sx) {
932 int base_x = ctx.
object.
x_ + (sx * 4);
933 int base_y = ctx.
object.
y_ + (sy * 4);
945 if (ctx.
tiles.size() < 24)
962 for (
int xx = 1; xx < max; ++xx) {
963 for (
int yy = 1; yy < max; ++yy) {
973 for (
int yy = 1; yy < max; ++yy) {
987 if (ctx.
tiles.size() < 4)
990 for (
int sy = 0; sy < size_y; ++sy) {
991 for (
int sx = 0; sx < size_x; ++sx) {
992 int base_x = ctx.
object.
x_ + (sx * 2);
993 int base_y = ctx.
object.
y_ + (sy * 2);
1011 if (ctx.
tiles.size() < 16)
1014 int right_x = ctx.
object.
x_ + (3 + (size_x * 2));
1015 int bottom_y = ctx.
object.
y_ + (3 + (size_y * 2));
1018 for (
int xx = 0; xx < size_x + 1; ++xx) {
1019 for (
int yy = 0; yy < size_y + 1; ++yy) {
1020 int base_x = ctx.
object.
x_ + (xx * 2);
1021 int base_y = ctx.
object.
y_ + (yy * 2);
1034 for (
int yy = 0; yy < size_y + 1; ++yy) {
1035 int base_y = ctx.
object.
y_ + (yy * 2);
1048 for (
int xx = 0; xx < size_x + 1; ++xx) {
1049 int base_x = ctx.
object.
x_ + (xx * 2);
1080 int count_x = size_x + 2;
1081 int count_y = size_y + 2;
1083 if (ctx.
tiles.empty())
1085 if (ctx.
tiles.size() < 8) {
1087 for (
int yy = 0; yy < count_y; ++yy) {
1088 for (
int xx = 0; xx < count_x; ++xx) {
1089 int base_x = ctx.
object.
x_ + (xx * 4);
1090 int base_y = ctx.
object.
y_ + (yy * 4);
1092 ctx.
tiles[
static_cast<size_t>((xx + yy) % ctx.
tiles.size())];
1093 for (
int y = 0; y < 4; ++y) {
1094 for (
int x = 0; x < 4; ++x) {
1104 for (
int yy = 0; yy < count_y; ++yy) {
1105 for (
int xx = 0; xx < count_x; ++xx) {
1106 int base_x = ctx.
object.
x_ + (xx * 4);
1107 int base_y = ctx.
object.
y_ + (yy * 4);
1109 for (
int x = 0; x < 4; ++x) {
1133 if (ctx.
tiles.size() < 16)
1158 if (ctx.
tiles.size() < 12)
1173 if (ctx.
tiles.size() < 16)
1187 if (ctx.
tiles.size() < 16)
1191 !IsStraightInterroomLower(ctx.
object.
id_)) {
1196 const bool south_lower = IsSouthLowerStraightInterroomStairs(ctx.
object.
id_);
1197 size_t tile_index = 0;
1198 for (
int col = 0; col < 4; ++col) {
1199 for (
int row = 0; row < 4; ++row) {
1200 const auto& tile = TileAtWrapped(ctx.
tiles, tile_index++);
1203 if ((!south_lower && row == 0) || (south_lower && row == 3)) {
1222 if (ctx.
tiles.size() < 6) {
1232 tile.horizontal_mirror_ =
true;
1236 for (
int col = 0; col < 5; ++col) {
1237 const int left_x = base_x + 2 + col;
1238 const int right_x = base_x + 9 + col;
1244 with_horizontal_mirror(ctx.
tiles[2]));
1248 with_horizontal_mirror(ctx.
tiles[4]));
1252 with_horizontal_mirror(ctx.
tiles[5]));
1257 with_horizontal_mirror(ctx.
tiles[0]));
1258 for (
int x_offset : {1, 7, 8, 14}) {
1265 with_horizontal_mirror(ctx.
tiles[3]));
1282 if (ctx.
tiles.size() < 16) {
1289 const bool is_open = ctx.
state !=
nullptr &&
1291 ctx.
tiles.size() >= 32;
1292 const size_t state_offset = is_open ? 16 : 0;
1294 for (
int block_y = 0; block_y < 2; ++block_y) {
1295 for (
int block_x = 0; block_x < 2; ++block_x) {
1296 const size_t block_offset =
1297 state_offset +
static_cast<size_t>((block_y * 2 + block_x) * 4);
1298 for (
int x = 0; x < 2; ++x) {
1299 for (
int y = 0; y < 2; ++y) {
1303 ctx.
tiles[block_offset +
static_cast<size_t>(x * 2 + y)]);
1313 ctx.
tiles.size() < 24) {
1319 const int height = direction * 2 + 6;
1323 DrawMovingWallFill(ctx, ctx.
object.
x_ - column_count, column_count, height);
1324 DrawMovingWallPlatform(ctx, direction);
1330 ctx.
tiles.size() < 24) {
1336 const int height = direction * 2 + 6;
1340 DrawMovingWallPlatform(ctx, direction);
1341 DrawMovingWallFill(ctx, ctx.
object.
x_ + 3, column_count, height);
1352 if (row_count <= 0 || tile_offset < 0 || ctx.
tiles.empty()) {
1356 if (tile_offset >=
static_cast<int>(ctx.
tiles.size())) {
1360 const int available_tiles =
static_cast<int>(ctx.
tiles.size()) - tile_offset;
1362 const int rows_to_draw = std::min(row_count, available_rows);
1364 for (
int row = 0; row < rows_to_draw; ++row) {
1369 ctx.
tiles[row_base + col]);
1384 const bool water_active =
1387 const int row_count = water_active ? 5 : 3;
1388 const int tile_offset = water_active ? 12 : 0;
1389 DrawWaterFaceRows(ctx, row_count, tile_offset);
1395 DrawWaterFaceRows(ctx, 5, 0);
1401 DrawWaterFaceRows(ctx, 7, 0);
1415 if (ctx.
tiles.size() < 68)
1418 const int size_x = (ctx.
object.
size_ >> 2) & 0x03;
1420 const int width_blocks = size_x + 4;
1421 const int height_blocks = size_y + 1;
1424 DrawPlatform1x3Rightwards(ctx, 0, 0, 0,
1426 for (
int x = 0; x < width_blocks; ++x) {
1427 DrawPlatform1x3Rightwards(ctx, 3 + x * 2, 0,
1430 DrawPlatform1x3Rightwards(ctx, 3 + width_blocks * 2, 0,
1434 for (
int y = 0; y < height_blocks; ++y) {
1435 const int dy = 3 + y * 2;
1436 DrawPlatform3x2(ctx, 0, dy, 24);
1437 for (
int x = 0; x < width_blocks; ++x) {
1438 DrawPlatform2x2(ctx, 3 + x * 2, dy, 30);
1440 DrawPlatform3x2(ctx, 3 + width_blocks * 2, dy,
1445 const int bottom_y = 3 + height_blocks * 2;
1446 DrawPlatform1x3Rightwards(ctx, 0, bottom_y, 40,
1448 for (
int x = 0; x < width_blocks; ++x) {
1449 DrawPlatform1x3Rightwards(ctx, 3 + x * 2, bottom_y,
1452 DrawPlatform1x3Rightwards(ctx, 3 + width_blocks * 2, bottom_y,
1457 DrawPlatform2x2(ctx, width_blocks + 2,
1458 bottom_y - (height_blocks + 1),
1466 if (ctx.
tiles.size() < 21)
1469 const int size_x = (ctx.
object.
size_ >> 2) & 0x03;
1471 const int fill_width = size_x + 1;
1472 const int body_rows = size_y * 2 + 5;
1474 for (
int row = 0; row < body_rows; ++row) {
1475 DrawOpenChestPlatformSegment(ctx, row, 0, fill_width);
1477 DrawOpenChestPlatformSegment(ctx, body_rows, 1, fill_width);
1478 DrawOpenChestPlatformSegment(ctx, body_rows + 1, 2,
1486 if (ctx.
tiles.size() < 3)
1489 for (
int x = 0; x < width; ++x) {
1490 size_t tile_idx = (x == 0) ? 0 : ((x == width - 1) ? 2 : 1);
1500 if (ctx.
tiles.empty())
1503 for (
int y = 0; y < height; ++y) {
1522 .draws_to_both_bgs =
false,
1533 .draws_to_both_bgs =
false,
1541 .name =
"DoorSwitcherer",
1543 .draws_to_both_bgs =
false,
1552 .name =
"SomariaLine",
1554 .draws_to_both_bgs =
false,
1563 .name =
"WaterFace",
1565 .draws_to_both_bgs =
false,
1578 .name =
"4x4BlocksIn4x4SuperSquare",
1580 .draws_to_both_bgs =
false,
1588 .name =
"3x3FloorIn4x4SuperSquare",
1590 .draws_to_both_bgs =
false,
1598 .name =
"4x4FloorIn4x4SuperSquare",
1600 .draws_to_both_bgs =
false,
1608 .name =
"4x4FloorOneIn4x4SuperSquare",
1610 .draws_to_both_bgs =
false,
1618 .name =
"4x4FloorTwoIn4x4SuperSquare",
1620 .draws_to_both_bgs =
false,
1628 .name =
"BigHole4x4_1to16",
1630 .draws_to_both_bgs =
false,
1638 .name =
"Spike2x2In4x4SuperSquare",
1640 .draws_to_both_bgs =
false,
1648 .name =
"TableRock4x4_1to16",
1650 .draws_to_both_bgs =
false,
1658 .name =
"WaterOverlay8x8_1to16",
1660 .draws_to_both_bgs =
false,
1669 .name =
"InterRoomFatStairsUp",
1671 .draws_to_both_bgs =
false,
1680 .name =
"InterRoomFatStairsDownA",
1682 .draws_to_both_bgs =
false,
1691 .name =
"InterRoomFatStairsDownB",
1693 .draws_to_both_bgs =
false,
1702 .name =
"AutoStairs",
1704 .draws_to_both_bgs =
false,
1713 .name =
"StraightInterRoomStairs",
1715 .draws_to_both_bgs =
false,
1725 .name =
"SpiralStairsGoingUpUpper",
1728 .draws_to_both_bgs =
false,
1737 .name =
"SpiralStairsGoingDownUpper",
1740 .draws_to_both_bgs =
false,
1749 .name =
"SpiralStairsGoingUpLower",
1752 .draws_to_both_bgs =
false,
1761 .name =
"SpiralStairsGoingDownLower",
1764 .draws_to_both_bgs =
false,
1773 .name =
"WaterHopStairsA",
1774 .function = DrawWaterHopStairsA,
1775 .draws_to_both_bgs =
false,
1784 .name =
"WaterHopStairsB",
1785 .function = DrawWaterHopStairsB,
1786 .draws_to_both_bgs =
true,
1795 .name =
"DamFloodGate",
1796 .function = DrawDamFloodGate,
1797 .draws_to_both_bgs =
false,
1807 .name =
"BigKeyLock",
1809 .draws_to_both_bgs =
false,
1818 .name =
"BombableFloor",
1820 .draws_to_both_bgs =
false,
1830 .name =
"EmptyWaterFace",
1832 .draws_to_both_bgs =
false,
1841 .name =
"SpittingWaterFace",
1843 .draws_to_both_bgs =
false,
1852 .name =
"DrenchingWaterFace",
1854 .draws_to_both_bgs =
false,
1865 .name =
"PrisonCell",
1867 .draws_to_both_bgs =
false,
1878 .draws_to_both_bgs =
false,
1886 .name =
"Rightwards3x6",
1888 .draws_to_both_bgs =
false,
1896 .name =
"Utility6x3",
1898 .draws_to_both_bgs =
false,
1906 .name =
"Utility3x5",
1908 .draws_to_both_bgs =
false,
1916 .name =
"VerticalTurtleRockPipe",
1918 .draws_to_both_bgs =
false,
1926 .name =
"HorizontalTurtleRockPipe",
1928 .draws_to_both_bgs =
false,
1936 .name =
"LightBeam",
1938 .draws_to_both_bgs =
false,
1947 .name =
"BigLightBeam",
1949 .draws_to_both_bgs =
false,
1958 .name =
"FloorLight",
1960 .draws_to_both_bgs =
false,
1969 .name =
"BossShell4x4",
1971 .draws_to_both_bgs =
false,
1979 .name =
"SolidWallDecor3x4",
1981 .draws_to_both_bgs =
false,
1989 .name =
"ArcheryGameTargetDoor",
1991 .draws_to_both_bgs =
false,
1999 .name =
"GanonTriforceFloorDecor",
2001 .draws_to_both_bgs =
false,
2009 .name =
"Single2x2",
2011 .draws_to_both_bgs =
false,
2020 .name =
"Single4x4",
2022 .draws_to_both_bgs =
false,
2031 .name =
"Single4x3",
2033 .draws_to_both_bgs =
false,
2042 .name =
"RupeeFloor",
2044 .draws_to_both_bgs =
false,
2053 .name =
"Actual4x4",
2055 .draws_to_both_bgs =
false,
2064 .name =
"BigWallDecor",
2066 .draws_to_both_bgs =
false,
2075 .name =
"TableBowl",
2077 .draws_to_both_bgs =
false,
2086 .name =
"SmithyFurnace",
2088 .draws_to_both_bgs =
false,
2097 .name =
"BigGrayRock",
2099 .draws_to_both_bgs =
false,
2108 .name =
"AgahnimsAltar",
2110 .draws_to_both_bgs =
false,
2119 .name =
"FortuneTellerRoom",
2121 .draws_to_both_bgs =
false,
2130 .name =
"Waterfall47",
2132 .draws_to_both_bgs =
false,
2140 .name =
"Waterfall48",
2142 .draws_to_both_bgs =
false,
2151 .name =
"ClosedChestPlatform",
2153 .draws_to_both_bgs =
false,
2162 .name =
"MovingWallWest",
2164 .draws_to_both_bgs =
false,
2173 .name =
"MovingWallEast",
2175 .draws_to_both_bgs =
false,
2184 .name =
"OpenChestPlatform",
2186 .draws_to_both_bgs =
false,
2196 .name =
"DownwardsHasEdge1x1_1to16_plus23",
2200 int size = ctx.object.size_ & 0x0F;
2201 int count = size + 21;
2202 if (ctx.tiles.size() < 3)
2205 int tile_y = ctx.object.y_;
2209 ctx.target_bg, ctx.object.x_, tile_y, {0x00E3})) {
2215 for (
int s = 0; s < count; s++) {
2224 .draws_to_both_bgs =
false,
2236 .name =
"CustomObject",
2238 .draws_to_both_bgs =
false,
absl::StatusOr< uint16_t > ReadWord(int offset) const
SNES 16-bit tile metadata container.
static CustomObjectManager & Get()
absl::StatusOr< std::shared_ptr< CustomObject > > GetObjectInternal(int object_id, int subtype)
virtual bool IsWaterFaceActive(int room_id) const
virtual bool IsFloorBombable(int room_id) const =0
virtual bool IsWallMoved(int room_id) const =0
virtual bool IsChestOpen(int room_id, int chest_index) const =0
virtual bool IsDoorSwitchActive(int room_id) const =0
virtual bool IsDamFloodgateOpen(int room_id) const
virtual bool IsRupeeFloorCleared(int room_id) const =0
#define LOG_DEBUG(category, format,...)
TileInfo WordToTileInfo(uint16_t word)
constexpr int kGanonTriforceFloorDecor
constexpr int kWaterHopStairsA
constexpr int kArcheryGameTargetDoor
constexpr int kAgahnimsAltar
constexpr int kDamFloodGate
constexpr int kRupeeFloor
constexpr int kWaterfall47
constexpr int kClosedChestPlatform
constexpr int kHorizontalTurtleRockPipe
constexpr int kBigLightBeam
constexpr int kSolidWallDecor3x4
constexpr int kVerticalTurtleRockPipe
constexpr int kWaterHopStairsB
constexpr int kMovingWallWest
constexpr int kMovingWallEast
constexpr int kBigGrayRock
constexpr int kSmithyFurnace
constexpr int kFloorLight
constexpr int kUtility6x3
constexpr int kCustomObject
constexpr int kOpenChestPlatform
constexpr int kUtility3x5
constexpr int kFortuneTellerRoom
constexpr int kBigWallDecor
constexpr int kRightwards3x6
constexpr int kDownwardsHasEdge1x1_1to16_plus23
constexpr int kBossShell4x4
constexpr int kWaterfall48
bool ExistingTileMatchesAny(const gfx::BackgroundBuffer &bg, int tile_x, int tile_y, std::initializer_list< uint16_t > tile_ids)
void WriteTile8(gfx::BackgroundBuffer &bg, int tile_x, int tile_y, const gfx::TileInfo &tile_info)
Write an 8x8 tile to the background buffer.
void DrawNx4(const DrawContext &ctx, int columns, size_t start_index)
std::array< gfx::TileInfo, 3 > LoadMovingWallFillTiles(const DrawContext &ctx)
void DrawMovingWallFill(const DrawContext &ctx, int start_x, int column_count, int height)
bool IsSouthLowerStraightInterroomStairs(int16_t object_id)
bool IsStraightInterroomLower(int16_t object_id)
void DrawRowMajor(gfx::BackgroundBuffer &bg, int base_x, int base_y, int w, int h, std::span< const gfx::TileInfo > tiles, size_t start_index=0)
void DrawOpenChestPlatformSegment(const DrawContext &ctx, int dy, size_t start_index, int fill_width)
void Draw4x4ColumnMajor(const DrawContext &ctx, int x_offset, int y_offset, size_t start_index)
constexpr int kWaterFaceWidthTiles
void DrawWaterHopStairsA(const DrawContext &ctx)
void DrawWaterFaceRows(const DrawContext &ctx, int row_count, int tile_offset)
void Draw1x3NRightwards(const DrawContext &ctx, int columns, size_t start_index, int y_offset=0)
void DrawPlatform3x2(const DrawContext &ctx, int dx, int dy, size_t start_index)
bool IsStraightInterroomUpper(int16_t object_id)
const gfx::TileInfo & TileAtWrapped(std::span< const gfx::TileInfo > tiles, size_t index)
bool IsAutoStairsDualLayer(int16_t object_id)
void Draw4x4ColumnMajorTo(gfx::BackgroundBuffer &bg, const RoomObject &object, std::span< const gfx::TileInfo > tiles)
void Draw1x5Column(const DrawContext &ctx, int x_offset, size_t start_index)
void DrawMany32x32Block(gfx::BackgroundBuffer &bg, int base_x, int base_y, std::span< const gfx::TileInfo > tiles)
void DrawFloorLightGrid(const DrawContext &ctx)
void DrawPlatform2x2(const DrawContext &ctx, int dx, int dy, size_t start_index)
constexpr int kMovingWallFillDataOffset
void DrawMovingWallPlatform(const DrawContext &ctx, int direction)
void WritePlatformTile(const DrawContext &ctx, int dx, int dy, size_t index)
void DrawDamFloodGate(const DrawContext &ctx)
void DrawColumnMajor(gfx::BackgroundBuffer &bg, int base_x, int base_y, int w, int h, std::span< const gfx::TileInfo > tiles, size_t start_index=0)
void DrawPlatform1x3Rightwards(const DrawContext &ctx, int dx, int dy, size_t start_index, int columns)
void DrawWaterHopStairsB(const DrawContext &ctx)
constexpr std::array< uint16_t, 3 > kMovingWallFallbackFillWords
void DrawTableRock4x4_1to16(const DrawContext &ctx)
Draw 4x4 table rock pattern.
void DrawInterRoomFatStairsDownA(const DrawContext &ctx)
Draw inter-room fat stairs going down A (Type 2 object 0x12E)
void DrawSingle2x2(const DrawContext &ctx)
Draw a single 2x2 block (column-major order)
void DrawWaterfall47(const DrawContext &ctx)
Draw waterfall object 0x47 pattern.
void DrawHorizontalTurtleRockPipe(const DrawContext &ctx)
Draw horizontal Turtle Rock pipe (6x4)
void DrawAutoStairs(const DrawContext &ctx)
Draw auto stairs (Type 2/3 objects 0x130-0x133, 0x21B-0x21D, 0x233)
void DrawSpittingWaterFace(const DrawContext &ctx)
Draw spitting water face (Type 3 object 0x201)
void DrawAgahnimsAltar(const DrawContext &ctx)
Draw the fixed 14x14 Agahnim altar with mirrored right half.
void DrawLargeCanvasObject(const DrawContext &ctx, int width, int height)
Draw large canvas object with arbitrary dimensions.
void DrawMovingWallEast(const DrawContext &ctx)
Draw the east-moving wall (Type 1 object 0xCE)
void DrawBigGrayRock(const DrawContext &ctx)
Draw the fixed 4x4 big gray rock as two column-major 4x2 bands.
void DrawChest(const DrawContext &ctx, int chest_index)
Draw a small chest with open/closed state support.
void DrawMovingWallWest(const DrawContext &ctx)
Draw the west-moving wall (Type 1 object 0xCD)
void DrawBed4x5(const DrawContext &ctx)
Draw a 4x5 bed pattern (row-major)
void DrawSingle4x4(const DrawContext &ctx)
Draw a single 4x4 block (column-major order)
void DrawUtility3x5(const DrawContext &ctx)
Draw utility 3x5 pattern (special row pattern)
void DrawDoorSwitcherer(const DrawContext &ctx)
Draw door switcher object with state-based graphics.
void Draw4x4BlocksIn4x4SuperSquare(const DrawContext &ctx)
Draw 4x4 solid blocks in a super square grid.
void DrawBigHole4x4_1to16(const DrawContext &ctx)
Draw 4x4 big hole pattern.
void DrawFloorLight(const DrawContext &ctx)
Draw unconditional floor light (8x8 footprint)
void Draw4x4FloorTwoIn4x4SuperSquare(const DrawContext &ctx)
Draw two 4x4 floor pattern variant.
void DrawSolidWallDecor3x4(const DrawContext &ctx)
Draw solid wall decor 3x4.
void DrawLightBeamOnFloor(const DrawContext &ctx)
Draw floor light beam composed of three 4x4 blocks.
void DrawWaterFace(const DrawContext &ctx)
Draw a generic 2x2 water-face helper pattern.
void DrawTableBowl(const DrawContext &ctx)
Draw a fixed 4x2 table bowl in row-major order.
void DrawChestPlatformVerticalWall(const DrawContext &ctx)
Draw chest platform vertical wall section.
void DrawClosedChestPlatform(const DrawContext &ctx)
Draw closed chest platform (Type 1 object 0xC1)
void DrawSmithyFurnace(const DrawContext &ctx)
Draw the fixed 6x8 smithy furnace in row-major order.
void DrawSpike2x2In4x4SuperSquare(const DrawContext &ctx)
Draw 2x2 spike pattern in super square units.
void DrawSingle4x3(const DrawContext &ctx)
Draw a single 4x3 block (column-major order)
void DrawBigLightBeamOnFloor(const DrawContext &ctx)
Draw state-gated big floor light beam active variant (8x8 footprint)
void DrawOpenChestPlatform(const DrawContext &ctx)
Draw open chest platform (Type 1 object 0xDC)
void DrawSpiralStairs(const DrawContext &ctx, bool going_up, bool is_upper)
Draw spiral stairs (Type 2 objects 0x138-0x13B)
void DrawFortuneTellerRoom(const DrawContext &ctx)
Draw the fixed 14x14 fortune teller room on BG1.
void DrawSomariaLine(const DrawContext &ctx)
Draw one Somaria path tile at the object anchor.
void DrawWaterfall48(const DrawContext &ctx)
Draw waterfall object 0x48 pattern.
void DrawVerticalTurtleRockPipe(const DrawContext &ctx)
Draw vertical Turtle Rock pipe (two stacked 4x3 sections)
void DrawBombableFloor(const DrawContext &ctx)
Draw bombable floor (Type 3 object 0xFC7 / ASM object 0x247)
void DrawDrenchingWaterFace(const DrawContext &ctx)
Draw drenching water face (Type 3 object 0x202)
void DrawEmptyWaterFace(const DrawContext &ctx)
Draw empty water face (Type 3 object 0x200)
void DrawBossShell4x4(const DrawContext &ctx)
Draw boss shell 4x4.
void CustomDraw(const DrawContext &ctx)
Custom draw routine for special objects.
void DrawBigWallDecor(const DrawContext &ctx)
Draw fixed 8x3 big wall decor in column-major order.
void Draw4x4FloorIn4x4SuperSquare(const DrawContext &ctx)
Draw 4x4 floor pattern in super square units.
void DrawInterRoomFatStairsUp(const DrawContext &ctx)
Draw inter-room fat stairs going up (Type 2 object 0x12D)
void Draw3x3FloorIn4x4SuperSquare(const DrawContext &ctx)
Draw 3x3 floor pattern in super square units.
void DrawArcheryGameTargetDoor(const DrawContext &ctx)
Draw archery game target door (two 3x3 sections)
void DrawStraightInterRoomStairs(const DrawContext &ctx)
Draw straight inter-room stairs (Type 3 objects 0x21E-0x229)
void DrawGanonTriforceFloorDecor(const DrawContext &ctx)
Draw Ganon triforce floor decor (three 4x4 sections)
void RegisterSpecialRoutines(std::vector< DrawRoutineInfo > ®istry)
Register all special/miscellaneous draw routines to the registry.
void DrawInterRoomFatStairsDownB(const DrawContext &ctx)
Draw inter-room fat stairs going down B (Type 2 object 0x12F)
void DrawUtility6x3(const DrawContext &ctx)
Draw utility 6x3 pattern via RoomDraw_1x3N_rightwards.
void DrawRightwards3x6(const DrawContext &ctx)
Draw a 6x3 pattern via RoomDraw_1x3N_rightwards semantics.
void DrawChestPlatformHorizontalWall(const DrawContext &ctx)
Draw chest platform horizontal wall section.
void DrawWaterOverlay8x8_1to16(const DrawContext &ctx)
Draw water overlay 8x8 pattern.
void DrawRupeeFloor(const DrawContext &ctx)
Draw the blue rupee floor pattern (5x8 bounds with gaps)
void Draw4x4FloorOneIn4x4SuperSquare(const DrawContext &ctx)
Draw single 4x4 floor pattern variant.
void DrawNothing(const DrawContext &ctx)
Draw nothing - represents invisible logic objects or placeholders.
void DrawActual4x4(const DrawContext &ctx)
Draw an actual 4x4 tile8 pattern (column-major order)
void DrawBigKeyLock(const DrawContext &ctx)
Draw a closed big key lock (Yaze 0xF98 / ASM object 0x218)
void DrawPrisonCell(const DrawContext &ctx)
Draw prison cell with bars (Type 3 objects 0x20D, 0x217)
constexpr int DirectionForSize(int size)
constexpr int ObjectCountForSize(int size)
constexpr int kRoomObjectTileAddress
Context passed to draw routines containing all necessary state.
std::span< const gfx::TileInfo > tiles
gfx::BackgroundBuffer & target_bg
const RoomObject & object
gfx::BackgroundBuffer * secondary_bg
const DungeonState * state
Metadata about a draw routine.