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