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