852 const int x = w.Word(0x06A0 + i);
853 out.Store(x, 0x3B3B, S::kStar);
854 out.Store(x + 0x40, 0x3B3B, S::kStar);
860 uint16_t counter = 0x3030;
862 auto next_counter = [&] {
863 counter =
static_cast<uint16_t
>(counter + 0x101);
865 auto stairs = [&](
int end_address,
auto&& body) {
866 const uint16_t end = w.
Word(end_address);
872 auto spiral = [&](uint16_t value) {
873 return [&, value](
int x) {
874 out.
Store(x + 0x01, value, S::kStairs);
875 out.
Store(x + 0x81, value, S::kStairs);
876 out.
Store(x + 0xC1, value, S::kStairs);
877 out.
Store(x + 0x41, counter, S::kStairs);
881 auto straight_north = [&](
int x) {
882 out.
Store(x + 0x81, 0x0000, S::kStairs);
883 out.
Store(x + 0xC1, 0x0000, S::kStairs);
884 out.
Store(x + 0x01, 0x3838, S::kStairs);
885 out.
Store(x + 0x41, counter, S::kStairs);
888 auto straight_south = [&](
int x) {
889 out.
Store(x + 0x01, 0x0000, S::kStairs);
890 out.
Store(x + 0x41, 0x0000, S::kStairs);
891 out.
Store(x + 0xC1, 0x3939, S::kStairs);
892 out.
Store(x + 0x81, counter, S::kStairs);
895 if (w.
Word(0x0438) != 0) {
896 stairs(0x0438, [&](
int x) {
897 out.
Store(x + 0x81, 0x0000, S::kStairs);
898 out.
Store(x + 0x01, 0x2626, S::kStairs);
899 out.
Store(x + 0x41, counter, S::kStairs);
903 stairs(0x047E, spiral(0x5E5E));
904 stairs(0x0482, spiral(0x5F5F));
905 stairs(0x04A2, straight_north);
906 stairs(0x04A4, straight_south);
907 counter =
static_cast<uint16_t
>((counter & 0x0707) | 0x3434);
908 stairs(0x043A, [&](
int x) {
909 out.
Store(x + 0xC1, 0x2626, S::kStairs);
910 out.
Store(x + 0x81, counter, S::kStairs);
913 stairs(0x0480, spiral(0x5E5E));
914 stairs(0x0484, spiral(0x5F5F));
915 stairs(0x04A6, straight_north);
916 stairs(0x04A8, straight_south);
922 if (w.
Word(0x043C) != 0) {
924 end = w.
Word(0x043C);
925 }
else if (w.
Word(0x043E) != 0) {
927 end = w.
Word(0x043E);
928 }
else if (w.
Word(0x0440) != 0) {
930 end = w.
Word(0x0440);
934 const int x = w.
Word(0x06B8 + i);
935 out.
Store(x + 0x0000, 0x0002, S::kLayerStairs);
936 out.
Store(x + 0x10C0, 0x0002, S::kLayerStairs);
937 out.
Store(x + 0x0002, 0x0200, S::kLayerStairs);
938 out.
Store(x + 0x10C2, 0x0200, S::kLayerStairs);
939 out.
Store(x + 0x0040, 0x0001, S::kLayerStairs);
940 out.
Store(x + 0x1080, 0x0001, S::kLayerStairs);
941 out.
Store(x + 0x0042, 0x0100, S::kLayerStairs);
942 out.
Store(x + 0x1082, 0x0100, S::kLayerStairs);
943 out.
Store(x + 0x0041, value, S::kLayerStairs);
944 out.
Store(x + 0x1041, value, S::kLayerStairs);
945 out.
Store(x + 0x0081, value, S::kLayerStairs);
946 out.
Store(x + 0x1081, value, S::kLayerStairs);
949 if (y != w.
Word(0x0448)) {
951 const int x = w.Word(0x06B8 + i);
952 out.Store(x + 0x0000, 0x0A03, S::kWater);
953 out.Store(x + 0x1000, 0x0A03, S::kWater);
954 out.Store(x + 0x0002, 0x030A, S::kWater);
955 out.Store(x + 0x1002, 0x030A, S::kWater);
956 out.Store(x + 0x0040, 0x0803, S::kWater);
957 out.Store(x + 0x0042, 0x0308, S::kWater);
961 if (w.
Word(0x0442) != 0) {
963 const int x = w.Word(0x06B8 + i);
964 out.Store(x + 0x0000, 0x0003, S::kWater);
965 out.Store(x + 0x0002, 0x0300, S::kWater);
966 out.Store(x + 0x1000, 0x0A03, S::kWater);
967 out.Store(x + 0x1002, 0x030A, S::kWater);
968 out.Store(x + 0x0040, 0x0808, S::kWater);
969 out.Store(x + 0x0042, 0x0808, S::kWater);
972 if (y != w.
Word(0x0444)) {
974 const int x = w.Word(0x06B8 + i);
975 out.Store(x + 0x0000, 0x0003, S::kWater);
976 out.Store(x + 0x0002, 0x0300, S::kWater);
977 out.Store(x + 0x1000, 0x0A03, S::kWater);
978 out.Store(x + 0x1002, 0x030A, S::kWater);
988 if ((w.Word(0x0500 + i) & 0x00F0) != 0x0030) {
989 const int x = (w.Word(0x0540 + i) & 0x3FFF) >> 1;
990 out.Store(x, counter, S::kManipulable);
991 out.Store(x + 0x40, counter, S::kManipulable);
997 if (y != w.Word(kTorchEnd)) {
999 ForEachEntry(y, w.Word(kTorchEnd), [&](uint16_t i) {
1000 const int x = (w.Word(0x0540 + i) & 0x3FFF) >> 1;
1001 out.Store(x, counter, S::kTorch);
1002 out.Store(x + 0x40, counter, S::kTorch);
1003 counter = static_cast<uint16_t>((counter & 0xEFEF) + 0x0101);
1008 auto hides_chests = [](uint8_t tag) {
1009 return tag == 0x27 || tag == 0x3C || tag == 0x3E ||
1010 (tag >= 0x29 && tag < 0x33);
1014 bool skip_locks =
false;
1015 if (w.Word(kChestCount) != 0) {
1016 if (hides_chests(tag1) || hides_chests(tag2)) {
1021 const uint16_t entry = w.Word(0x06E0 + i);
1023 const int x = (entry & 0x7FFF) >> 1;
1024 out.Store(x, counter, S::kChest);
1025 out.Store(x + 0x40, counter, S::kChest);
1026 if (entry & 0x8000) {
1027 w.SetWord(0x06E0 + i, static_cast<uint16_t>(entry & 0x7FFF));
1028 out.Store(x + 0x42, counter, S::kChest);
1029 out.Store(x + 0x80, counter, S::kChest);
1030 out.Store(x + 0x82, counter, S::kChest);
1037 if (!skip_locks && y != w.Word(kBigKeyLockEnd)) {
1038 ForEachEntry(y, w.Word(kBigKeyLockEnd), [&](uint16_t i) {
1039 const uint16_t entry = w.Word(0x06E0 + i);
1040 w.SetWord(0x06E0 + i, static_cast<uint16_t>(entry | 0x8000));
1041 const int x = (entry & 0x7FFF) >> 1;
1042 out.Store(x, counter, S::kBigKeyLock);
1043 out.Store(x + 0x40, counter, S::kBigKeyLock);
1051 if (w.Word(0x049A) != 0) {
1053 end = w.Word(0x049A);
1054 }
else if (w.Word(0x049C) != 0) {
1056 end = w.Word(0x049C);
1057 }
else if (w.Word(0x049E) != 0) {
1059 end = w.Word(0x049E);
1063 const int x = w.Word(0x06EC + i);
1064 out.Store(x + 0x1000, 0x0002, S::kLayerStairs);
1065 out.Store(x + 0x00C0, 0x0002, S::kLayerStairs);
1066 out.Store(x + 0x1040, 0x0001, S::kLayerStairs);
1067 out.Store(x + 0x0080, 0x0001, S::kLayerStairs);
1068 out.Store(x + 0x1002, 0x0200, S::kLayerStairs);
1069 out.Store(x + 0x00C2, 0x0200, S::kLayerStairs);
1070 out.Store(x + 0x1042, 0x0100, S::kLayerStairs);
1071 out.Store(x + 0x0082, 0x0100, S::kLayerStairs);
1072 out.Store(x + 0x0041, value, S::kLayerStairs);
1073 out.Store(x + 0x1041, value, S::kLayerStairs);
1074 out.Store(x + 0x0081, value, S::kLayerStairs);
1075 out.Store(x + 0x1081, value, S::kLayerStairs);
1079 if (w.Word(0x04AE) != 0) {
1081 const int x = w.Word(0x06EC + i);
1082 out.Store(x + 0x10C0, 0x0A03, S::kWater);
1083 out.Store(x + 0x10C2, 0x030A, S::kWater);
1084 out.Store(x + 0x00C0, 0x0003, S::kWater);
1085 out.Store(x + 0x00C2, 0x0300, S::kWater);
1086 out.Store(x + 0x0080, 0x0808, S::kWater);
1087 out.Store(x + 0x0082, 0x0808, S::kWater);
1096 auto doorway_properties = [&](uint16_t type) {
1099 auto is_exit_door = [&](uint16_t position) {
1100 for (
int i = 0; i < 4; ++i) {
1108 for (uint16_t y = 0; y < 0x20; y = static_cast<uint16_t>(y + 2)) {
1110 if (position == 0) {
1118 const uint8_t v =
static_cast<uint8_t
>((y >> 1) | 0xF0);
1119 const int x = position >> 1;
1120 out.
Store(x + 0x41,
static_cast<uint16_t
>(v | (v << 8)), S::kLockedDoor);
1121 out.
Store(x + 0x81,
static_cast<uint16_t
>(v | (v << 8)), S::kLockedDoor);
1125 auto full_long = [&] {
1126 uint16_t v = doorway_properties(type);
1127 if (direction == 0) {
1128 const int x = (position >> 1) & 0x783F;
1129 for (
int k = 0; k < 10; ++k) {
1130 out.
Store(x + 0x01 + 0x40 * k, v, S::kDoor);
1132 }
else if (direction == 1) {
1133 if (type == 0x0C || type == 0x10 || type == 0x04 ||
1134 is_exit_door(position & 0x1FFF)) {
1137 const int x = (position >> 1) + 0x40;
1138 for (
int k = 0; k < 8; ++k) {
1139 out.
Store(x + 0x01 + 0x40 * k, v, S::kDoor);
1143 direction == 2 ? ((position >> 1) & 0xFFE0) : (position >> 1) + 1;
1144 const uint16_t v2 =
static_cast<uint16_t
>(v + 0x0101);
1145 for (
int o : {0x40, 0x42, 0x44, 0x46, 0x80, 0x82, 0x84, 0x86}) {
1146 out.
Store(x + o, v2, S::kDoor);
1152 auto doorway = [&] {
1153 if (type >= 0x20 && type < 0x28) {
1156 uint16_t v = doorway_properties(type);
1157 if (direction == 0) {
1158 if (is_exit_door(position)) {
1161 const int x = (position >> 1) & 0x783F;
1162 for (
int k = 0; k < 7; ++k) {
1163 out.
Store(x + 0x01 + 0x40 * k, v, S::kDoor);
1165 out.
Store(x + 0x1C1, 0x0000, S::kDoor);
1166 }
else if (direction == 1) {
1167 if (type == 0x0A || type == 0x0E || is_exit_door(position)) {
1170 const int x = position >> 1;
1171 for (
int o : {0x41, 0x81, 0xC1, 0x101, 0x141}) {
1172 out.
Store(x + o, v, S::kDoor);
1174 }
else if (direction == 2) {
1175 const int x = (position >> 1) & 0xFFE0;
1176 const uint16_t v2 =
static_cast<uint16_t
>(v + 0x0101);
1177 for (
int o : {0x40, 0x42, 0x80, 0x82}) {
1178 out.
Store(x + o, v2, S::kDoor);
1180 out.
Store(x + 0x44, v2 & 0x00FF, S::kDoor);
1181 out.
Store(x + 0x84, v2 & 0x00FF, S::kDoor);
1183 const int x = position >> 1;
1184 const uint16_t v2 =
static_cast<uint16_t
>(v + 0x0101);
1185 for (
int o : {0x42, 0x44, 0x82, 0x84}) {
1186 out.
Store(x + o, v2, S::kDoor);
1188 out.
Store(x + 0x40, v2 & 0xFF00, S::kDoor);
1189 out.
Store(x + 0x80, v2 & 0xFF00, S::kDoor);
1194 if (type == 0x00 || type == 0x06 || type == 0x12 || type == 0x0A ||
1197 }
else if (type == 0x0C || type == 0x10 || type == 0x04 || type == 0x02 ||
1200 }
else if (type == 0x30) {
1202 }
else if (type >= 0x40) {
1203 if (type == 0x40 || type == 0x46 ||
1210 const uint16_t mask_index =
1211 type == 0x18 ? (y & 0xFF) : (y & 0x0F);
1223 auto toggles = [&](
int counter,
int list, uint16_t bits) {
1224 const uint16_t count = w.
Word(counter);
1230 const int x = w.
Word(list + i);
1231 if ((out.
Word(x) & 0x00F0) == 0x0080) {
1232 const uint16_t v = out.Word(x) | bits;
1233 out.Store(x, v, S::kDoorLayerToggle);
1234 out.Store(x + 0x40, v, S::kDoorLayerToggle);
1236 const uint16_t v = out.Word(x + 0x1000) | bits;
1237 out.Store(x + 0x1000, v, S::kDoorLayerToggle);
1238 out.Store(x + 0x1040, v, S::kDoorLayerToggle);
1247 if (door_switch != 0) {
1248 int x = (door_switch & 0x3FFF) >> 1;
1249 const int columns = (door_switch & 0x8000) ? 6 : 5;
1251 for (
int i = 0; i < columns; ++i, x += 2) {
1253 out.
Store(x, 0x0101, S::kDoorSwitch);
1254 out.
Store(x + 0x280, 0x0101, S::kDoorSwitch);
1255 for (
int o : {0x80, 0x100, 0x180, 0x200}) {
1256 out.
Store(x + o, 0x0000, S::kDoorSwitch);
1259 for (
int o : {0x80, 0x100, 0x180, 0x200}) {
1260 out.
Store(x + o, 0x2323, S::kDoorSwitch);