yaze 0.2.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dungeon_map.cc
Go to the documentation of this file.
1#include "dungeon_map.h"
2
3#include <fstream>
4#include <vector>
5
8#include "app/gfx/bitmap.h"
9#include "app/gfx/snes_tile.h"
10#include "app/gfx/tilemap.h"
11#include "app/snes.h"
12#include "util/hex.h"
13
14namespace yaze::zelda3 {
15
16absl::StatusOr<std::vector<DungeonMap>> LoadDungeonMaps(
17 Rom &rom, DungeonMapLabels &dungeon_map_labels) {
18 std::vector<DungeonMap> dungeon_maps;
19 std::vector<std::array<uint8_t, kNumRooms>> current_floor_rooms_d;
20 std::vector<std::array<uint8_t, kNumRooms>> current_floor_gfx_d;
21 int total_floors_d;
22 uint8_t nbr_floor_d;
23 uint8_t nbr_basement_d;
24
25 for (int d = 0; d < kNumDungeons; d++) {
26 current_floor_rooms_d.clear();
27 current_floor_gfx_d.clear();
28 ASSIGN_OR_RETURN(int ptr, rom.ReadWord(kDungeonMapRoomsPtr + (d * 2)));
29 ASSIGN_OR_RETURN(int ptr_gfx, rom.ReadWord(kDungeonMapGfxPtr + (d * 2)));
30 ptr |= 0x0A0000; // Add bank to the short ptr
31 ptr_gfx |= 0x0A0000; // Add bank to the short ptr
32 int pc_ptr = SnesToPc(ptr); // Contains data for the next 25 rooms
33 int pc_ptr_gfx = SnesToPc(ptr_gfx); // Contains data for the next 25 rooms
34
35 ASSIGN_OR_RETURN(uint16_t boss_room_d,
36 rom.ReadWord(kDungeonMapBossRooms + (d * 2)));
37
38 ASSIGN_OR_RETURN(nbr_basement_d, rom.ReadByte(kDungeonMapFloors + (d * 2)));
39 nbr_basement_d &= 0x0F;
40
41 ASSIGN_OR_RETURN(nbr_floor_d, rom.ReadByte(kDungeonMapFloors + (d * 2)));
42 nbr_floor_d &= 0xF0;
43 nbr_floor_d = nbr_floor_d >> 4;
44
45 total_floors_d = nbr_basement_d + nbr_floor_d;
46
47 // for each floor in the dungeon
48 for (int i = 0; i < total_floors_d; i++) {
49 dungeon_map_labels[d].emplace_back();
50
51 std::array<uint8_t, kNumRooms> rdata;
52 std::array<uint8_t, kNumRooms> gdata;
53
54 // for each room on the floor
55 for (int j = 0; j < kNumRooms; j++) {
56 gdata[j] = 0xFF;
57 rdata[j] = rom.data()[pc_ptr + j + (i * kNumRooms)]; // Set the rooms
58
59 gdata[j] = rdata[j] == 0x0F ? 0xFF : rom.data()[pc_ptr_gfx++];
60
61 std::string label = util::HexByte(rdata[j]);
62 dungeon_map_labels[d][i][j] = label;
63 }
64
65 current_floor_gfx_d.push_back(gdata); // Add new floor gfx data
66 current_floor_rooms_d.push_back(rdata); // Add new floor data
67 }
68
69 dungeon_maps.emplace_back(boss_room_d, nbr_floor_d, nbr_basement_d,
70 current_floor_rooms_d, current_floor_gfx_d);
71 }
72
73 return dungeon_maps;
74}
75
76absl::Status SaveDungeonMaps(Rom &rom, std::vector<DungeonMap> &dungeon_maps) {
77 for (int d = 0; d < kNumDungeons; d++) {
78 int ptr = kDungeonMapRoomsPtr + (d * 2);
79 int ptr_gfx = kDungeonMapGfxPtr + (d * 2);
80 int pc_ptr = SnesToPc(ptr);
81 int pc_ptr_gfx = SnesToPc(ptr_gfx);
82
83 const int nbr_floors = dungeon_maps[d].nbr_of_floor;
84 const int nbr_basements = dungeon_maps[d].nbr_of_basement;
85 for (int i = 0; i < nbr_floors + nbr_basements; i++) {
86 for (int j = 0; j < kNumRooms; j++) {
87 RETURN_IF_ERROR(rom.WriteByte(pc_ptr + j + (i * kNumRooms),
88 dungeon_maps[d].floor_rooms[i][j]));
89 RETURN_IF_ERROR(rom.WriteByte(pc_ptr_gfx + j + (i * kNumRooms),
90 dungeon_maps[d].floor_gfx[i][j]));
91 pc_ptr_gfx++;
92 }
93 }
94 }
95
96 return absl::OkStatus();
97}
98
99absl::Status LoadDungeonMapTile16(gfx::Tilemap &tile16_blockset, Rom &rom,
100 const std::vector<uint8_t> &gfx_data,
101 bool bin_mode) {
102 tile16_blockset.tile_size = {16, 16};
103 tile16_blockset.map_size = {186, 186};
104 tile16_blockset.atlas.Create(256, 192, 8,
105 std::vector<uint8_t>(256 * 192, 0x00));
106
107 for (int i = 0; i < kNumDungeonMapTile16; i++) {
108 int addr = kDungeonMapTile16;
109 if (rom.data()[kDungeonMapExpCheck] != 0xB9) {
111 }
112
113 ASSIGN_OR_RETURN(auto tl, rom.ReadWord(addr + (i * 8)));
114 gfx::TileInfo t1 = gfx::WordToTileInfo(tl); // Top left
115
116 ASSIGN_OR_RETURN(auto tr, rom.ReadWord(addr + 2 + (i * 8)));
117 gfx::TileInfo t2 = gfx::WordToTileInfo(tr); // Top right
118
119 ASSIGN_OR_RETURN(auto bl, rom.ReadWord(addr + 4 + (i * 8)));
120 gfx::TileInfo t3 = gfx::WordToTileInfo(bl); // Bottom left
121
122 ASSIGN_OR_RETURN(auto br, rom.ReadWord(addr + 6 + (i * 8)));
123 gfx::TileInfo t4 = gfx::WordToTileInfo(br); // Bottom right
124
125 int sheet_offset = 212;
126 if (bin_mode) {
127 sheet_offset = 0;
128 }
129 ComposeTile16(tile16_blockset, gfx_data, t1, t2, t3, t4, sheet_offset);
130 }
131
132 tile16_blockset.atlas.SetPalette(*rom.mutable_dungeon_palette(3));
133 core::Renderer::Get().RenderBitmap(&tile16_blockset.atlas);
134 return absl::OkStatus();
135}
136
137absl::Status SaveDungeonMapTile16(gfx::Tilemap &tile16_blockset, Rom &rom) {
138 for (int i = 0; i < kNumDungeonMapTile16; i++) {
139 int addr = kDungeonMapTile16;
140 if (rom.data()[kDungeonMapExpCheck] != 0xB9) {
142 }
143
144 gfx::TileInfo t1 = tile16_blockset.tile_info[i][0];
145 gfx::TileInfo t2 = tile16_blockset.tile_info[i][1];
146 gfx::TileInfo t3 = tile16_blockset.tile_info[i][2];
147 gfx::TileInfo t4 = tile16_blockset.tile_info[i][3];
148
149 auto tl = gfx::TileInfoToWord(t1);
150 RETURN_IF_ERROR(rom.WriteWord(addr + (i * 8), tl));
151
152 auto tr = gfx::TileInfoToWord(t2);
153 RETURN_IF_ERROR(rom.WriteWord(addr + 2 + (i * 8), tr));
154
155 auto bl = gfx::TileInfoToWord(t3);
156 RETURN_IF_ERROR(rom.WriteWord(addr + 4 + (i * 8), bl));
157
158 auto br = gfx::TileInfoToWord(t4);
159 RETURN_IF_ERROR(rom.WriteWord(addr + 6 + (i * 8), br));
160 }
161 return absl::OkStatus();
162}
163
165 gfx::Tilemap &tile16_blockset,
166 std::array<gfx::Bitmap, 4> &sheets,
167 std::vector<uint8_t> &gfx_bin_data) {
168 std::string bin_file = core::FileDialogWrapper::ShowOpenFileDialog();
169 if (bin_file.empty()) {
170 return absl::InternalError("No file selected");
171 }
172
173 std::ifstream file(bin_file, std::ios::binary);
174 if (!file.is_open()) {
175 return absl::InternalError("Failed to open file");
176 }
177
178 // Read the gfx data into a buffer
179 std::vector<uint8_t> bin_data((std::istreambuf_iterator<char>(file)),
180 std::istreambuf_iterator<char>());
181 auto converted_bin = gfx::SnesTo8bppSheet(bin_data, 4, 4);
182 gfx_bin_data = converted_bin;
183 if (LoadDungeonMapTile16(tile16_blockset, rom, converted_bin, true).ok()) {
184 std::vector<std::vector<uint8_t>> gfx_sheets;
185 for (int i = 0; i < 4; i++) {
186 gfx_sheets.emplace_back(converted_bin.begin() + (i * 0x1000),
187 converted_bin.begin() + ((i + 1) * 0x1000));
188 sheets[i] = gfx::Bitmap(128, 32, 8, gfx_sheets[i]);
189 sheets[i].SetPalette(*rom.mutable_dungeon_palette(3));
190 core::Renderer::Get().RenderBitmap(&sheets[i]);
191 }
192 }
193 file.close();
194
195 return absl::OkStatus();
196}
197
198} // namespace yaze::zelda3
The Rom class is used to load, save, and modify Rom data.
Definition rom.h:58
absl::Status WriteByte(int addr, uint8_t value)
Definition rom.cc:582
auto mutable_dungeon_palette(int i)
Definition rom.h:190
absl::StatusOr< uint16_t > ReadWord(int offset)
Definition rom.cc:522
auto data() const
Definition rom.h:177
absl::StatusOr< uint8_t > ReadByte(int offset)
Definition rom.cc:515
absl::Status WriteWord(int addr, uint16_t value)
Definition rom.cc:593
static std::string ShowOpenFileDialog()
ShowOpenFileDialog opens a file dialog and returns the selected filepath.
static Renderer & Get()
Definition renderer.h:26
void RenderBitmap(gfx::Bitmap *bitmap)
Definition renderer.h:45
Represents a bitmap image.
Definition bitmap.h:59
void Create(int width, int height, int depth, std::span< uint8_t > data)
Create a bitmap with the given dimensions and data.
Definition bitmap.cc:218
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap.
Definition bitmap.cc:307
SNES 16-bit tile metadata container.
Definition snes_tile.h:50
#define RETURN_IF_ERROR(expression)
Definition macro.h:51
#define ASSIGN_OR_RETURN(type_variable_name, expression)
Definition macro.h:59
uint16_t TileInfoToWord(TileInfo tile_info)
Definition snes_tile.cc:291
std::vector< uint8_t > SnesTo8bppSheet(std::span< uint8_t > sheet, int bpp, int num_sheets)
Definition snes_tile.cc:129
TileInfo WordToTileInfo(uint16_t word)
Definition snes_tile.cc:308
std::string HexByte(uint8_t byte, HexStringParams params)
Definition hex.cc:30
Zelda 3 specific classes and functions.
absl::Status LoadDungeonMapGfxFromBinary(Rom &rom, gfx::Tilemap &tile16_blockset, std::array< gfx::Bitmap, 4 > &sheets, std::vector< uint8_t > &gfx_bin_data)
Load the dungeon map gfx from binary.
constexpr int kDungeonMapExpCheck
Definition dungeon_map.h:23
absl::Status LoadDungeonMapTile16(gfx::Tilemap &tile16_blockset, Rom &rom, const std::vector< uint8_t > &gfx_data, bool bin_mode)
Load the dungeon map tile16 from the ROM.
constexpr int kDungeonMapFloors
Definition dungeon_map.h:15
constexpr int kDungeonMapTile16
Definition dungeon_map.h:24
constexpr int kNumRooms
Definition dungeon_map.h:35
constexpr int kDungeonMapTile16Expanded
Definition dungeon_map.h:25
absl::Status SaveDungeonMapTile16(gfx::Tilemap &tile16_blockset, Rom &rom)
Save the dungeon map tile16 to the ROM.
constexpr int kDungeonMapBossRooms
Definition dungeon_map.h:28
constexpr int kDungeonMapRoomsPtr
Definition dungeon_map.h:14
constexpr int kNumDungeonMapTile16
Definition dungeon_map.h:36
constexpr int kNumDungeons
Definition dungeon_map.h:34
std::array< std::vector< std::array< std::string, kNumRooms > >, kNumDungeons > DungeonMapLabels
Definition dungeon_map.h:59
absl::StatusOr< std::vector< DungeonMap > > LoadDungeonMaps(Rom &rom, DungeonMapLabels &dungeon_map_labels)
Load the dungeon maps from the ROM.
constexpr int kDungeonMapGfxPtr
Definition dungeon_map.h:17
absl::Status SaveDungeonMaps(Rom &rom, std::vector< DungeonMap > &dungeon_maps)
Save the dungeon maps to the ROM.
uint32_t SnesToPc(uint32_t addr) noexcept
Definition snes.h:8
std::vector< std::array< gfx::TileInfo, 4 > > tile_info
Definition tilemap.h:19