855 const int x = w.Word(0x06A0 + i);
856 out.Store(x, 0x3B3B, S::kStar);
857 out.Store(x + 0x40, 0x3B3B, S::kStar);
863 uint16_t counter = 0x3030;
865 auto next_counter = [&] {
866 counter =
static_cast<uint16_t
>(counter + 0x101);
868 auto stairs = [&](
int end_address,
auto&& body) {
869 const uint16_t end = w.
Word(end_address);
875 auto spiral = [&](uint16_t value) {
876 return [&, value](
int x) {
877 out.
Store(x + 0x01, value, S::kStairs);
878 out.
Store(x + 0x81, value, S::kStairs);
879 out.
Store(x + 0xC1, value, S::kStairs);
880 out.
Store(x + 0x41, counter, S::kStairs);
884 auto straight_north = [&](
int x) {
885 out.
Store(x + 0x81, 0x0000, S::kStairs);
886 out.
Store(x + 0xC1, 0x0000, S::kStairs);
887 out.
Store(x + 0x01, 0x3838, S::kStairs);
888 out.
Store(x + 0x41, counter, S::kStairs);
891 auto straight_south = [&](
int x) {
892 out.
Store(x + 0x01, 0x0000, S::kStairs);
893 out.
Store(x + 0x41, 0x0000, S::kStairs);
894 out.
Store(x + 0xC1, 0x3939, S::kStairs);
895 out.
Store(x + 0x81, counter, S::kStairs);
898 if (w.
Word(0x0438) != 0) {
899 stairs(0x0438, [&](
int x) {
900 out.
Store(x + 0x81, 0x0000, S::kStairs);
901 out.
Store(x + 0x01, 0x2626, S::kStairs);
902 out.
Store(x + 0x41, counter, S::kStairs);
906 stairs(0x047E, spiral(0x5E5E));
907 stairs(0x0482, spiral(0x5F5F));
908 stairs(0x04A2, straight_north);
909 stairs(0x04A4, straight_south);
910 counter =
static_cast<uint16_t
>((counter & 0x0707) | 0x3434);
911 stairs(0x043A, [&](
int x) {
912 out.
Store(x + 0xC1, 0x2626, S::kStairs);
913 out.
Store(x + 0x81, counter, S::kStairs);
916 stairs(0x0480, spiral(0x5E5E));
917 stairs(0x0484, spiral(0x5F5F));
918 stairs(0x04A6, straight_north);
919 stairs(0x04A8, straight_south);
925 if (w.
Word(0x043C) != 0) {
927 end = w.
Word(0x043C);
928 }
else if (w.
Word(0x043E) != 0) {
930 end = w.
Word(0x043E);
931 }
else if (w.
Word(0x0440) != 0) {
933 end = w.
Word(0x0440);
937 const int x = w.
Word(0x06B8 + i);
938 out.
Store(x + 0x0000, 0x0002, S::kLayerStairs);
939 out.
Store(x + 0x10C0, 0x0002, S::kLayerStairs);
940 out.
Store(x + 0x0002, 0x0200, S::kLayerStairs);
941 out.
Store(x + 0x10C2, 0x0200, S::kLayerStairs);
942 out.
Store(x + 0x0040, 0x0001, S::kLayerStairs);
943 out.
Store(x + 0x1080, 0x0001, S::kLayerStairs);
944 out.
Store(x + 0x0042, 0x0100, S::kLayerStairs);
945 out.
Store(x + 0x1082, 0x0100, S::kLayerStairs);
946 out.
Store(x + 0x0041, value, S::kLayerStairs);
947 out.
Store(x + 0x1041, value, S::kLayerStairs);
948 out.
Store(x + 0x0081, value, S::kLayerStairs);
949 out.
Store(x + 0x1081, value, S::kLayerStairs);
952 if (y != w.
Word(0x0448)) {
954 const int x = w.Word(0x06B8 + i);
955 out.Store(x + 0x0000, 0x0A03, S::kWater);
956 out.Store(x + 0x1000, 0x0A03, S::kWater);
957 out.Store(x + 0x0002, 0x030A, S::kWater);
958 out.Store(x + 0x1002, 0x030A, S::kWater);
959 out.Store(x + 0x0040, 0x0803, S::kWater);
960 out.Store(x + 0x0042, 0x0308, S::kWater);
964 if (w.
Word(0x0442) != 0) {
966 const int x = w.Word(0x06B8 + i);
967 out.Store(x + 0x0000, 0x0003, S::kWater);
968 out.Store(x + 0x0002, 0x0300, S::kWater);
969 out.Store(x + 0x1000, 0x0A03, S::kWater);
970 out.Store(x + 0x1002, 0x030A, S::kWater);
971 out.Store(x + 0x0040, 0x0808, S::kWater);
972 out.Store(x + 0x0042, 0x0808, S::kWater);
975 if (y != w.
Word(0x0444)) {
977 const int x = w.Word(0x06B8 + i);
978 out.Store(x + 0x0000, 0x0003, S::kWater);
979 out.Store(x + 0x0002, 0x0300, S::kWater);
980 out.Store(x + 0x1000, 0x0A03, S::kWater);
981 out.Store(x + 0x1002, 0x030A, S::kWater);
991 if ((w.Word(0x0500 + i) & 0x00F0) != 0x0030) {
992 const int x = (w.Word(0x0540 + i) & 0x3FFF) >> 1;
993 out.Store(x, counter, S::kManipulable);
994 out.Store(x + 0x40, counter, S::kManipulable);
1000 if (y != w.Word(kTorchEnd)) {
1002 ForEachEntry(y, w.Word(kTorchEnd), [&](uint16_t i) {
1003 const int x = (w.Word(0x0540 + i) & 0x3FFF) >> 1;
1004 out.Store(x, counter, S::kTorch);
1005 out.Store(x + 0x40, counter, S::kTorch);
1006 counter = static_cast<uint16_t>((counter & 0xEFEF) + 0x0101);
1011 auto hides_chests = [](uint8_t tag) {
1012 return tag == 0x27 || tag == 0x3C || tag == 0x3E ||
1013 (tag >= 0x29 && tag < 0x33);
1017 bool skip_locks =
false;
1018 if (w.Word(kChestCount) != 0) {
1019 if (hides_chests(tag1) || hides_chests(tag2)) {
1024 const uint16_t entry = w.Word(0x06E0 + i);
1026 const int x = (entry & 0x7FFF) >> 1;
1027 out.Store(x, counter, S::kChest);
1028 out.Store(x + 0x40, counter, S::kChest);
1029 if (entry & 0x8000) {
1030 w.SetWord(0x06E0 + i, static_cast<uint16_t>(entry & 0x7FFF));
1031 out.Store(x + 0x42, counter, S::kChest);
1032 out.Store(x + 0x80, counter, S::kChest);
1033 out.Store(x + 0x82, counter, S::kChest);
1040 if (!skip_locks && y != w.Word(kBigKeyLockEnd)) {
1041 ForEachEntry(y, w.Word(kBigKeyLockEnd), [&](uint16_t i) {
1042 const uint16_t entry = w.Word(0x06E0 + i);
1043 w.SetWord(0x06E0 + i, static_cast<uint16_t>(entry | 0x8000));
1044 const int x = (entry & 0x7FFF) >> 1;
1045 out.Store(x, counter, S::kBigKeyLock);
1046 out.Store(x + 0x40, counter, S::kBigKeyLock);
1054 if (w.Word(0x049A) != 0) {
1056 end = w.Word(0x049A);
1057 }
else if (w.Word(0x049C) != 0) {
1059 end = w.Word(0x049C);
1060 }
else if (w.Word(0x049E) != 0) {
1062 end = w.Word(0x049E);
1066 const int x = w.Word(0x06EC + i);
1067 out.Store(x + 0x1000, 0x0002, S::kLayerStairs);
1068 out.Store(x + 0x00C0, 0x0002, S::kLayerStairs);
1069 out.Store(x + 0x1040, 0x0001, S::kLayerStairs);
1070 out.Store(x + 0x0080, 0x0001, S::kLayerStairs);
1071 out.Store(x + 0x1002, 0x0200, S::kLayerStairs);
1072 out.Store(x + 0x00C2, 0x0200, S::kLayerStairs);
1073 out.Store(x + 0x1042, 0x0100, S::kLayerStairs);
1074 out.Store(x + 0x0082, 0x0100, S::kLayerStairs);
1075 out.Store(x + 0x0041, value, S::kLayerStairs);
1076 out.Store(x + 0x1041, value, S::kLayerStairs);
1077 out.Store(x + 0x0081, value, S::kLayerStairs);
1078 out.Store(x + 0x1081, value, S::kLayerStairs);
1082 if (w.Word(0x04AE) != 0) {
1084 const int x = w.Word(0x06EC + i);
1085 out.Store(x + 0x10C0, 0x0A03, S::kWater);
1086 out.Store(x + 0x10C2, 0x030A, S::kWater);
1087 out.Store(x + 0x00C0, 0x0003, S::kWater);
1088 out.Store(x + 0x00C2, 0x0300, S::kWater);
1089 out.Store(x + 0x0080, 0x0808, S::kWater);
1090 out.Store(x + 0x0082, 0x0808, S::kWater);
1099 auto doorway_properties = [&](uint16_t type) {
1102 auto is_exit_door = [&](uint16_t position) {
1103 for (
int i = 0; i < 4; ++i) {
1111 for (uint16_t y = 0; y < 0x20; y = static_cast<uint16_t>(y + 2)) {
1113 if (position == 0) {
1121 const uint8_t v =
static_cast<uint8_t
>((y >> 1) | 0xF0);
1122 const int x = position >> 1;
1123 out.
Store(x + 0x41,
static_cast<uint16_t
>(v | (v << 8)), S::kLockedDoor);
1124 out.
Store(x + 0x81,
static_cast<uint16_t
>(v | (v << 8)), S::kLockedDoor);
1128 auto full_long = [&] {
1129 uint16_t v = doorway_properties(type);
1130 if (direction == 0) {
1131 const int x = (position >> 1) & 0x783F;
1132 for (
int k = 0; k < 10; ++k) {
1133 out.
Store(x + 0x01 + 0x40 * k, v, S::kDoor);
1135 }
else if (direction == 1) {
1136 if (type == 0x0C || type == 0x10 || type == 0x04 ||
1137 is_exit_door(position & 0x1FFF)) {
1140 const int x = (position >> 1) + 0x40;
1141 for (
int k = 0; k < 8; ++k) {
1142 out.
Store(x + 0x01 + 0x40 * k, v, S::kDoor);
1146 direction == 2 ? ((position >> 1) & 0xFFE0) : (position >> 1) + 1;
1147 const uint16_t v2 =
static_cast<uint16_t
>(v + 0x0101);
1148 for (
int o : {0x40, 0x42, 0x44, 0x46, 0x80, 0x82, 0x84, 0x86}) {
1149 out.
Store(x + o, v2, S::kDoor);
1155 auto doorway = [&] {
1156 if (type >= 0x20 && type < 0x28) {
1159 uint16_t v = doorway_properties(type);
1160 if (direction == 0) {
1161 if (is_exit_door(position)) {
1164 const int x = (position >> 1) & 0x783F;
1165 for (
int k = 0; k < 7; ++k) {
1166 out.
Store(x + 0x01 + 0x40 * k, v, S::kDoor);
1168 out.
Store(x + 0x1C1, 0x0000, S::kDoor);
1169 }
else if (direction == 1) {
1170 if (type == 0x0A || type == 0x0E || is_exit_door(position)) {
1173 const int x = position >> 1;
1174 for (
int o : {0x41, 0x81, 0xC1, 0x101, 0x141}) {
1175 out.
Store(x + o, v, S::kDoor);
1177 }
else if (direction == 2) {
1178 const int x = (position >> 1) & 0xFFE0;
1179 const uint16_t v2 =
static_cast<uint16_t
>(v + 0x0101);
1180 for (
int o : {0x40, 0x42, 0x80, 0x82}) {
1181 out.
Store(x + o, v2, S::kDoor);
1183 out.
Store(x + 0x44, v2 & 0x00FF, S::kDoor);
1184 out.
Store(x + 0x84, v2 & 0x00FF, S::kDoor);
1186 const int x = position >> 1;
1187 const uint16_t v2 =
static_cast<uint16_t
>(v + 0x0101);
1188 for (
int o : {0x42, 0x44, 0x82, 0x84}) {
1189 out.
Store(x + o, v2, S::kDoor);
1191 out.
Store(x + 0x40, v2 & 0xFF00, S::kDoor);
1192 out.
Store(x + 0x80, v2 & 0xFF00, S::kDoor);
1197 if (type == 0x00 || type == 0x06 || type == 0x12 || type == 0x0A ||
1200 }
else if (type == 0x0C || type == 0x10 || type == 0x04 || type == 0x02 ||
1203 }
else if (type == 0x30) {
1205 }
else if (type >= 0x40) {
1206 if (type == 0x40 || type == 0x46 ||
1213 const uint16_t mask_index =
1214 type == 0x18 ? (y & 0xFF) : (y & 0x0F);
1226 auto toggles = [&](
int counter,
int list, uint16_t bits) {
1227 const uint16_t count = w.
Word(counter);
1233 const int x = w.
Word(list + i);
1234 if ((out.
Word(x) & 0x00F0) == 0x0080) {
1235 const uint16_t v = out.Word(x) | bits;
1236 out.Store(x, v, S::kDoorLayerToggle);
1237 out.Store(x + 0x40, v, S::kDoorLayerToggle);
1239 const uint16_t v = out.Word(x + 0x1000) | bits;
1240 out.Store(x + 0x1000, v, S::kDoorLayerToggle);
1241 out.Store(x + 0x1040, v, S::kDoorLayerToggle);
1250 if (door_switch != 0) {
1251 int x = (door_switch & 0x3FFF) >> 1;
1252 const int columns = (door_switch & 0x8000) ? 6 : 5;
1254 for (
int i = 0; i < columns; ++i, x += 2) {
1256 out.
Store(x, 0x0101, S::kDoorSwitch);
1257 out.
Store(x + 0x280, 0x0101, S::kDoorSwitch);
1258 for (
int o : {0x80, 0x100, 0x180, 0x200}) {
1259 out.
Store(x + o, 0x0000, S::kDoorSwitch);
1262 for (
int o : {0x80, 0x100, 0x180, 0x200}) {
1263 out.
Store(x + o, 0x2323, S::kDoorSwitch);