yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
overworld_entrance.cc
Go to the documentation of this file.
2
3#include <vector>
4
5#include "absl/status/status.h"
6#include "absl/status/statusor.h"
7#include "rom/rom.h"
8#include "util/macro.h"
9
10namespace yaze::zelda3 {
11
12absl::StatusOr<std::vector<OverworldEntrance>> LoadEntrances(Rom* rom) {
13 std::vector<OverworldEntrance> entrances;
14 int ow_entrance_map_ptr = kOverworldEntranceMap;
15 int ow_entrance_pos_ptr = kOverworldEntrancePos;
16 int ow_entrance_id_ptr = kOverworldEntranceEntranceId;
17 int num_entrances = 129;
18
19 // Check if expanded entrance data is actually present in ROM
20 // The flag position should contain 0xB8 for vanilla, something else for
21 // expanded
22 if (rom->data()[kOverworldEntranceExpandedFlagPos] != 0xB8) {
23 // ROM has expanded entrance data - use expanded addresses
24 ow_entrance_map_ptr = kOverworldEntranceMapExpanded;
25 ow_entrance_pos_ptr = kOverworldEntrancePosExpanded;
26 ow_entrance_id_ptr = kOverworldEntranceEntranceIdExpanded;
27 num_entrances = 256; // Expanded entrance count
28 }
29 // Otherwise use vanilla addresses (already set above)
30
31 for (int i = 0; i < num_entrances; i++) {
32 ASSIGN_OR_RETURN(auto map_id, rom->ReadWord(ow_entrance_map_ptr + (i * 2)));
33 ASSIGN_OR_RETURN(auto map_pos,
34 rom->ReadWord(ow_entrance_pos_ptr + (i * 2)));
35 ASSIGN_OR_RETURN(auto entrance_id, rom->ReadByte(ow_entrance_id_ptr + i));
36 int p = map_pos >> 1;
37 int x = (p % 64);
38 int y = (p >> 6);
39 bool deleted = false;
40 if (map_pos == 0xFFFF) {
41 deleted = true;
42 }
43 entrances.emplace_back(
44 (x * 16) + (((map_id % 64) - (((map_id % 64) / 8) * 8)) * 512),
45 (y * 16) + (((map_id % 64) / 8) * 512), entrance_id, map_id, map_pos,
46 deleted);
47 }
48
49 return entrances;
50}
51
52absl::StatusOr<std::vector<OverworldEntrance>> LoadHoles(Rom* rom) {
53 constexpr int kNumHoles = 0x13;
54 std::vector<OverworldEntrance> holes;
55 for (int i = 0; i < kNumHoles; i++) {
56 ASSIGN_OR_RETURN(auto map_id, rom->ReadWord(kOverworldHoleArea + (i * 2)));
57 ASSIGN_OR_RETURN(auto map_pos, rom->ReadWord(kOverworldHolePos + (i * 2)));
58 ASSIGN_OR_RETURN(auto entrance_id,
60 int p = (map_pos + 0x400) >> 1;
61 int x = (p % 64);
62 int y = (p >> 6);
63 holes.emplace_back(
64 (x * 16) + (((map_id % 64) - (((map_id % 64) / 8) * 8)) * 512),
65 (y * 16) + (((map_id % 64) / 8) * 512), entrance_id, map_id,
66 (uint16_t)(map_pos + 0x400), true);
67 }
68 return holes;
69}
70
71absl::Status SaveEntrances(Rom* rom,
72 const std::vector<OverworldEntrance>& entrances,
73 bool expanded_entrances) {
74 auto write_entrance = [&](int index, uint32_t map_addr, uint32_t pos_addr,
75 uint32_t id_addr) -> absl::Status {
76 // Mirrors ZeldaFullEditor/Save.cs::SaveOWEntrances (see lines ~1081-1085)
77 // where MapID and MapPos are written as 16-bit words and EntranceID as a
78 // byte.
79 RETURN_IF_ERROR(rom->WriteShort(map_addr, entrances[index].map_id_));
80 RETURN_IF_ERROR(rom->WriteShort(pos_addr, entrances[index].map_pos_));
81 RETURN_IF_ERROR(rom->WriteByte(id_addr, entrances[index].entrance_id_));
82 return absl::OkStatus();
83 };
84
85 // Always keep the legacy tables in sync for pure vanilla ROMs so e.g. Hyrule
86 // Magic expects them. ZScream does the same in SaveOWEntrances.
87 for (int i = 0; i < kNumOverworldEntrances; ++i) {
88 RETURN_IF_ERROR(write_entrance(i, kOverworldEntranceMap + (i * 2),
89 kOverworldEntrancePos + (i * 2),
91 }
92
93 if (expanded_entrances) {
94 // For ZS v3+ ROMs, mirror writes into the expanded tables the way
95 // ZeldaFullEditor does when the ASM patch is active.
96 for (int i = 0; i < kNumOverworldEntrances; ++i) {
97 RETURN_IF_ERROR(write_entrance(i, kOverworldEntranceMapExpanded + (i * 2),
100 }
101 }
102
103 return absl::OkStatus();
104}
105
106absl::Status SaveHoles(Rom* rom, const std::vector<OverworldEntrance>& holes) {
107 for (int i = 0; i < kNumOverworldHoles; ++i) {
109 rom->WriteShort(kOverworldHoleArea + (i * 2), holes[i].map_id_));
110
111 // ZeldaFullEditor/Data/Overworld.cs::LoadHoles() adds 0x400 when loading
112 // (see lines ~1006-1014). SaveOWEntrances subtracts it before writing
113 // (Save.cs lines ~1088-1092). We replicate that here so vanilla ROMs
114 // receive the expected values.
115 uint16_t rom_map_pos = static_cast<uint16_t>(holes[i].map_pos_ >= 0x400
116 ? holes[i].map_pos_ - 0x400
117 : holes[i].map_pos_);
118 RETURN_IF_ERROR(rom->WriteShort(kOverworldHolePos + (i * 2), rom_map_pos));
120 rom->WriteByte(kOverworldHoleEntrance + i, holes[i].entrance_id_));
121 }
122
123 return absl::OkStatus();
124}
125
126} // namespace yaze::zelda3
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:24
absl::Status WriteByte(int addr, uint8_t value)
Definition rom.cc:286
absl::StatusOr< uint16_t > ReadWord(int offset)
Definition rom.cc:228
auto data() const
Definition rom.h:135
absl::StatusOr< uint8_t > ReadByte(int offset)
Definition rom.cc:221
absl::Status WriteShort(int addr, uint16_t value)
Definition rom.cc:316
#define ASSIGN_OR_RETURN(type_variable_name, expression)
Definition macro.h:62
Zelda 3 specific classes and functions.
Definition editor.h:35
absl::Status SaveEntrances(Rom *rom, const std::vector< OverworldEntrance > &entrances, bool expanded_entrances)
constexpr int kOverworldHoleArea
constexpr int kOverworldEntrancePos
constexpr int kOverworldHoleEntrance
absl::StatusOr< std::vector< OverworldEntrance > > LoadEntrances(Rom *rom)
constexpr int kOverworldEntranceEntranceIdExpanded
constexpr int kNumOverworldHoles
constexpr int kOverworldEntranceEntranceId
constexpr int kOverworldHolePos
constexpr int kOverworldEntranceMap
constexpr int kOverworldEntrancePosExpanded
constexpr int kOverworldEntranceMapExpanded
absl::Status SaveHoles(Rom *rom, const std::vector< OverworldEntrance > &holes)
absl::StatusOr< std::vector< OverworldEntrance > > LoadHoles(Rom *rom)
constexpr int kOverworldEntranceExpandedFlagPos
constexpr int kNumOverworldEntrances
#define RETURN_IF_ERROR(expr)
Definition snes.cc:22