yaze 0.2.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
overworld.cc
Go to the documentation of this file.
1#include "overworld.h"
2
3#include <algorithm>
4#include <future>
5#include <unordered_map>
6#include <vector>
7
8#include "absl/status/status.h"
9#include "app/core/features.h"
10#include "app/gfx/compression.h"
11#include "app/gfx/snes_tile.h"
12#include "app/rom.h"
13#include "app/snes.h"
14#include "util/hex.h"
15#include "util/log.h"
16#include "util/macro.h"
17
18namespace yaze {
19namespace zelda3 {
20
21absl::Status Overworld::Load(Rom *rom) {
22 if (rom->size() == 0) {
23 return absl::InvalidArgumentError("ROM file not loaded");
24 }
25 rom_ = rom;
26
30
31 for (int map_index = 0; map_index < kNumOverworldMaps; ++map_index)
32 overworld_maps_.emplace_back(map_index, rom_);
33
41
42 is_loaded_ = true;
43 return absl::OkStatus();
44}
45
47 for (int i = 128; i < 145; i++) {
48 overworld_maps_[i].SetAsSmallMap(0);
49 }
50
51 overworld_maps_[129].SetAsLargeMap(129, 0);
52 overworld_maps_[130].SetAsLargeMap(129, 1);
53 overworld_maps_[137].SetAsLargeMap(129, 2);
54 overworld_maps_[138].SetAsLargeMap(129, 3);
55 overworld_maps_[136].SetAsSmallMap();
56
57 std::array<bool, kNumMapsPerWorld> map_checked;
58 std::fill(map_checked.begin(), map_checked.end(), false);
59
60 int xx = 0;
61 int yy = 0;
62 while (true) {
63 if (int i = xx + (yy * 8); map_checked[i] == false) {
64 if (overworld_maps_[i].is_large_map()) {
65 map_checked[i] = true;
66 overworld_maps_[i].SetAsLargeMap(i, 0);
67 overworld_maps_[i + 64].SetAsLargeMap(i + 64, 0);
68
69 map_checked[i + 1] = true;
70 overworld_maps_[i + 1].SetAsLargeMap(i, 1);
71 overworld_maps_[i + 65].SetAsLargeMap(i + 64, 1);
72
73 map_checked[i + 8] = true;
74 overworld_maps_[i + 8].SetAsLargeMap(i, 2);
75 overworld_maps_[i + 72].SetAsLargeMap(i + 64, 2);
76
77 map_checked[i + 9] = true;
78 overworld_maps_[i + 9].SetAsLargeMap(i, 3);
79 overworld_maps_[i + 73].SetAsLargeMap(i + 64, 3);
80 xx++;
81 } else {
82 overworld_maps_[i].SetAsSmallMap();
83 overworld_maps_[i + 64].SetAsSmallMap();
84 map_checked[i] = true;
85 }
86 }
87
88 xx++;
89 if (xx >= 8) {
90 xx = 0;
91 yy += 1;
92 if (yy >= 8) {
93 break;
94 }
95 }
96 }
97}
98
99absl::StatusOr<uint16_t> Overworld::GetTile16ForTile32(
100 int index, int quadrant, int dimension, const uint32_t *map32address) {
102 auto arg1, rom()->ReadByte(map32address[dimension] + quadrant + (index)));
103 ASSIGN_OR_RETURN(auto arg2,
104 rom()->ReadWord(map32address[dimension] + (index) +
105 (quadrant <= 1 ? 4 : 5)));
106 return (uint16_t)(arg1 +
107 (((arg2 >> (quadrant % 2 == 0 ? 4 : 0)) & 0x0F) * 256));
108}
109
111 constexpr int kMap32TilesLength = 0x33F0;
112 int num_tile32 = kMap32TilesLength;
113 uint32_t map32address[4] = {rom()->version_constants().kMap32TileTL,
114 rom()->version_constants().kMap32TileTR,
115 rom()->version_constants().kMap32TileBL,
116 rom()->version_constants().kMap32TileBR};
117 if (rom()->data()[kMap32ExpandedFlagPos] != 0x04 &&
118 core::FeatureFlags::get().overworld.kLoadCustomOverworld) {
119 map32address[0] = rom()->version_constants().kMap32TileTL;
120 map32address[1] = kMap32TileTRExpanded;
121 map32address[2] = kMap32TileBLExpanded;
122 map32address[3] = kMap32TileBRExpanded;
123 num_tile32 = kMap32TileCountExpanded;
124 expanded_tile32_ = true;
125 }
126
127 // Loop through each 32x32 pixel tile in the rom
128 for (int i = 0; i < num_tile32; i += 6) {
129 // Loop through each quadrant of the 32x32 pixel tile.
130 for (int k = 0; k < 4; k++) {
131 // Generate the 16-bit tile for the current quadrant of the current
132 // 32x32 pixel tile.
134 uint16_t tl,
135 GetTile16ForTile32(i, k, (int)Dimension::map32TilesTL, map32address));
137 uint16_t tr,
138 GetTile16ForTile32(i, k, (int)Dimension::map32TilesTR, map32address));
140 uint16_t bl,
141 GetTile16ForTile32(i, k, (int)Dimension::map32TilesBL, map32address));
143 uint16_t br,
144 GetTile16ForTile32(i, k, (int)Dimension::map32TilesBR, map32address));
145
146 // Add the generated 16-bit tiles to the tiles32 vector.
147 tiles32_unique_.emplace_back(gfx::Tile32(tl, tr, bl, br));
148 }
149 }
150
151 map_tiles_.light_world.resize(0x200);
152 map_tiles_.dark_world.resize(0x200);
153 map_tiles_.special_world.resize(0x200);
154 for (int i = 0; i < 0x200; i++) {
155 map_tiles_.light_world[i].resize(0x200);
156 map_tiles_.dark_world[i].resize(0x200);
157 map_tiles_.special_world[i].resize(0x200);
158 }
159
160 return absl::OkStatus();
161}
162
164 int tpos = kMap16Tiles;
165 int num_tile16 = kNumTile16Individual;
166 if (rom()->data()[kMap16ExpandedFlagPos] != 0x0F &&
167 core::FeatureFlags::get().overworld.kLoadCustomOverworld) {
168 tpos = kMap16TilesExpanded;
169 num_tile16 = NumberOfMap16Ex;
170 expanded_tile16_ = true;
171 }
172
173 for (int i = 0; i < num_tile16; i += 1) {
174 ASSIGN_OR_RETURN(auto t0_data, rom()->ReadWord(tpos));
175 gfx::TileInfo t0 = gfx::GetTilesInfo(t0_data);
176 tpos += 2;
177 ASSIGN_OR_RETURN(auto t1_data, rom()->ReadWord(tpos));
178 gfx::TileInfo t1 = gfx::GetTilesInfo(t1_data);
179 tpos += 2;
180 ASSIGN_OR_RETURN(auto t2_data, rom()->ReadWord(tpos));
181 gfx::TileInfo t2 = gfx::GetTilesInfo(t2_data);
182 tpos += 2;
183 ASSIGN_OR_RETURN(auto t3_data, rom()->ReadWord(tpos));
184 gfx::TileInfo t3 = gfx::GetTilesInfo(t3_data);
185 tpos += 2;
186 tiles16_.emplace_back(t0, t1, t2, t3);
187 }
188 return absl::OkStatus();
189}
190
191void Overworld::AssignWorldTiles(int x, int y, int sx, int sy, int tpos,
192 OverworldBlockset &world) {
193 int position_x1 = (x * 2) + (sx * 32);
194 int position_y1 = (y * 2) + (sy * 32);
195 int position_x2 = (x * 2) + 1 + (sx * 32);
196 int position_y2 = (y * 2) + 1 + (sy * 32);
197 world[position_x1][position_y1] = tiles32_unique_[tpos].tile0_;
198 world[position_x2][position_y1] = tiles32_unique_[tpos].tile1_;
199 world[position_x1][position_y2] = tiles32_unique_[tpos].tile2_;
200 world[position_x2][position_y2] = tiles32_unique_[tpos].tile3_;
201}
202
203void Overworld::OrganizeMapTiles(std::vector<uint8_t> &bytes,
204 std::vector<uint8_t> &bytes2, int i, int sx,
205 int sy, int &ttpos) {
206 for (int y = 0; y < 16; y++) {
207 for (int x = 0; x < 16; x++) {
208 auto tidD = (uint16_t)((bytes2[ttpos] << 8) + bytes[ttpos]);
209 if (int tpos = tidD; tpos < tiles32_unique_.size()) {
210 if (i < kDarkWorldMapIdStart) {
211 AssignWorldTiles(x, y, sx, sy, tpos, map_tiles_.light_world);
212 } else if (i < kSpecialWorldMapIdStart && i >= kDarkWorldMapIdStart) {
213 AssignWorldTiles(x, y, sx, sy, tpos, map_tiles_.dark_world);
214 } else {
215 AssignWorldTiles(x, y, sx, sy, tpos, map_tiles_.special_world);
216 }
217 }
218 ttpos += 1;
219 }
220 }
221}
222
224 const auto get_ow_map_gfx_ptr = [this](int index, uint32_t map_ptr) {
225 int p = (rom()->data()[map_ptr + 2 + (3 * index)] << 16) +
226 (rom()->data()[map_ptr + 1 + (3 * index)] << 8) +
227 (rom()->data()[map_ptr + (3 * index)]);
228 return SnesToPc(p);
229 };
230
231 constexpr uint32_t kBaseLowest = 0x0FFFFF;
232 constexpr uint32_t kBaseHighest = 0x0F8000;
233
234 uint32_t lowest = kBaseLowest;
235 uint32_t highest = kBaseHighest;
236 int sx = 0;
237 int sy = 0;
238 int c = 0;
239 for (int i = 0; i < kNumOverworldMaps; i++) {
240 auto p1 = get_ow_map_gfx_ptr(
241 i, rom()->version_constants().kCompressedAllMap32PointersHigh);
242 auto p2 = get_ow_map_gfx_ptr(
243 i, rom()->version_constants().kCompressedAllMap32PointersLow);
244
245 int ttpos = 0;
246
247 if (p1 >= highest) highest = p1;
248 if (p2 >= highest) highest = p2;
249
250 if (p1 <= lowest && p1 > kBaseHighest) lowest = p1;
251 if (p2 <= lowest && p2 > kBaseHighest) lowest = p2;
252
253 int size1, size2;
254 auto bytes = gfx::HyruleMagicDecompress(rom()->data() + p2, &size1, 1);
255 auto bytes2 = gfx::HyruleMagicDecompress(rom()->data() + p1, &size2, 1);
256 OrganizeMapTiles(bytes, bytes2, i, sx, sy, ttpos);
257
258 sx++;
259 if (sx >= 8) {
260 sy++;
261 sx = 0;
262 }
263
264 c++;
265 if (c >= 64) {
266 sx = 0;
267 sy = 0;
268 c = 0;
269 }
270 }
271}
272
274 auto size = tiles16_.size();
275 std::vector<std::future<absl::Status>> futures;
276 for (int i = 0; i < kNumOverworldMaps; ++i) {
277 int world_type = 0;
279 world_type = 1;
280 } else if (i >= kSpecialWorldMapIdStart) {
281 world_type = 2;
282 }
283 auto task_function = [this, i, size, world_type]() {
284 return overworld_maps_[i].BuildMap(size, game_state_, world_type,
285 tiles16_, GetMapTiles(world_type));
286 };
287 futures.emplace_back(std::async(std::launch::async, task_function));
288 }
289
290 // Wait for all tasks to complete and check their results
291 for (auto &future : futures) {
292 future.wait();
293 RETURN_IF_ERROR(future.get());
294 }
295 return absl::OkStatus();
296}
297
299 for (int i = 0; i < kNumTileTypes; ++i) {
301 rom()->data()[rom()->version_constants().kOverworldTilesType + i];
302 }
303}
304
306 int ow_entrance_map_ptr = kOverworldEntranceMap;
307 int ow_entrance_pos_ptr = kOverworldEntrancePos;
308 int ow_entrance_id_ptr = kOverworldEntranceEntranceId;
309 int num_entrances = 129;
310 if (rom()->data()[kOverworldEntranceExpandedFlagPos] != 0xB8 &&
311 core::FeatureFlags::get().overworld.kLoadCustomOverworld) {
312 ow_entrance_map_ptr = kOverworldEntranceMapExpanded;
313 ow_entrance_pos_ptr = kOverworldEntrancePosExpanded;
314 ow_entrance_id_ptr = kOverworldEntranceEntranceIdExpanded;
315 expanded_entrances_ = true;
316 }
317
318 for (int i = 0; i < num_entrances; i++) {
319 ASSIGN_OR_RETURN(auto map_id,
320 rom()->ReadWord(ow_entrance_map_ptr + (i * 2)));
321 ASSIGN_OR_RETURN(auto map_pos,
322 rom()->ReadWord(ow_entrance_pos_ptr + (i * 2)));
323 ASSIGN_OR_RETURN(auto entrance_id, rom()->ReadByte(ow_entrance_id_ptr + i));
324 int p = map_pos >> 1;
325 int x = (p % 64);
326 int y = (p >> 6);
327 bool deleted = false;
328 if (map_pos == 0xFFFF) {
329 deleted = true;
330 }
331 all_entrances_.emplace_back(
332 (x * 16) + (((map_id % 64) - (((map_id % 64) / 8) * 8)) * 512),
333 (y * 16) + (((map_id % 64) / 8) * 512), entrance_id, map_id, map_pos,
334 deleted);
335 }
336
337 return absl::OkStatus();
338}
339
340absl::Status Overworld::LoadHoles() {
341 constexpr int kNumHoles = 0x13;
342 for (int i = 0; i < kNumHoles; i++) {
343 ASSIGN_OR_RETURN(auto map_id,
344 rom()->ReadWord(kOverworldHoleArea + (i * 2)));
345 ASSIGN_OR_RETURN(auto map_pos,
346 rom()->ReadWord(kOverworldHolePos + (i * 2)));
347 ASSIGN_OR_RETURN(auto entrance_id,
348 rom()->ReadByte(kOverworldHoleEntrance + i));
349 int p = (map_pos + 0x400) >> 1;
350 int x = (p % 64);
351 int y = (p >> 6);
352 all_holes_.emplace_back(
353 (x * 16) + (((map_id % 64) - (((map_id % 64) / 8) * 8)) * 512),
354 (y * 16) + (((map_id % 64) / 8) * 512), entrance_id, map_id,
355 (uint16_t)(map_pos + 0x400), true);
356 }
357 return absl::OkStatus();
358}
359
360absl::Status Overworld::LoadExits() {
361 const int NumberOfOverworldExits = 0x4F;
362 std::vector<OverworldExit> exits;
363 for (int i = 0; i < NumberOfOverworldExits; i++) {
364 auto rom_data = rom()->data();
365
366 uint16_t exit_room_id;
367 uint16_t exit_map_id;
368 uint16_t exit_vram;
369 uint16_t exit_y_scroll;
370 uint16_t exit_x_scroll;
371 uint16_t exit_y_player;
372 uint16_t exit_x_player;
373 uint16_t exit_y_camera;
374 uint16_t exit_x_camera;
375 uint16_t exit_scroll_mod_y;
376 uint16_t exit_scroll_mod_x;
377 uint16_t exit_door_type_1;
378 uint16_t exit_door_type_2;
379 RETURN_IF_ERROR(rom()->ReadTransaction(
380 exit_room_id, (OWExitRoomId + (i * 2)), exit_map_id, OWExitMapId + i,
381 exit_vram, OWExitVram + (i * 2), exit_y_scroll, OWExitYScroll + (i * 2),
382 exit_x_scroll, OWExitXScroll + (i * 2), exit_y_player,
383 OWExitYPlayer + (i * 2), exit_x_player, OWExitXPlayer + (i * 2),
384 exit_y_camera, OWExitYCamera + (i * 2), exit_x_camera,
385 OWExitXCamera + (i * 2), exit_scroll_mod_y, OWExitUnk1 + i,
386 exit_scroll_mod_x, OWExitUnk2 + i, exit_door_type_1,
387 OWExitDoorType1 + (i * 2), exit_door_type_2,
388 OWExitDoorType2 + (i * 2)));
389
390 uint16_t py = (uint16_t)((rom_data[OWExitYPlayer + (i * 2) + 1] << 8) +
391 rom_data[OWExitYPlayer + (i * 2)]);
392 uint16_t px = (uint16_t)((rom_data[OWExitXPlayer + (i * 2) + 1] << 8) +
393 rom_data[OWExitXPlayer + (i * 2)]);
394
395 util::logf(
396 "Exit: %d RoomID: %d MapID: %d VRAM: %d YScroll: %d XScroll: "
397 "%d YPlayer: %d XPlayer: %d YCamera: %d XCamera: %d "
398 "ScrollModY: %d ScrollModX: %d DoorType1: %d DoorType2: %d",
399 i, exit_room_id, exit_map_id, exit_vram, exit_y_scroll, exit_x_scroll,
400 py, px, exit_y_camera, exit_x_camera, exit_scroll_mod_y,
401 exit_scroll_mod_x, exit_door_type_1, exit_door_type_2);
402
403 exits.emplace_back(exit_room_id, exit_map_id, exit_vram, exit_y_scroll,
404 exit_x_scroll, py, px, exit_y_camera, exit_x_camera,
405 exit_scroll_mod_y, exit_scroll_mod_x, exit_door_type_1,
406 exit_door_type_2, (px & py) == 0xFFFF);
407 }
409 return absl::OkStatus();
410}
411
412absl::Status Overworld::LoadItems() {
413 ASSIGN_OR_RETURN(uint32_t pointer,
415 uint32_t pointer_pc = SnesToPc(pointer); // 1BC2F9 -> 0DC2F9
416 for (int i = 0; i < 128; i++) {
417 ASSIGN_OR_RETURN(uint16_t word_address,
418 rom()->ReadWord(pointer_pc + i * 2));
419 uint32_t addr = (pointer & 0xFF0000) | word_address; // 1B F9 3C
420 addr = SnesToPc(addr);
421
422 if (overworld_maps_[i].is_large_map()) {
423 if (overworld_maps_[i].parent() != (uint8_t)i) {
424 continue;
425 }
426 }
427
428 while (true) {
429 ASSIGN_OR_RETURN(uint8_t b1, rom()->ReadByte(addr));
430 ASSIGN_OR_RETURN(uint8_t b2, rom()->ReadByte(addr + 1));
431 ASSIGN_OR_RETURN(uint8_t b3, rom()->ReadByte(addr + 2));
432
433 if (b1 == 0xFF && b2 == 0xFF) {
434 break;
435 }
436
437 int p = (((b2 & 0x1F) << 8) + b1) >> 1;
438
439 int x = p % 64;
440 int y = p >> 6;
441
442 int fakeID = i;
443 if (fakeID >= 64) {
444 fakeID -= 64;
445 }
446
447 int sy = fakeID / 8;
448 int sx = fakeID - (sy * 8);
449
450 all_items_.emplace_back(b3, (uint16_t)i, (x * 16) + (sx * 512),
451 (y * 16) + (sy * 512), false);
452 auto size = all_items_.size();
453
454 all_items_[size - 1].game_x_ = (uint8_t)x;
455 all_items_[size - 1].game_y_ = (uint8_t)y;
456 addr += 3;
457 }
458 }
459 return absl::OkStatus();
460}
461
463 std::vector<std::future<absl::Status>> futures;
464 futures.emplace_back(std::async(std::launch::async, [this]() {
466 }));
467 futures.emplace_back(std::async(std::launch::async, [this]() {
469 }));
470 futures.emplace_back(std::async(std::launch::async, [this]() {
472 }));
473
474 for (auto &future : futures) {
475 future.wait();
476 RETURN_IF_ERROR(future.get());
477 }
478 return absl::OkStatus();
479}
480
481absl::Status Overworld::LoadSpritesFromMap(int sprites_per_gamestate_ptr,
482 int num_maps_per_gamestate,
483 int game_state) {
484 for (int i = 0; i < num_maps_per_gamestate; i++) {
485 if (map_parent_[i] != i) continue;
486
487 int current_spr_ptr = sprites_per_gamestate_ptr + (i * 2);
488 ASSIGN_OR_RETURN(auto word_addr, rom()->ReadWord(current_spr_ptr));
489 int sprite_address = SnesToPc((0x09 << 0x10) | word_addr);
490 while (true) {
491 ASSIGN_OR_RETURN(uint8_t b1, rom()->ReadByte(sprite_address));
492 ASSIGN_OR_RETURN(uint8_t b2, rom()->ReadByte(sprite_address + 1));
493 ASSIGN_OR_RETURN(uint8_t b3, rom()->ReadByte(sprite_address + 2));
494 if (b1 == 0xFF) break;
495
496 int editor_map_index = i;
497 if (game_state != 0) {
498 if (editor_map_index >= 128)
499 editor_map_index -= 128;
500 else if (editor_map_index >= 64)
501 editor_map_index -= 64;
502 }
503 int mapY = (editor_map_index / 8);
504 int mapX = (editor_map_index % 8);
505
506 int realX = ((b2 & 0x3F) * 16) + mapX * 512;
507 int realY = ((b1 & 0x3F) * 16) + mapY * 512;
508 all_sprites_[game_state].emplace_back(
509 *overworld_maps_[i].mutable_current_graphics(), (uint8_t)i, b3,
510 (uint8_t)(b2 & 0x3F), (uint8_t)(b1 & 0x3F), realX, realY);
511 all_sprites_[game_state][i].Draw();
512
513 sprite_address += 3;
514 }
515 }
516
517 return absl::OkStatus();
518}
519
531
533 util::logf("Saving Overworld Maps");
534
535 // Initialize map pointers
536 std::fill(map_pointers1_id.begin(), map_pointers1_id.end(), -1);
537 std::fill(map_pointers2_id.begin(), map_pointers2_id.end(), -1);
538
539 // Compress and save each map
541 for (int i = 0; i < kNumOverworldMaps; i++) {
542 std::vector<uint8_t> single_map_1(512);
543 std::vector<uint8_t> single_map_2(512);
544
545 // Copy tiles32 data to single_map_1 and single_map_2
546 int npos = 0;
547 for (int y = 0; y < 16; y++) {
548 for (int x = 0; x < 16; x++) {
549 auto packed = tiles32_list_[npos + (i * 256)];
550 single_map_1[npos] = packed & 0xFF; // Lower 8 bits
551 single_map_2[npos] = (packed >> 8) & 0xFF; // Next 8 bits
552 npos++;
553 }
554 }
555
556 int size_a, size_b;
557 // Compress single_map_1 and single_map_2
558 auto a = gfx::HyruleMagicCompress(single_map_1.data(), 256, &size_a, 1);
559 auto b = gfx::HyruleMagicCompress(single_map_2.data(), 256, &size_b, 1);
560 if (a.empty() || b.empty()) {
561 return absl::AbortedError("Error compressing map gfx.");
562 }
563
564 // Save compressed data and pointers
565 map_data_p1[i] = std::vector<uint8_t>(size_a);
566 map_data_p2[i] = std::vector<uint8_t>(size_b);
567
568 if ((pos + size_a) >= 0x5FE70 && (pos + size_a) <= 0x60000) {
569 pos = 0x60000;
570 }
571
572 if ((pos + size_a) >= 0x6411F && (pos + size_a) <= 0x70000) {
573 util::logf("Pos set to overflow region for map %s at %s",
574 std::to_string(i), util::HexLong(pos));
575 pos = kOverworldMapDataOverflow; // 0x0F8780;
576 }
577
578 const auto compare_array = [](const std::vector<uint8_t> &array1,
579 const std::vector<uint8_t> &array2) -> bool {
580 if (array1.size() != array2.size()) {
581 return false;
582 }
583
584 for (size_t i = 0; i < array1.size(); i++) {
585 if (array1[i] != array2[i]) {
586 return false;
587 }
588 }
589
590 return true;
591 };
592
593 for (int j = 0; j < i; j++) {
594 if (compare_array(a, map_data_p1[j])) {
595 // Reuse pointer id j for P1 (a)
596 map_pointers1_id[i] = j;
597 }
598
599 if (compare_array(b, map_data_p2[j])) {
600 map_pointers2_id[i] = j;
601 // Reuse pointer id j for P2 (b)
602 }
603 }
604
605 if (map_pointers1_id[i] == -1) {
606 // Save compressed data and pointer for map1
607 std::copy(a.begin(), a.end(), map_data_p1[i].begin());
608 int snes_pos = PcToSnes(pos);
609 map_pointers1[i] = snes_pos;
610 util::logf("Saving map pointers1 and compressed data for map %s at %s",
611 util::HexByte(i), util::HexLong(snes_pos));
612 RETURN_IF_ERROR(rom()->WriteLong(
613 rom()->version_constants().kCompressedAllMap32PointersLow + (3 * i),
614 snes_pos));
615 RETURN_IF_ERROR(rom()->WriteVector(pos, a));
616 pos += size_a;
617 } else {
618 // Save pointer for map1
619 int snes_pos = map_pointers1[map_pointers1_id[i]];
620 util::logf("Saving map pointers1 for map %s at %s", util::HexByte(i),
621 util::HexLong(snes_pos));
622 RETURN_IF_ERROR(rom()->WriteLong(
623 rom()->version_constants().kCompressedAllMap32PointersLow + (3 * i),
624 snes_pos));
625 }
626
627 if ((pos + b.size()) >= 0x5FE70 && (pos + b.size()) <= 0x60000) {
628 pos = 0x60000;
629 }
630
631 if ((pos + b.size()) >= 0x6411F && (pos + b.size()) <= 0x70000) {
632 util::logf("Pos set to overflow region for map %s at %s",
635 }
636
637 if (map_pointers2_id[i] == -1) {
638 // Save compressed data and pointer for map2
639 std::copy(b.begin(), b.end(), map_data_p2[i].begin());
640 int snes_pos = PcToSnes(pos);
641 map_pointers2[i] = snes_pos;
642 util::logf("Saving map pointers2 and compressed data for map %s at %s",
643 util::HexByte(i), util::HexLong(snes_pos));
644 RETURN_IF_ERROR(rom()->WriteLong(
645 rom()->version_constants().kCompressedAllMap32PointersHigh + (3 * i),
646 snes_pos));
647 RETURN_IF_ERROR(rom()->WriteVector(pos, b));
648 pos += size_b;
649 } else {
650 // Save pointer for map2
651 int snes_pos = map_pointers2[map_pointers2_id[i]];
652 util::logf("Saving map pointers2 for map %s at %s", util::HexByte(i),
653 util::HexLong(snes_pos));
654 RETURN_IF_ERROR(rom()->WriteLong(
655 rom()->version_constants().kCompressedAllMap32PointersHigh + (3 * i),
656 snes_pos));
657 }
658 }
659
660 // Check if too many maps data
662 util::logf("Too many maps data %s", util::HexLong(pos));
663 return absl::AbortedError("Too many maps data " + std::to_string(pos));
664 }
665
667 return absl::OkStatus();
668}
669
671 util::logf("Saving Large Maps");
672 std::vector<uint8_t> checked_map;
673
674 for (int i = 0; i < kNumMapsPerWorld; ++i) {
675 int y_pos = i / 8;
676 int x_pos = i % 8;
677 int parent_y_pos = overworld_maps_[i].parent() / 8;
678 int parent_x_pos = overworld_maps_[i].parent() % 8;
679
680 // Always write the map parent since it should not matter
682 overworld_maps_[i].parent()))
683
684 if (std::find(checked_map.begin(), checked_map.end(), i) !=
685 checked_map.end()) {
686 continue;
687 }
688
689 // If it's large then save parent pos *
690 // 0x200 otherwise pos * 0x200
691 if (overworld_maps_[i].is_large_map()) {
692 const uint8_t large_map_offsets[] = {0, 1, 8, 9};
693 for (const auto &offset : large_map_offsets) {
694 // Check 1
695 RETURN_IF_ERROR(rom()->WriteByte(kOverworldMapSize + i + offset, 0x20));
696 // Check 2
698 rom()->WriteByte(kOverworldMapSizeHighByte + i + offset, 0x03));
699 // Check 3
701 rom()->WriteByte(kOverworldScreenSize + i + offset, 0x00));
703 rom()->WriteByte(kOverworldScreenSize + i + offset + 64, 0x00));
704 // Check 4
705 RETURN_IF_ERROR(rom()->WriteByte(
706 kOverworldScreenSizeForLoading + i + offset, 0x04));
707 RETURN_IF_ERROR(rom()->WriteByte(
709 0x04));
712 0x04));
713 }
714
715 // Check 5 and 6
717 rom()->WriteShort(kTransitionTargetNorth + (i * 2),
718 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
720 rom()->WriteShort(kTransitionTargetWest + (i * 2),
721 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
722
724 rom()->WriteShort(kTransitionTargetNorth + (i * 2) + 2,
725 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
727 rom()->WriteShort(kTransitionTargetWest + (i * 2) + 2,
728 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
729
731 rom()->WriteShort(kTransitionTargetNorth + (i * 2) + 16,
732 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
734 rom()->WriteShort(kTransitionTargetWest + (i * 2) + 16,
735 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
736
738 rom()->WriteShort(kTransitionTargetNorth + (i * 2) + 18,
739 (uint16_t)((parent_y_pos * 0x200) - 0xE0)));
741 rom()->WriteShort(kTransitionTargetWest + (i * 2) + 18,
742 (uint16_t)((parent_x_pos * 0x200) - 0x100)));
743
744 // Check 7 and 8
745 RETURN_IF_ERROR(rom()->WriteShort(kOverworldTransitionPositionX + (i * 2),
746 (parent_x_pos * 0x200)));
747 RETURN_IF_ERROR(rom()->WriteShort(kOverworldTransitionPositionY + (i * 2),
748 (parent_y_pos * 0x200)));
749
751 rom()->WriteShort(kOverworldTransitionPositionX + (i * 2) + 02,
752 (parent_x_pos * 0x200)));
754 rom()->WriteShort(kOverworldTransitionPositionY + (i * 2) + 02,
755 (parent_y_pos * 0x200)));
756
757 // problematic
759 rom()->WriteShort(kOverworldTransitionPositionX + (i * 2) + 16,
760 (parent_x_pos * 0x200)));
762 rom()->WriteShort(kOverworldTransitionPositionY + (i * 2) + 16,
763 (parent_y_pos * 0x200)));
764
766 rom()->WriteShort(kOverworldTransitionPositionX + (i * 2) + 18,
767 (parent_x_pos * 0x200)));
769 rom()->WriteShort(kOverworldTransitionPositionY + (i * 2) + 18,
770 (parent_y_pos * 0x200)));
771
772 // Check 9
773 RETURN_IF_ERROR(rom()->WriteShort(
774 kOverworldScreenTileMapChangeByScreen1 + (i * 2) + 00, 0x0060));
775 RETURN_IF_ERROR(rom()->WriteShort(
776 kOverworldScreenTileMapChangeByScreen1 + (i * 2) + 02, 0x0060));
777
778 // If parentX == 0 then lower submaps == 0x0060 too
779 if (parent_x_pos == 0) {
780 RETURN_IF_ERROR(rom()->WriteShort(
781 kOverworldScreenTileMapChangeByScreen1 + (i * 2) + 16, 0x0060));
782 RETURN_IF_ERROR(rom()->WriteShort(
783 kOverworldScreenTileMapChangeByScreen1 + (i * 2) + 18, 0x0060));
784 } else {
785 // Otherwise lower submaps == 0x1060
786 RETURN_IF_ERROR(rom()->WriteShort(
787 kOverworldScreenTileMapChangeByScreen1 + (i * 2) + 16, 0x1060));
788 RETURN_IF_ERROR(rom()->WriteShort(
789 kOverworldScreenTileMapChangeByScreen1 + (i * 2) + 18, 0x1060));
790
791 // If the area to the left is a large map, we don't need to add an
792 // offset to it. otherwise leave it the same. Just to make sure where
793 // don't try to read outside of the array.
794 if ((i - 1) >= 0) {
795 // If the area to the left is a large area.
796 if (overworld_maps_[i - 1].is_large_map()) {
797 // If the area to the left is the bottom right of a large area.
798 if (overworld_maps_[i - 1].large_index() == 1) {
799 RETURN_IF_ERROR(rom()->WriteShort(
801 0x0060));
802 }
803 }
804 }
805 }
806
807 // Always 0x0080
808 RETURN_IF_ERROR(rom()->WriteShort(
809 kOverworldScreenTileMapChangeByScreen2 + (i * 2) + 00, 0x0080));
810 RETURN_IF_ERROR(rom()->WriteShort(
811 kOverworldScreenTileMapChangeByScreen2 + (i * 2) + 2, 0x0080));
812 // Lower always 0x1080
813 RETURN_IF_ERROR(rom()->WriteShort(
814 kOverworldScreenTileMapChangeByScreen2 + (i * 2) + 16, 0x1080));
815 RETURN_IF_ERROR(rom()->WriteShort(
816 kOverworldScreenTileMapChangeByScreen2 + (i * 2) + 18, 0x1080));
817
818 // If the area to the right is a large map, we don't need to add an offset
819 // to it. otherwise leave it the same. Just to make sure where don't try
820 // to read outside of the array.
821 if ((i + 2) < 64) {
822 // If the area to the right is a large area.
823 if (overworld_maps_[i + 2].is_large_map()) {
824 // If the area to the right is the top left of a large area.
825 if (overworld_maps_[i + 2].large_index() == 0) {
826 RETURN_IF_ERROR(rom()->WriteShort(
827 kOverworldScreenTileMapChangeByScreen2 + (i * 2) + 18, 0x0080));
828 }
829 }
830 }
831
832 // Always 0x1800
833 RETURN_IF_ERROR(rom()->WriteShort(
834 kOverworldScreenTileMapChangeByScreen3 + (i * 2), 0x1800));
835 RETURN_IF_ERROR(rom()->WriteShort(
836 kOverworldScreenTileMapChangeByScreen3 + (i * 2) + 16, 0x1800));
837 // Right side is always 0x1840
838 RETURN_IF_ERROR(rom()->WriteShort(
839 kOverworldScreenTileMapChangeByScreen3 + (i * 2) + 2, 0x1840));
840 RETURN_IF_ERROR(rom()->WriteShort(
841 kOverworldScreenTileMapChangeByScreen3 + (i * 2) + 18, 0x1840));
842
843 // If the area above is a large map, we don't need to add an offset to it.
844 // otherwise leave it the same.
845 // Just to make sure where don't try to read outside of the array.
846 if (i - 8 >= 0) {
847 // If the area just above us is a large area.
848 if (overworld_maps_[i - 8].is_large_map()) {
849 // If the area just above us is the bottom left of a large area.
850 if (overworld_maps_[i - 8].large_index() == 2) {
851 RETURN_IF_ERROR(rom()->WriteShort(
852 kOverworldScreenTileMapChangeByScreen3 + (i * 2) + 02, 0x1800));
853 }
854 }
855 }
856
857 // Always 0x2000
858 RETURN_IF_ERROR(rom()->WriteShort(
859 kOverworldScreenTileMapChangeByScreen4 + (i * 2) + 00, 0x2000));
860 RETURN_IF_ERROR(rom()->WriteShort(
861 kOverworldScreenTileMapChangeByScreen4 + (i * 2) + 16, 0x2000));
862 // Right side always 0x2040
863 RETURN_IF_ERROR(rom()->WriteShort(
864 kOverworldScreenTileMapChangeByScreen4 + (i * 2) + 2, 0x2040));
865 RETURN_IF_ERROR(rom()->WriteShort(
866 kOverworldScreenTileMapChangeByScreen4 + (i * 2) + 18, 0x2040));
867
868 // If the area below is a large map, we don't need to add an offset to it.
869 // otherwise leave it the same.
870 // Just to make sure where don't try to read outside of the array.
871 if (i + 16 < 64) {
872 // If the area just below us is a large area.
873 if (overworld_maps_[i + 16].is_large_map()) {
874 // If the area just below us is the top left of a large area.
875 if (overworld_maps_[i + 16].large_index() == 0) {
876 RETURN_IF_ERROR(rom()->WriteShort(
877 kOverworldScreenTileMapChangeByScreen4 + (i * 2) + 18, 0x2000));
878 }
879 }
880 }
881
882 checked_map.emplace_back(i);
883 checked_map.emplace_back((i + 1));
884 checked_map.emplace_back((i + 8));
885 checked_map.emplace_back((i + 9));
886
887 } else {
888 RETURN_IF_ERROR(rom()->WriteByte(kOverworldMapSize + i, 0x00));
889 RETURN_IF_ERROR(rom()->WriteByte(kOverworldMapSizeHighByte + i, 0x01));
890
891 RETURN_IF_ERROR(rom()->WriteByte(kOverworldScreenSize + i, 0x01));
892 RETURN_IF_ERROR(rom()->WriteByte(kOverworldScreenSize + i + 64, 0x01));
893
895 rom()->WriteByte(kOverworldScreenSizeForLoading + i, 0x02));
896 RETURN_IF_ERROR(rom()->WriteByte(
898 RETURN_IF_ERROR(rom()->WriteByte(
900
901 RETURN_IF_ERROR(rom()->WriteShort(
902 kOverworldScreenTileMapChangeByScreen1 + (i * 2), 0x0060));
903
904 // If the area to the left is a large map, we don't need to add an offset
905 // to it. otherwise leave it the same.
906 // Just to make sure where don't try to read outside of the array.
907 if (i - 1 >= 0 && parent_x_pos != 0) {
908 if (overworld_maps_[i - 1].is_large_map()) {
909 if (overworld_maps_[i - 1].large_index() == 3) {
910 RETURN_IF_ERROR(rom()->WriteShort(
911 kOverworldScreenTileMapChangeByScreen1 + (i * 2), 0xF060));
912 }
913 }
914 }
915
916 RETURN_IF_ERROR(rom()->WriteShort(
917 kOverworldScreenTileMapChangeByScreen2 + (i * 2), 0x0040));
918
919 if (i + 1 < 64 && parent_x_pos != 7) {
920 if (overworld_maps_[i + 1].is_large_map()) {
921 if (overworld_maps_[i + 1].large_index() == 2) {
922 RETURN_IF_ERROR(rom()->WriteShort(
923 kOverworldScreenTileMapChangeByScreen2 + (i * 2), 0xF040));
924 }
925 }
926 }
927
928 RETURN_IF_ERROR(rom()->WriteShort(
929 kOverworldScreenTileMapChangeByScreen3 + (i * 2), 0x1800));
930
931 // If the area above is a large map, we don't need to add an offset to it.
932 // otherwise leave it the same.
933 // Just to make sure where don't try to read outside of the array.
934 if (i - 8 >= 0) {
935 // If the area just above us is a large area.
936 if (overworld_maps_[i - 8].is_large_map()) {
937 // If we are under the bottom right of the large area.
938 if (overworld_maps_[i - 8].large_index() == 3) {
939 RETURN_IF_ERROR(rom()->WriteShort(
940 kOverworldScreenTileMapChangeByScreen3 + (i * 2), 0x17C0));
941 }
942 }
943 }
944
945 RETURN_IF_ERROR(rom()->WriteShort(
946 kOverworldScreenTileMapChangeByScreen4 + (i * 2), 0x1000));
947
948 // If the area below is a large map, we don't need to add an offset to it.
949 // otherwise leave it the same.
950 // Just to make sure where don't try to read outside of the array.
951 if (i + 8 < 64) {
952 // If the area just below us is a large area.
953 if (overworld_maps_[i + 8].is_large_map()) {
954 // If we are on top of the top right of the large area.
955 if (overworld_maps_[i + 8].large_index() == 1) {
956 RETURN_IF_ERROR(rom()->WriteShort(
957 kOverworldScreenTileMapChangeByScreen4 + (i * 2), 0x0FC0));
958 }
959 }
960 }
961
962 RETURN_IF_ERROR(rom()->WriteShort(kTransitionTargetNorth + (i * 2),
963 (uint16_t)((y_pos * 0x200) - 0xE0)));
964 RETURN_IF_ERROR(rom()->WriteShort(kTransitionTargetWest + (i * 2),
965 (uint16_t)((x_pos * 0x200) - 0x100)));
966
967 RETURN_IF_ERROR(rom()->WriteShort(kOverworldTransitionPositionX + (i * 2),
968 (x_pos * 0x200)));
969 RETURN_IF_ERROR(rom()->WriteShort(kOverworldTransitionPositionY + (i * 2),
970 (y_pos * 0x200)));
971
972 checked_map.emplace_back(i);
973 }
974 }
975
976 constexpr int OverworldScreenTileMapChangeMask = 0x1262C;
977
979 rom()->WriteShort(OverworldScreenTileMapChangeMask + 0, 0x1F80));
981 rom()->WriteShort(OverworldScreenTileMapChangeMask + 2, 0x1F80));
983 rom()->WriteShort(OverworldScreenTileMapChangeMask + 4, 0x007F));
985 rom()->WriteShort(OverworldScreenTileMapChangeMask + 6, 0x007F));
986
987 return absl::OkStatus();
988}
989
990namespace {
991std::vector<uint64_t> GetAllTile16(OverworldMapTiles &map_tiles_) {
992 std::vector<uint64_t> all_tile_16; // Ensure it's 64 bits
993
994 int sx = 0;
995 int sy = 0;
996 int c = 0;
997 OverworldBlockset tiles_used;
998 for (int i = 0; i < kNumOverworldMaps; i++) {
999 if (i < kDarkWorldMapIdStart) {
1000 tiles_used = map_tiles_.light_world;
1001 } else if (i < kSpecialWorldMapIdStart && i >= kDarkWorldMapIdStart) {
1002 tiles_used = map_tiles_.dark_world;
1003 } else {
1004 tiles_used = map_tiles_.special_world;
1005 }
1006
1007 for (int y = 0; y < 32; y += 2) {
1008 for (int x = 0; x < 32; x += 2) {
1009 gfx::Tile32 current_tile(
1010 tiles_used[x + (sx * 32)][y + (sy * 32)],
1011 tiles_used[x + 1 + (sx * 32)][y + (sy * 32)],
1012 tiles_used[x + (sx * 32)][y + 1 + (sy * 32)],
1013 tiles_used[x + 1 + (sx * 32)][y + 1 + (sy * 32)]);
1014
1015 all_tile_16.emplace_back(current_tile.GetPackedValue());
1016 }
1017 }
1018
1019 sx++;
1020 if (sx >= 8) {
1021 sy++;
1022 sx = 0;
1023 }
1024
1025 c++;
1026 if (c >= 64) {
1027 sx = 0;
1028 sy = 0;
1029 c = 0;
1030 }
1031 }
1032
1033 return all_tile_16;
1034}
1035} // namespace
1036
1038 tiles32_unique_.clear();
1039 tiles32_list_.clear();
1040
1041 // Get all tiles16 and packs them into tiles32
1042 std::vector<uint64_t> all_tile_16 = GetAllTile16(map_tiles_);
1043
1044 // Convert to set then back to vector
1045 std::set<uint64_t> unique_tiles_set(all_tile_16.begin(), all_tile_16.end());
1046
1047 std::vector<uint64_t> unique_tiles(all_tile_16);
1048 unique_tiles.assign(unique_tiles_set.begin(), unique_tiles_set.end());
1049
1050 // Create the indexed tiles list
1051 std::unordered_map<uint64_t, uint16_t> all_tiles_indexed;
1052 for (size_t tile32_id = 0; tile32_id < unique_tiles.size(); tile32_id++) {
1053 all_tiles_indexed.insert(
1054 {unique_tiles[tile32_id], static_cast<uint16_t>(tile32_id)});
1055 }
1056
1057 // Add all tiles32 from all maps.
1058 // Convert all tiles32 non-unique IDs into unique array of IDs.
1059 for (int j = 0; j < NumberOfMap32; j++) {
1060 tiles32_list_.emplace_back(all_tiles_indexed[all_tile_16[j]]);
1061 }
1062
1063 // Create the unique tiles list
1064 for (size_t i = 0; i < unique_tiles.size(); ++i) {
1065 tiles32_unique_.emplace_back(gfx::Tile32(unique_tiles[i]));
1066 }
1067
1068 while (tiles32_unique_.size() % 4 != 0) {
1069 gfx::Tile32 padding_tile(0, 0, 0, 0);
1070 tiles32_unique_.emplace_back(padding_tile.GetPackedValue());
1071 }
1072
1073 if (tiles32_unique_.size() > LimitOfMap32) {
1074 return absl::InternalError(absl::StrFormat(
1075 "Number of unique Tiles32: %d Out of: %d\nUnique Tile32 count exceed "
1076 "the limit\nThe ROM Has not been saved\nYou can fill maps with grass "
1077 "tiles to free some space\nOr use the option Clear DW Tiles in the "
1078 "Overworld Menu",
1079 unique_tiles.size(), LimitOfMap32));
1080 }
1081
1082 if (core::FeatureFlags::get().kLogToConsole) {
1083 std::cout << "Number of unique Tiles32: " << tiles32_unique_.size()
1084 << " Saved:" << tiles32_unique_.size()
1085 << " Out of: " << LimitOfMap32 << std::endl;
1086 }
1087
1088 int v = tiles32_unique_.size();
1089 for (int i = v; i < LimitOfMap32; i++) {
1090 gfx::Tile32 padding_tile(420, 420, 420, 420);
1091 tiles32_unique_.emplace_back(padding_tile.GetPackedValue());
1092 }
1093
1094 return absl::OkStatus();
1095}
1096
1098 int bottomLeft = kMap32TileBLExpanded;
1099 int bottomRight = kMap32TileBRExpanded;
1100 int topRight = kMap32TileTRExpanded;
1101 int limit = 0x8A80;
1102
1103 // Updates the pointers too for the tile32
1104 // Top Right
1105 RETURN_IF_ERROR(rom()->WriteLong(0x0176EC, PcToSnes(kMap32TileTRExpanded)));
1107 rom()->WriteLong(0x0176F3, PcToSnes(kMap32TileTRExpanded + 1)));
1109 rom()->WriteLong(0x0176FA, PcToSnes(kMap32TileTRExpanded + 2)));
1111 rom()->WriteLong(0x017701, PcToSnes(kMap32TileTRExpanded + 3)));
1113 rom()->WriteLong(0x017708, PcToSnes(kMap32TileTRExpanded + 4)));
1115 rom()->WriteLong(0x01771A, PcToSnes(kMap32TileTRExpanded + 5)));
1116
1117 // BottomLeft
1118 RETURN_IF_ERROR(rom()->WriteLong(0x01772C, PcToSnes(kMap32TileBLExpanded)));
1120 rom()->WriteLong(0x017733, PcToSnes(kMap32TileBLExpanded + 1)));
1122 rom()->WriteLong(0x01773A, PcToSnes(kMap32TileBLExpanded + 2)));
1124 rom()->WriteLong(0x017741, PcToSnes(kMap32TileBLExpanded + 3)));
1126 rom()->WriteLong(0x017748, PcToSnes(kMap32TileBLExpanded + 4)));
1128 rom()->WriteLong(0x01775A, PcToSnes(kMap32TileBLExpanded + 5)));
1129
1130 // BottomRight
1131 RETURN_IF_ERROR(rom()->WriteLong(0x01776C, PcToSnes(kMap32TileBRExpanded)));
1133 rom()->WriteLong(0x017773, PcToSnes(kMap32TileBRExpanded + 1)));
1135 rom()->WriteLong(0x01777A, PcToSnes(kMap32TileBRExpanded + 2)));
1137 rom()->WriteLong(0x017781, PcToSnes(kMap32TileBRExpanded + 3)));
1139 rom()->WriteLong(0x017788, PcToSnes(kMap32TileBRExpanded + 4)));
1141 rom()->WriteLong(0x01779A, PcToSnes(kMap32TileBRExpanded + 5)));
1142 return absl::OkStatus();
1143}
1144
1146 util::logf("Saving Map32 Tiles");
1147 constexpr int kMaxUniqueTiles = 0x4540;
1148 constexpr int kTilesPer32x32Tile = 6;
1149
1150 int unique_tile_index = 0;
1151 int num_unique_tiles = tiles32_unique_.size();
1152
1153 for (int i = 0; i < num_unique_tiles; i += kTilesPer32x32Tile) {
1154 if (unique_tile_index >= kMaxUniqueTiles) {
1155 return absl::AbortedError("Too many unique tile32 definitions.");
1156 }
1157
1158 // Top Left.
1159 auto top_left = rom()->version_constants().kMap32TileTL;
1160
1161 RETURN_IF_ERROR(rom()->WriteByte(
1162 top_left + i,
1163 (uint8_t)(tiles32_unique_[unique_tile_index].tile0_ & 0xFF)));
1164 RETURN_IF_ERROR(rom()->WriteByte(
1165 top_left + (i + 1),
1166 (uint8_t)(tiles32_unique_[unique_tile_index + 1].tile0_ & 0xFF)));
1167 RETURN_IF_ERROR(rom()->WriteByte(
1168 top_left + (i + 2),
1169 (uint8_t)(tiles32_unique_[unique_tile_index + 2].tile0_ & 0xFF)));
1170 RETURN_IF_ERROR(rom()->WriteByte(
1171 top_left + (i + 3),
1172 (uint8_t)(tiles32_unique_[unique_tile_index + 3].tile0_ & 0xFF)));
1173
1174 RETURN_IF_ERROR(rom()->WriteByte(
1175 top_left + (i + 4),
1176 (uint8_t)(((tiles32_unique_[unique_tile_index].tile0_ >> 4) & 0xF0) +
1177 ((tiles32_unique_[unique_tile_index + 1].tile0_ >> 8) &
1178 0x0F))));
1179 RETURN_IF_ERROR(rom()->WriteByte(
1180 top_left + (i + 5),
1181 (uint8_t)(((tiles32_unique_[unique_tile_index + 2].tile0_ >> 4) &
1182 0xF0) +
1183 ((tiles32_unique_[unique_tile_index + 3].tile0_ >> 8) &
1184 0x0F))));
1185
1186 // Top Right.
1187 auto top_right = rom()->version_constants().kMap32TileTR;
1188 RETURN_IF_ERROR(rom()->WriteByte(
1189 top_right + i,
1190 (uint8_t)(tiles32_unique_[unique_tile_index].tile1_ & 0xFF)));
1191 RETURN_IF_ERROR(rom()->WriteByte(
1192 top_right + (i + 1),
1193 (uint8_t)(tiles32_unique_[unique_tile_index + 1].tile1_ & 0xFF)));
1194 RETURN_IF_ERROR(rom()->WriteByte(
1195 top_right + (i + 2),
1196 (uint8_t)(tiles32_unique_[unique_tile_index + 2].tile1_ & 0xFF)));
1197 RETURN_IF_ERROR(rom()->WriteByte(
1198 top_right + (i + 3),
1199 (uint8_t)(tiles32_unique_[unique_tile_index + 3].tile1_ & 0xFF)));
1200
1201 RETURN_IF_ERROR(rom()->WriteByte(
1202 top_right + (i + 4),
1203 (uint8_t)(((tiles32_unique_[unique_tile_index].tile1_ >> 4) & 0xF0) |
1204 ((tiles32_unique_[unique_tile_index + 1].tile1_ >> 8) &
1205 0x0F))));
1206 RETURN_IF_ERROR(rom()->WriteByte(
1207 top_right + (i + 5),
1208 (uint8_t)(((tiles32_unique_[unique_tile_index + 2].tile1_ >> 4) &
1209 0xF0) |
1210 ((tiles32_unique_[unique_tile_index + 3].tile1_ >> 8) &
1211 0x0F))));
1212
1213 // Bottom Left.
1214 const auto map32TilesBL = rom()->version_constants().kMap32TileBL;
1215 RETURN_IF_ERROR(rom()->WriteByte(
1216 map32TilesBL + i,
1217 (uint8_t)(tiles32_unique_[unique_tile_index].tile2_ & 0xFF)));
1218 RETURN_IF_ERROR(rom()->WriteByte(
1219 map32TilesBL + (i + 1),
1220 (uint8_t)(tiles32_unique_[unique_tile_index + 1].tile2_ & 0xFF)));
1221 RETURN_IF_ERROR(rom()->WriteByte(
1222 map32TilesBL + (i + 2),
1223 (uint8_t)(tiles32_unique_[unique_tile_index + 2].tile2_ & 0xFF)));
1224 RETURN_IF_ERROR(rom()->WriteByte(
1225 map32TilesBL + (i + 3),
1226 (uint8_t)(tiles32_unique_[unique_tile_index + 3].tile2_ & 0xFF)));
1227
1228 RETURN_IF_ERROR(rom()->WriteByte(
1229 map32TilesBL + (i + 4),
1230 (uint8_t)(((tiles32_unique_[unique_tile_index].tile2_ >> 4) & 0xF0) |
1231 ((tiles32_unique_[unique_tile_index + 1].tile2_ >> 8) &
1232 0x0F))));
1233 RETURN_IF_ERROR(rom()->WriteByte(
1234 map32TilesBL + (i + 5),
1235 (uint8_t)(((tiles32_unique_[unique_tile_index + 2].tile2_ >> 4) &
1236 0xF0) |
1237 ((tiles32_unique_[unique_tile_index + 3].tile2_ >> 8) &
1238 0x0F))));
1239
1240 // Bottom Right.
1241 const auto map32TilesBR = rom()->version_constants().kMap32TileBR;
1242 RETURN_IF_ERROR(rom()->WriteByte(
1243 map32TilesBR + i,
1244 (uint8_t)(tiles32_unique_[unique_tile_index].tile3_ & 0xFF)));
1245 RETURN_IF_ERROR(rom()->WriteByte(
1246 map32TilesBR + (i + 1),
1247 (uint8_t)(tiles32_unique_[unique_tile_index + 1].tile3_ & 0xFF)));
1248 RETURN_IF_ERROR(rom()->WriteByte(
1249 map32TilesBR + (i + 2),
1250 (uint8_t)(tiles32_unique_[unique_tile_index + 2].tile3_ & 0xFF)));
1251 RETURN_IF_ERROR(rom()->WriteByte(
1252 map32TilesBR + (i + 3),
1253 (uint8_t)(tiles32_unique_[unique_tile_index + 3].tile3_ & 0xFF)));
1254
1255 RETURN_IF_ERROR(rom()->WriteByte(
1256 map32TilesBR + (i + 4),
1257 (uint8_t)(((tiles32_unique_[unique_tile_index].tile3_ >> 4) & 0xF0) |
1258 ((tiles32_unique_[unique_tile_index + 1].tile3_ >> 8) &
1259 0x0F))));
1260 RETURN_IF_ERROR(rom()->WriteByte(
1261 map32TilesBR + (i + 5),
1262 (uint8_t)(((tiles32_unique_[unique_tile_index + 2].tile3_ >> 4) &
1263 0xF0) |
1264 ((tiles32_unique_[unique_tile_index + 3].tile3_ >> 8) &
1265 0x0F))));
1266
1267 unique_tile_index += 4;
1268 num_unique_tiles += 2;
1269 }
1270
1271 return absl::OkStatus();
1272}
1273
1276 rom()->WriteLong(SnesToPc(0x008865), PcToSnes(kMap16TilesExpanded)));
1278 rom()->WriteLong(SnesToPc(0x0EDE4F), PcToSnes(kMap16TilesExpanded)));
1280 rom()->WriteLong(SnesToPc(0x0EDEE9), PcToSnes(kMap16TilesExpanded)));
1281
1283 rom()->WriteLong(SnesToPc(0x1BBC2D), PcToSnes(kMap16TilesExpanded + 2)));
1285 rom()->WriteLong(SnesToPc(0x1BBC4C), PcToSnes(kMap16TilesExpanded)));
1287 rom()->WriteLong(SnesToPc(0x1BBCC2), PcToSnes(kMap16TilesExpanded + 4)));
1289 rom()->WriteLong(SnesToPc(0x1BBCCB), PcToSnes(kMap16TilesExpanded + 6)));
1290
1292 rom()->WriteLong(SnesToPc(0x1BBEF6), PcToSnes(kMap16TilesExpanded)));
1294 rom()->WriteLong(SnesToPc(0x1BBF23), PcToSnes(kMap16TilesExpanded)));
1296 rom()->WriteLong(SnesToPc(0x1BC041), PcToSnes(kMap16TilesExpanded)));
1298 rom()->WriteLong(SnesToPc(0x1BC9B3), PcToSnes(kMap16TilesExpanded)));
1299
1301 rom()->WriteLong(SnesToPc(0x1BC9BA), PcToSnes(kMap16TilesExpanded + 2)));
1303 rom()->WriteLong(SnesToPc(0x1BC9C1), PcToSnes(kMap16TilesExpanded + 4)));
1305 rom()->WriteLong(SnesToPc(0x1BC9C8), PcToSnes(kMap16TilesExpanded + 6)));
1306
1308 rom()->WriteLong(SnesToPc(0x1BCA40), PcToSnes(kMap16TilesExpanded)));
1310 rom()->WriteLong(SnesToPc(0x1BCA47), PcToSnes(kMap16TilesExpanded + 2)));
1312 rom()->WriteLong(SnesToPc(0x1BCA4E), PcToSnes(kMap16TilesExpanded + 4)));
1314 rom()->WriteLong(SnesToPc(0x1BCA55), PcToSnes(kMap16TilesExpanded + 6)));
1315
1317 rom()->WriteLong(SnesToPc(0x02F457), PcToSnes(kMap16TilesExpanded)));
1319 rom()->WriteLong(SnesToPc(0x02F45E), PcToSnes(kMap16TilesExpanded + 2)));
1321 rom()->WriteLong(SnesToPc(0x02F467), PcToSnes(kMap16TilesExpanded + 4)));
1323 rom()->WriteLong(SnesToPc(0x02F46E), PcToSnes(kMap16TilesExpanded + 6)));
1325 rom()->WriteLong(SnesToPc(0x02F51F), PcToSnes(kMap16TilesExpanded)));
1327 rom()->WriteLong(SnesToPc(0x02F526), PcToSnes(kMap16TilesExpanded + 4)));
1329 rom()->WriteLong(SnesToPc(0x02F52F), PcToSnes(kMap16TilesExpanded + 2)));
1331 rom()->WriteLong(SnesToPc(0x02F536), PcToSnes(kMap16TilesExpanded + 6)));
1332
1334 rom()->WriteShort(SnesToPc(0x02FE1C), PcToSnes(kMap16TilesExpanded)));
1336 rom()->WriteShort(SnesToPc(0x02FE23), PcToSnes(kMap16TilesExpanded + 4)));
1338 rom()->WriteShort(SnesToPc(0x02FE2C), PcToSnes(kMap16TilesExpanded + 2)));
1340 rom()->WriteShort(SnesToPc(0x02FE33), PcToSnes(kMap16TilesExpanded + 6)));
1341
1342 RETURN_IF_ERROR(rom()->WriteByte(
1343 SnesToPc(0x02FD28),
1344 static_cast<uint8_t>(PcToSnes(kMap16TilesExpanded) >> 16)));
1345 RETURN_IF_ERROR(rom()->WriteByte(
1346 SnesToPc(0x02FD39),
1347 static_cast<uint8_t>(PcToSnes(kMap16TilesExpanded) >> 16)));
1348
1349 return absl::OkStatus();
1350}
1351
1353 util::logf("Saving Map16 Tiles");
1354 int tpos = kMap16Tiles;
1355 // 3760
1356 for (int i = 0; i < NumberOfMap16; i += 1) {
1358 rom()->WriteShort(tpos, TileInfoToShort(tiles16_[i].tile0_)))
1359 tpos += 2;
1361 rom()->WriteShort(tpos, TileInfoToShort(tiles16_[i].tile1_)))
1362 tpos += 2;
1364 rom()->WriteShort(tpos, TileInfoToShort(tiles16_[i].tile2_)))
1365 tpos += 2;
1367 rom()->WriteShort(tpos, TileInfoToShort(tiles16_[i].tile3_)))
1368 tpos += 2;
1369 }
1370 return absl::OkStatus();
1371}
1372
1374 util::logf("Saving Entrances");
1375 int ow_entrance_map_ptr = kOverworldEntranceMap;
1376 int ow_entrance_pos_ptr = kOverworldEntrancePos;
1377 int ow_entrance_id_ptr = kOverworldEntranceEntranceId;
1378 int num_entrances = kNumOverworldEntrances;
1379 if (expanded_entrances_) {
1380 ow_entrance_map_ptr = kOverworldEntranceMapExpanded;
1381 ow_entrance_pos_ptr = kOverworldEntrancePosExpanded;
1382 ow_entrance_id_ptr = kOverworldEntranceEntranceIdExpanded;
1383 expanded_entrances_ = true;
1384 }
1385
1386 for (int i = 0; i < kNumOverworldEntrances; i++) {
1387 RETURN_IF_ERROR(rom()->WriteShort(kOverworldEntranceMap + (i * 2),
1388 all_entrances_[i].map_id_))
1389 RETURN_IF_ERROR(rom()->WriteShort(kOverworldEntrancePos + (i * 2),
1390 all_entrances_[i].map_pos_))
1392 all_entrances_[i].entrance_id_))
1393 }
1394
1395 for (int i = 0; i < kNumOverworldHoles; i++) {
1397 rom()->WriteShort(kOverworldHoleArea + (i * 2), all_holes_[i].map_id_))
1399 rom()->WriteShort(kOverworldHolePos + (i * 2), all_holes_[i].map_pos_))
1401 all_holes_[i].entrance_id_))
1402 }
1403
1404 return absl::OkStatus();
1405}
1406
1407absl::Status Overworld::SaveExits() {
1408 util::logf("Saving Exits");
1409 for (int i = 0; i < kNumOverworldExits; i++) {
1411 rom()->WriteShort(OWExitRoomId + (i * 2), all_exits_[i].room_id_));
1412 RETURN_IF_ERROR(rom()->WriteByte(OWExitMapId + i, all_exits_[i].map_id_));
1414 rom()->WriteShort(OWExitVram + (i * 2), all_exits_[i].map_pos_));
1416 rom()->WriteShort(OWExitYScroll + (i * 2), all_exits_[i].y_scroll_));
1418 rom()->WriteShort(OWExitXScroll + (i * 2), all_exits_[i].x_scroll_));
1420 rom()->WriteByte(OWExitYPlayer + (i * 2), all_exits_[i].y_player_));
1422 rom()->WriteByte(OWExitXPlayer + (i * 2), all_exits_[i].x_player_));
1424 rom()->WriteByte(OWExitYCamera + (i * 2), all_exits_[i].y_camera_));
1426 rom()->WriteByte(OWExitXCamera + (i * 2), all_exits_[i].x_camera_));
1428 rom()->WriteByte(OWExitUnk1 + i, all_exits_[i].scroll_mod_y_));
1430 rom()->WriteByte(OWExitUnk2 + i, all_exits_[i].scroll_mod_x_));
1431 RETURN_IF_ERROR(rom()->WriteShort(OWExitDoorType1 + (i * 2),
1432 all_exits_[i].door_type_1_));
1433 RETURN_IF_ERROR(rom()->WriteShort(OWExitDoorType2 + (i * 2),
1434 all_exits_[i].door_type_2_));
1435 }
1436
1437 return absl::OkStatus();
1438}
1439
1440namespace {
1441bool CompareItemsArrays(std::vector<OverworldItem> item_array1,
1442 std::vector<OverworldItem> item_array2) {
1443 if (item_array1.size() != item_array2.size()) {
1444 return false;
1445 }
1446
1447 bool match;
1448 for (size_t i = 0; i < item_array1.size(); i++) {
1449 match = false;
1450 for (size_t j = 0; j < item_array2.size(); j++) {
1451 // Check all sprite in 2nd array if one match
1452 if (item_array1[i].x_ == item_array2[j].x_ &&
1453 item_array1[i].y_ == item_array2[j].y_ &&
1454 item_array1[i].id_ == item_array2[j].id_) {
1455 match = true;
1456 break;
1457 }
1458 }
1459
1460 if (!match) {
1461 return false;
1462 }
1463 }
1464
1465 return true;
1466}
1467} // namespace
1468
1469absl::Status Overworld::SaveItems() {
1470 std::vector<std::vector<OverworldItem>> room_items(
1472
1473 for (int i = 0; i < kNumOverworldMapItemPointers; i++) {
1474 room_items[i] = std::vector<OverworldItem>();
1475 for (const OverworldItem &item : all_items_) {
1476 if (item.room_map_id_ == i) {
1477 room_items[i].emplace_back(item);
1478 if (item.id_ == 0x86) {
1479 RETURN_IF_ERROR(rom()->WriteWord(
1480 0x16DC5 + (i * 2), (item.game_x_ + (item.game_y_ * 64)) * 2));
1481 }
1482 }
1483 }
1484 }
1485
1486 int data_pos = kOverworldItemsPointers + 0x100;
1487 int item_pointers[kNumOverworldMapItemPointers];
1488 int item_pointers_reuse[kNumOverworldMapItemPointers];
1489 int empty_pointer = 0;
1490 for (int i = 0; i < kNumOverworldMapItemPointers; i++) {
1491 item_pointers_reuse[i] = -1;
1492 for (int ci = 0; ci < i; ci++) {
1493 if (room_items[i].empty()) {
1494 item_pointers_reuse[i] = -2;
1495 break;
1496 }
1497
1498 // Copy into separator vectors from i to ci, then ci to end
1499 if (CompareItemsArrays(
1500 std::vector<OverworldItem>(room_items[i].begin(),
1501 room_items[i].end()),
1502 std::vector<OverworldItem>(room_items[ci].begin(),
1503 room_items[ci].end()))) {
1504 item_pointers_reuse[i] = ci;
1505 break;
1506 }
1507 }
1508 }
1509
1510 for (int i = 0; i < kNumOverworldMapItemPointers; i++) {
1511 if (item_pointers_reuse[i] == -1) {
1512 item_pointers[i] = data_pos;
1513 for (const OverworldItem &item : room_items[i]) {
1514 short map_pos =
1515 static_cast<short>(((item.game_y_ << 6) + item.game_x_) << 1);
1516
1517 uint32_t data = static_cast<uint8_t>(map_pos & 0xFF) |
1518 static_cast<uint8_t>(map_pos >> 8) |
1519 static_cast<uint8_t>(item.id_);
1520 RETURN_IF_ERROR(rom()->WriteLong(data_pos, data));
1521 data_pos += 3;
1522 }
1523
1524 empty_pointer = data_pos;
1525 RETURN_IF_ERROR(rom()->WriteWord(data_pos, 0xFFFF));
1526 data_pos += 2;
1527 } else if (item_pointers_reuse[i] == -2) {
1528 item_pointers[i] = empty_pointer;
1529 } else {
1530 item_pointers[i] = item_pointers[item_pointers_reuse[i]];
1531 }
1532
1533 int snesaddr = PcToSnes(item_pointers[i]);
1535 rom()->WriteWord(kOverworldItemsPointers + (i * 2), snesaddr));
1536 }
1537
1538 if (data_pos > kOverworldItemsEndData) {
1539 return absl::AbortedError("Too many items");
1540 }
1541
1542 util::logf("End of Items : %d", data_pos);
1543
1544 return absl::OkStatus();
1545}
1546
1548 util::logf("Saving Map Properties");
1549 for (int i = 0; i < kDarkWorldMapIdStart; i++) {
1550 RETURN_IF_ERROR(rom()->WriteByte(kAreaGfxIdPtr + i,
1551 overworld_maps_[i].area_graphics()));
1553 overworld_maps_[i].area_palette()));
1554 RETURN_IF_ERROR(rom()->WriteByte(kOverworldSpriteset + i,
1555 overworld_maps_[i].sprite_graphics(0)));
1557 rom()->WriteByte(kOverworldSpriteset + kDarkWorldMapIdStart + i,
1558 overworld_maps_[i].sprite_graphics(1)));
1561 overworld_maps_[i].sprite_graphics(2)));
1563 overworld_maps_[i].sprite_palette(0)));
1566 overworld_maps_[i].sprite_palette(1)));
1567 RETURN_IF_ERROR(rom()->WriteByte(
1569 overworld_maps_[i].sprite_palette(2)));
1570 }
1571
1572 for (int i = kDarkWorldMapIdStart; i < kSpecialWorldMapIdStart; i++) {
1573 RETURN_IF_ERROR(rom()->WriteByte(kAreaGfxIdPtr + i,
1574 overworld_maps_[i].area_graphics()));
1575 RETURN_IF_ERROR(rom()->WriteByte(kOverworldSpriteset + i,
1576 overworld_maps_[i].sprite_graphics(0)));
1578 rom()->WriteByte(kOverworldSpriteset + kDarkWorldMapIdStart + i,
1579 overworld_maps_[i].sprite_graphics(1)));
1582 overworld_maps_[i].sprite_graphics(2)));
1584 overworld_maps_[i].area_palette()));
1587 overworld_maps_[i].sprite_palette(0)));
1588 RETURN_IF_ERROR(rom()->WriteByte(
1590 overworld_maps_[i].sprite_palette(1)));
1591 RETURN_IF_ERROR(rom()->WriteByte(kOverworldSpritePaletteIds + 192 + i,
1592 overworld_maps_[i].sprite_palette(2)));
1593 }
1594
1595 return absl::OkStatus();
1596}
1597
1598} // namespace zelda3
1599} // namespace yaze
The Rom class is used to load, save, and modify Rom data.
Definition rom.h:58
static Flags & get()
Definition features.h:66
Tile composition of four 16x16 tiles.
Definition snes_tile.h:88
uint64_t GetPackedValue() const
Definition snes_tile.h:118
SNES 16-bit tile metadata container.
Definition snes_tile.h:50
absl::Status SaveMap32Expanded()
absl::Status LoadExits()
Definition overworld.cc:360
std::vector< uint16_t > tiles32_list_
Definition overworld.h:266
absl::Status Load(Rom *rom)
Definition overworld.cc:21
std::vector< OverworldItem > all_items_
Definition overworld.h:260
void OrganizeMapTiles(std::vector< uint8_t > &bytes, std::vector< uint8_t > &bytes2, int i, int sx, int sy, int &ttpos)
Definition overworld.cc:203
std::array< int, kNumOverworldMaps > map_pointers1
Definition overworld.h:276
std::vector< gfx::Tile32 > tiles32_unique_
Definition overworld.h:264
absl::Status SaveMapProperties()
absl::Status SaveMap32Tiles()
std::vector< OverworldEntrance > all_entrances_
Definition overworld.h:257
OverworldMapTiles map_tiles_
Definition overworld.h:254
absl::Status SaveMap16Tiles()
absl::Status SaveLargeMaps()
Definition overworld.cc:670
std::array< uint8_t, kNumOverworldMaps > map_parent_
Definition overworld.h:269
void AssignWorldTiles(int x, int y, int sx, int sy, int tpos, OverworldBlockset &world)
Definition overworld.cc:191
std::array< uint8_t, kNumTileTypes > all_tiles_types_
Definition overworld.h:270
absl::Status CreateTile32Tilemap()
std::array< int, kNumOverworldMaps > map_pointers1_id
Definition overworld.h:274
absl::Status LoadItems()
Definition overworld.cc:412
absl::Status SaveEntrances()
absl::Status SaveExits()
absl::Status LoadSprites()
Definition overworld.cc:462
absl::Status LoadHoles()
Definition overworld.cc:340
std::vector< OverworldMap > overworld_maps_
Definition overworld.h:256
absl::Status SaveItems()
absl::Status LoadEntrances()
Definition overworld.cc:305
absl::Status Save(Rom *rom)
Definition overworld.cc:520
absl::Status SaveOverworldMaps()
Definition overworld.cc:532
std::array< std::vector< Sprite >, 3 > all_sprites_
Definition overworld.h:271
std::array< int, kNumOverworldMaps > map_pointers2_id
Definition overworld.h:275
absl::Status LoadOverworldMaps()
Definition overworld.cc:273
std::vector< gfx::Tile16 > tiles16_
Definition overworld.h:262
absl::Status AssembleMap16Tiles()
Definition overworld.cc:163
absl::Status LoadSpritesFromMap(int sprite_start, int sprite_count, int sprite_index)
Definition overworld.cc:481
std::array< std::vector< uint8_t >, kNumOverworldMaps > map_data_p1
Definition overworld.h:272
absl::Status SaveMap16Expanded()
std::vector< OverworldExit > all_exits_
Definition overworld.h:259
std::array< int, kNumOverworldMaps > map_pointers2
Definition overworld.h:277
absl::StatusOr< uint16_t > GetTile16ForTile32(int index, int quadrant, int dimension, const uint32_t *map32address)
Definition overworld.cc:99
std::array< std::vector< uint8_t >, kNumOverworldMaps > map_data_p2
Definition overworld.h:273
absl::Status AssembleMap32Tiles()
Definition overworld.cc:110
OverworldBlockset & GetMapTiles(int world_type)
Definition overworld.h:173
std::vector< OverworldEntrance > all_holes_
Definition overworld.h:258
#define RETURN_IF_ERROR(expression)
Definition macro.h:51
#define ASSIGN_OR_RETURN(type_variable_name, expression)
Definition macro.h:59
std::vector< uint8_t > HyruleMagicDecompress(uint8_t const *src, int *const size, int const p_big_endian)
TileInfo GetTilesInfo(uint16_t tile)
Definition snes_tile.cc:354
std::vector< uint8_t > HyruleMagicCompress(uint8_t const *const src, int const oldsize, int *const size, int const flag)
std::string HexByte(uint8_t byte, HexStringParams params)
Definition hex.cc:30
std::string HexLong(uint32_t dword, HexStringParams params)
Definition hex.cc:56
bool CompareItemsArrays(std::vector< OverworldItem > item_array1, std::vector< OverworldItem > item_array2)
std::vector< uint64_t > GetAllTile16(OverworldMapTiles &map_tiles_)
Definition overworld.cc:991
Zelda 3 specific classes and functions.
constexpr int OWExitYScroll
constexpr int kAreaGfxIdPtr
Definition overworld.h:40
constexpr int kOverworldHoleArea
constexpr int kOverworldTransitionPositionY
Definition overworld.h:64
constexpr int kOverworldEntrancePos
constexpr int kOverworldHoleEntrance
constexpr int kNumMapsPerWorld
Definition overworld.h:104
constexpr int kOverworldSpriteset
Definition overworld.h:33
constexpr int kMap16ExpandedFlagPos
Definition overworld.h:88
constexpr int LimitOfMap32
Definition overworld.h:101
constexpr int NumberOfMap16Ex
Definition overworld.h:100
constexpr int kOverworldScreenTileMapChangeByScreen1
Definition overworld.h:69
constexpr int kOverworldMapDataOverflow
Definition overworld.h:74
constexpr int kOverworldMapSizeHighByte
Definition overworld.h:55
constexpr int kOverworldEntranceEntranceIdExpanded
constexpr int kNumTileTypes
Definition overworld.h:94
constexpr int NumberOfMap32
Definition overworld.h:103
constexpr int kNumOverworldMapItemPointers
constexpr int kOverworldScreenSize
Definition overworld.h:66
constexpr int kOverworldScreenTileMapChangeByScreen4
Definition overworld.h:72
constexpr int kNumTile16Individual
Definition overworld.h:97
constexpr int kNumOverworldHoles
constexpr int kSpecialWorldMapIdStart
constexpr int OWExitDoorType2
constexpr int kOverworldEntranceEntranceId
constexpr int kOverworldItemsAddress
constexpr int kMap16Tiles
Definition overworld.h:95
constexpr int kOverworldHolePos
constexpr int kNumOverworldMaps
Definition overworld.h:96
constexpr int kOverworldEntranceMap
constexpr int kOverworldItemsEndData
constexpr int OWExitYCamera
std::vector< std::vector< uint16_t > > OverworldBlockset
Represents tile32 data for the overworld.
constexpr int kMap32TileBLExpanded
Definition overworld.h:84
constexpr int kOverworldTransitionPositionX
Definition overworld.h:65
constexpr int OWExitXScroll
constexpr int OWExitRoomId
constexpr int OWExitXCamera
constexpr int OWExitUnk1
constexpr int OWExitYPlayer
constexpr int kOverworldScreenSizeForLoading
Definition overworld.h:67
constexpr int kOverworldSpritePaletteIds
Definition overworld.h:31
constexpr int kMap32TileBRExpanded
Definition overworld.h:85
constexpr int kMap32TileCountExpanded
Definition overworld.h:86
constexpr int OWExitMapId
constexpr int OWExitUnk2
constexpr int kTransitionTargetWest
Definition overworld.h:77
constexpr int kOverworldSpritesZelda
Definition overworld.h:38
constexpr int kOverworldMapParentId
Definition overworld.h:63
constexpr int kMap32ExpandedFlagPos
Definition overworld.h:87
constexpr int kOverworldEntrancePosExpanded
constexpr int OWExitDoorType1
constexpr int kOverworldItemsPointers
constexpr int kNumOverworldExits
constexpr int NumberOfMap16
Definition overworld.h:99
constexpr int kOverworldMapSize
Definition overworld.h:52
constexpr int kOverworldScreenTileMapChangeByScreen2
Definition overworld.h:70
constexpr int kOverworldEntranceMapExpanded
constexpr int kDarkWorldMapIdStart
constexpr int kOverworldCompressedMapPos
Definition overworld.h:91
constexpr int kOverworldSpritesBeginning
Definition overworld.h:36
constexpr int kOverworldScreenTileMapChangeByScreen3
Definition overworld.h:71
constexpr int kMap16TilesExpanded
Definition overworld.h:82
constexpr int kOverworldEntranceExpandedFlagPos
Definition overworld.h:89
constexpr int kNumOverworldEntrances
constexpr int kOverworldSpritesAgahnim
Definition overworld.h:37
constexpr int kTransitionTargetNorth
Definition overworld.h:76
constexpr int kOverworldCompressedOverflowPos
Definition overworld.h:92
constexpr int kMap32TileTRExpanded
Definition overworld.h:83
constexpr int OWExitXPlayer
constexpr int OWExitVram
constexpr int kOverworldMapPaletteIds
Definition overworld.h:30
Main namespace for the application.
Definition controller.cc:18
uint32_t PcToSnes(uint32_t addr)
Definition snes.h:17
uint32_t SnesToPc(uint32_t addr) noexcept
Definition snes.h:8
Overworld map tile32 data.