yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
room_default_entrance.cc
Go to the documentation of this file.
2
3#include <map>
4
5#include "rom/rom.h"
9#include "zelda3/game_data.h"
11
12namespace yaze::zelda3 {
13namespace {
14
15constexpr uint8_t kEmptyMapRoom = 0x0F;
16
17} // namespace
18
19int DungeonBackgroundPaletteOffset(uint8_t main_blockset,
20 int destination_slot) {
21 if (destination_slot < 0 || destination_slot >= 8)
22 return 0;
23 const int runtime_slot = 7 - destination_slot;
24 const bool right = main_blockset < 0x20
25 ? runtime_slot >= 4
26 : runtime_slot == 2 || runtime_slot == 3 ||
27 runtime_slot == 4 || runtime_slot == 7;
28 return right ? 8 : 0;
29}
30
32 int room_id, uint8_t header_blockset, uint8_t requested_main_blockset,
33 const GameData& game_data) {
34 const auto valid = [&game_data](uint8_t group) {
35 return group != 0xFF && group < game_data.main_blockset_ids.size();
36 };
37 if (valid(requested_main_blockset)) {
38 return {requested_main_blockset, RoomMainBlocksetSource::kExplicitPreview};
39 }
40 if (room_id >= 0 &&
41 room_id < static_cast<int>(game_data.room_default_entrances.size())) {
42 const auto& entrance = game_data.room_default_entrances[room_id];
43 if (valid(entrance.main_blockset)) {
44 return {entrance.main_blockset,
45 entrance.source == RoomEntranceSource::kDirect
48 }
49 }
50 if (valid(header_blockset)) {
51 return {header_blockset, RoomMainBlocksetSource::kHeaderFallback};
52 }
54}
55
56std::vector<RoomDefaultEntrance> ComputeRoomDefaultEntrances(Rom& rom) {
57 std::vector<RoomDefaultEntrance> result(kNumberOfRooms);
58 if (!rom.is_loaded()) {
59 return result;
60 }
61 if (!ResolveEntranceLayout(rom.vector()).ok()) {
62 // Do not infer defaults from the populated but inactive legacy tables.
63 return result;
64 }
65
66 struct EntranceInfo {
67 int id;
68 int room;
69 uint8_t main_blockset;
70 uint8_t dungeon_id;
71 };
72 std::vector<EntranceInfo> entrances;
73 entrances.reserve(kNumRegularDungeonEntrances);
74 for (int id = 0; id < kNumRegularDungeonEntrances; ++id) {
75 RoomEntrance entrance(&rom, static_cast<uint8_t>(id), false);
76 if (!entrance.load_status().ok()) {
77 continue;
78 }
79 entrances.push_back(
80 {id, entrance.room_, entrance.blockset_, entrance.dungeon_id_});
81 }
82
83 // 1. Direct entrances.
84 for (const EntranceInfo& entrance : entrances) {
85 if (entrance.room < 0 || entrance.room >= kNumberOfRooms) {
86 continue;
87 }
88 RoomDefaultEntrance& slot = result[static_cast<size_t>(entrance.room)];
90 slot = {entrance.id, entrance.main_blockset, RoomEntranceSource::kDirect,
91 -1};
92 }
93 }
94
95 // 2. Pause-menu dungeon maps.
96 DungeonMapLabels labels;
97 auto maps = LoadDungeonMaps(rom, labels);
98 if (maps.ok()) {
99 for (const DungeonMap& map : *maps) {
100 std::vector<int> rooms;
101 for (const auto& floor : map.floor_rooms) {
102 for (uint8_t room : floor) {
103 if (room != kEmptyMapRoom) {
104 rooms.push_back(room);
105 }
106 }
107 }
108 // Which dungeon ID this map belongs to: the most common one among
109 // entrances that lead straight into its rooms.
110 std::map<uint8_t, int> votes;
111 for (int room : rooms) {
112 for (const EntranceInfo& entrance : entrances) {
113 if (entrance.room == room && entrance.dungeon_id != 0xFF) {
114 ++votes[entrance.dungeon_id];
115 }
116 }
117 }
118 if (votes.empty()) {
119 continue;
120 }
121 uint8_t dungeon_id = votes.begin()->first;
122 for (const auto& [id, count] : votes) {
123 if (count > votes[dungeon_id]) {
124 dungeon_id = id;
125 }
126 }
127 const EntranceInfo* representative = nullptr;
128 for (const EntranceInfo& entrance : entrances) {
129 if (entrance.dungeon_id == dungeon_id) {
130 representative = &entrance;
131 break;
132 }
133 }
134 if (representative == nullptr) {
135 continue;
136 }
137 for (int room : rooms) {
138 RoomDefaultEntrance& slot = result[static_cast<size_t>(room)];
139 if (slot.source == RoomEntranceSource::kNone) {
140 slot = {representative->id, representative->main_blockset,
142 }
143 }
144 }
145 }
146
147 // 3. Neighbours in the 16-wide room grid, until nothing changes.
148 bool changed = true;
149 while (changed) {
150 changed = false;
151 for (int room = 0; room < kNumberOfRooms; ++room) {
152 if (result[static_cast<size_t>(room)].source !=
154 continue;
155 }
156 for (int neighbour : {room - 1, room + 1, room - 16, room + 16}) {
157 const bool adjacent = neighbour / 16 == room / 16 ||
158 neighbour == room - 16 || neighbour == room + 16;
159 if (neighbour < 0 || neighbour >= kNumberOfRooms || !adjacent) {
160 continue;
161 }
162 const RoomDefaultEntrance& from =
163 result[static_cast<size_t>(neighbour)];
164 if (from.source == RoomEntranceSource::kNone) {
165 continue;
166 }
167 result[static_cast<size_t>(room)] = {
168 from.entrance_id, from.main_blockset,
170 changed = true;
171 break;
172 }
173 }
174 }
175 return result;
176}
177
178} // 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:49
const auto & vector() const
Definition rom.h:205
bool is_loaded() const
Definition rom.h:187
Dungeon Room Entrance or Spawn Point.
const absl::Status & load_status() const
Zelda 3 specific classes and functions.
std::vector< RoomDefaultEntrance > ComputeRoomDefaultEntrances(Rom &rom)
constexpr int kNumRegularDungeonEntrances
int DungeonBackgroundPaletteOffset(uint8_t main_blockset, int destination_slot)
RoomMainBlocksetResolution ResolveRoomMainBlockset(int room_id, uint8_t header_blockset, uint8_t requested_main_blockset, const GameData &game_data)
std::array< std::vector< std::array< std::string, kNumRooms > >, kNumDungeons > DungeonMapLabels
Definition dungeon_map.h:72
constexpr int kNumberOfRooms
absl::StatusOr< std::vector< DungeonMap > > LoadDungeonMaps(Rom &rom, DungeonMapLabels &dungeon_map_labels)
Load the dungeon maps from the ROM.
absl::StatusOr< EntranceLayout > ResolveEntranceLayout(std::span< const uint8_t > data)
DungeonMap represents the map menu for a dungeon.
Definition dungeon_map.h:54
std::vector< RoomDefaultEntrance > room_default_entrances
Definition game_data.h:118
std::array< std::array< uint8_t, 8 >, kNumMainBlocksets > main_blockset_ids
Definition game_data.h:97