yaze 0.2.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
room.cc
Go to the documentation of this file.
1#include "room.h"
2
3#include <dungeon.h>
4
5#include <cstdint>
6#include <vector>
7
8#include "absl/strings/str_cat.h"
9#include "app/rom.h"
13#include "util/macro.h"
14
15namespace yaze {
16namespace zelda3 {
17
19 int header_pointer = (rom()->data()[kRoomHeaderPointer + 2] << 16) +
20 (rom()->data()[kRoomHeaderPointer + 1] << 8) +
21 (rom()->data()[kRoomHeaderPointer]);
22 header_pointer = SnesToPc(header_pointer);
23
24 int address = (rom()->data()[kRoomHeaderPointerBank] << 16) +
25 (rom()->data()[(header_pointer + 1) + (room_id_ * 2)] << 8) +
26 rom()->data()[(header_pointer) + (room_id_ * 2)];
27
28 auto header_location = SnesToPc(address);
29
30 bg2_ = (background2)((rom()->data()[header_location] >> 5) & 0x07);
31 collision_ = (CollisionKey)((rom()->data()[header_location] >> 2) & 0x07);
32 is_light_ = ((rom()->data()[header_location]) & 0x01) == 1;
33
34 if (is_light_) {
35 bg2_ = background2::DarkRoom;
36 }
37
38 palette = ((rom()->data()[header_location + 1] & 0x3F));
39 blockset = (rom()->data()[header_location + 2]);
40 spriteset = (rom()->data()[header_location + 3]);
41 effect_ = (EffectKey)((rom()->data()[header_location + 4]));
42 tag1_ = (TagKey)((rom()->data()[header_location + 5]));
43 tag2_ = (TagKey)((rom()->data()[header_location + 6]));
44
45 staircase_plane_[0] = ((rom()->data()[header_location + 7] >> 2) & 0x03);
46 staircase_plane_[1] = ((rom()->data()[header_location + 7] >> 4) & 0x03);
47 staircase_plane_[2] = ((rom()->data()[header_location + 7] >> 6) & 0x03);
48 staircase_plane_[3] = ((rom()->data()[header_location + 8]) & 0x03);
49
50 holewarp = (rom()->data()[header_location + 9]);
51 staircase_rooms_[0] = (rom()->data()[header_location + 10]);
52 staircase_rooms_[1] = (rom()->data()[header_location + 11]);
53 staircase_rooms_[2] = (rom()->data()[header_location + 12]);
54 staircase_rooms_[3] = (rom()->data()[header_location + 13]);
55
57}
58
60 // Calculate the size of the room based on how many objects are used per room
61 // Some notes from hacker Zarby89
62 // vanilla rooms are using in average ~0x80 bytes
63 // a "normal" person who wants more details than vanilla will use around 0x100
64 // bytes per rooms you could fit 128 rooms like that in 1 bank
65 // F8000 I don't remember if that's PC or snes tho
66 // Check last rooms
67 // F8000+(roomid*3)
68 // So we want to search the rom() object at this addressed based on the room
69 // ID since it's the roomid * 3 we will by pulling 3 bytes at a time We can do
70 // this with the rom()->ReadByteVector(addr, size)
71 try {
72 // Existing room size address calculation...
73 auto room_size_address = 0xF8000 + (room_id_ * 3);
74
75 std::cout << "Room #" << room_id_ << " Address: " << std::hex
76 << room_size_address << std::endl;
77
78 // Reading bytes for long address construction
79 uint8_t low = rom()->data()[room_size_address];
80 uint8_t high = rom()->data()[room_size_address + 1];
81 uint8_t bank = rom()->data()[room_size_address + 2];
82
83 // Constructing the long address
84 int long_address = (bank << 16) | (high << 8) | low;
85 std::cout << std::hex << std::setfill('0') << std::setw(6) << long_address
86 << std::endl;
87 room_size_pointer_ = long_address;
88
89 if (long_address == 0x0A8000) {
90 // Blank room disregard in size calculation
91 std::cout << "Size of Room #" << room_id_ << ": 0 bytes" << std::endl;
92 room_size_ = 0;
93 } else {
94 // use the long address to calculate the size of the room
95 // we will use the room_id_ to calculate the next room's address
96 // and subtract the two to get the size of the room
97
98 int next_room_address = 0xF8000 + ((room_id_ + 1) * 3);
99
100 std::cout << "Next Room Address: " << std::hex << next_room_address
101 << std::endl;
102
103 // Reading bytes for long address construction
104 uint8_t next_low = rom()->data()[next_room_address];
105 uint8_t next_high = rom()->data()[next_room_address + 1];
106 uint8_t next_bank = rom()->data()[next_room_address + 2];
107
108 // Constructing the long address
109 int next_long_address = (next_bank << 16) | (next_high << 8) | next_low;
110
111 std::cout << std::hex << std::setfill('0') << std::setw(6)
112 << next_long_address << std::endl;
113
114 // Calculate the size of the room
115 int room_size = next_long_address - long_address;
117 std::cout << "Size of Room #" << room_id_ << ": " << std::dec << room_size
118 << " bytes" << std::endl;
119 }
120 } catch (const std::exception &e) {
121 std::cout << "Error: " << e.what() << std::endl;
122 }
123}
124
126 auto rom_data = rom()->vector();
127 int header_pointer = SnesToPc(kRoomHeaderPointer);
128
130
131 int address = (rom()->data()[kRoomHeaderPointerBank] << 16) +
132 (rom()->data()[(header_pointer + 1) + (room_id_ * 2)] << 8) +
133 rom()->data()[(header_pointer) + (room_id_ * 2)];
134
135 int hpos = SnesToPc(address);
136 hpos++;
137 uint8_t b = rom_data[hpos];
138
139 layer2_mode_ = (b >> 5);
140 layer_merging_ = kLayerMergeTypeList[(b & 0x0C) >> 2];
141
142 is_dark_ = (b & 0x01) == 0x01;
143 hpos++;
144
145 palette_ = rom_data[hpos];
146 hpos++;
147
148 background_tileset_ = rom_data[hpos];
149 hpos++;
150
151 sprite_tileset_ = rom_data[hpos];
152 hpos++;
153
154 layer2_behavior_ = rom_data[hpos];
155 hpos++;
156
157 tag1_ = (TagKey)rom_data[hpos];
158 hpos++;
159
160 tag2_ = (TagKey)rom_data[hpos];
161 hpos++;
162
163 b = rom_data[hpos];
164
165 pits_.target_layer = (uint8_t)(b & 0x03);
166 stair1_.target_layer = (uint8_t)((b >> 2) & 0x03);
167 stair2_.target_layer = (uint8_t)((b >> 4) & 0x03);
168 stair3_.target_layer = (uint8_t)((b >> 6) & 0x03);
169 hpos++;
170 stair4_.target_layer = (uint8_t)(rom_data[hpos] & 0x03);
171 hpos++;
172
173 pits_.target = rom_data[hpos];
174 hpos++;
175 stair1_.target = rom_data[hpos];
176 hpos++;
177 stair2_.target = rom_data[hpos];
178 hpos++;
179 stair3_.target = rom_data[hpos];
180 hpos++;
181 stair4_.target = rom_data[hpos];
182 hpos++;
183
184 // Load room objects
185 int object_pointer = SnesToPc(room_object_pointer);
186 int room_address = object_pointer + (room_id_ * 3);
187 int objects_location = SnesToPc(room_address);
188
189 // Load sprites
190 // int spr_ptr = 0x040000 | rooms_sprite_pointer;
191 // int sprite_address =
192 // SnesToPc(dungeon_spr_ptrs | spr_ptr + (room_id_ * 2));
193}
194
195void Room::LoadRoomGraphics(uint8_t entrance_blockset) {
196 const auto &main_gfx = rom()->main_blockset_ids;
197 const auto &room_gfx = rom()->room_blockset_ids;
198 const auto &sprite_gfx = rom()->spriteset_ids;
199 current_gfx16_.reserve(0x4000);
200
201 for (int i = 0; i < 8; i++) {
202 blocks_[i] = main_gfx[blockset][i];
203 if (i >= 6 && i <= 6) {
204 // 3-6
205 if (entrance_blockset != 0xFF) {
206 if (room_gfx[entrance_blockset][i - 3] != 0) {
207 blocks_[i] = room_gfx[entrance_blockset][i - 3];
208 }
209 }
210 }
211 }
212
213 blocks_[8] = 115 + 0; // Static Sprites Blocksets (fairy,pot,ect...)
214 blocks_[9] = 115 + 10;
215 blocks_[10] = 115 + 6;
216 blocks_[11] = 115 + 7;
217 for (int i = 0; i < 4; i++) {
218 blocks_[12 + i] = (uint8_t)(sprite_gfx[spriteset + 64][i] + 115);
219 } // 12-16 sprites
220}
221
222constexpr int kGfxBufferOffset = 92 * 2048;
223constexpr int kGfxBufferStride = 512;
224constexpr int kGfxBufferAnimatedFrameOffset = 7 * 2048;
226constexpr int kGfxBufferRoomOffset = 2048;
227constexpr int kGfxBufferRoomSpriteOffset = 512;
228constexpr int kGfxBufferRoomSpriteStride = 2048;
230
232 auto gfx_buffer_data = rom()->graphics_buffer();
233
234 // Copy room graphics to buffer
235 int sheet_pos = 0;
236 for (int i = 0; i < 16; i++) {
237 int data = 0;
238 int block_offset = blocks_[i] * kGfxBufferRoomOffset;
239 while (data < kGfxBufferRoomOffset) {
240 uint8_t map_byte = gfx_buffer_data[data + block_offset];
241 if (i < 4) {
243 }
244
245 current_gfx16_[data + sheet_pos] = map_byte;
246 data++;
247 }
248
249 sheet_pos += kGfxBufferRoomOffset;
250 }
251
253}
254
256 int gfx_ptr = SnesToPc(rom()->version_constants().kGfxAnimatedPointer);
257
258 auto gfx_buffer_data = rom()->graphics_buffer();
259 auto rom_data = rom()->vector();
260 int data = 0;
261 while (data < 512) {
262 uint8_t map_byte =
263 gfx_buffer_data[data + (92 * 2048) + (512 * animated_frame_)];
264 current_gfx16_[data + (7 * 2048)] = map_byte;
265
266 map_byte =
267 gfx_buffer_data[data +
268 (rom_data[gfx_ptr + background_tileset_] * 2048) +
269 (512 * animated_frame_)];
270 current_gfx16_[data + (7 * 2048) - 512] = map_byte;
271 data++;
272 }
273}
274
276 auto rom_data = rom()->vector();
277 int object_pointer = (rom_data[room_object_pointer + 2] << 16) +
278 (rom_data[room_object_pointer + 1] << 8) +
279 (rom_data[room_object_pointer]);
280 object_pointer = SnesToPc(object_pointer);
281 int room_address = object_pointer + (room_id_ * 3);
282
283 int tile_address = (rom_data[room_address + 2] << 16) +
284 (rom_data[room_address + 1] << 8) + rom_data[room_address];
285
286 int objects_location = SnesToPc(tile_address);
287
288 if (objects_location == 0x52CA2) {
289 std::cout << "Room ID : " << room_id_ << std::endl;
290 }
291
292 if (is_floor_) {
293 floor1_graphics_ = static_cast<uint8_t>(rom_data[objects_location] & 0x0F);
295 static_cast<uint8_t>((rom_data[objects_location] >> 4) & 0x0F);
296 }
297
298 layout = static_cast<uint8_t>((rom_data[objects_location + 1] >> 2) & 0x07);
299
300 LoadChests();
301
302 z3_staircases_.clear();
303 int nbr_of_staircase = 0;
304
305 int pos = objects_location + 2;
306 uint8_t b1 = 0;
307 uint8_t b2 = 0;
308 uint8_t b3 = 0;
309 uint8_t posX = 0;
310 uint8_t posY = 0;
311 uint8_t sizeX = 0;
312 uint8_t sizeY = 0;
313 uint8_t sizeXY = 0;
314 short oid = 0;
315 int layer = 0;
316 bool door = false;
317 bool end_read = false;
318 while (!end_read) {
319 b1 = rom_data[pos];
320 b2 = rom_data[pos + 1];
321
322 if (b1 == 0xFF && b2 == 0xFF) {
323 pos += 2; // We jump to layer2
324 layer++;
325 door = false;
326 if (layer == 3) {
327 break;
328 }
329 continue;
330 }
331
332 if (b1 == 0xF0 && b2 == 0xFF) {
333 pos += 2; // We jump to layer2
334 door = true;
335 continue;
336 }
337
338 b3 = rom_data[pos + 2];
339 if (door) {
340 pos += 2;
341 } else {
342 pos += 3;
343 }
344
345 if (!door) {
346 if (b3 >= 0xF8) {
347 oid = static_cast<short>((b3 << 4) |
348 0x80 + (((b2 & 0x03) << 2) + ((b1 & 0x03))));
349 posX = static_cast<uint8_t>((b1 & 0xFC) >> 2);
350 posY = static_cast<uint8_t>((b2 & 0xFC) >> 2);
351 sizeXY = static_cast<uint8_t>((((b1 & 0x03) << 2) + (b2 & 0x03)));
352 } else {
353 oid = b3;
354 posX = static_cast<uint8_t>((b1 & 0xFC) >> 2);
355 posY = static_cast<uint8_t>((b2 & 0xFC) >> 2);
356 sizeX = static_cast<uint8_t>((b1 & 0x03));
357 sizeY = static_cast<uint8_t>((b2 & 0x03));
358 sizeXY = static_cast<uint8_t>(((sizeX << 2) + sizeY));
359 }
360
361 if (b1 >= 0xFC) {
362 oid = static_cast<short>((b3 & 0x3F) + 0x100);
363 posX = static_cast<uint8_t>(((b2 & 0xF0) >> 4) + ((b1 & 0x3) << 4));
364 posY = static_cast<uint8_t>(((b2 & 0x0F) << 2) + ((b3 & 0xC0) >> 6));
365 sizeXY = 0;
366 }
367
368 RoomObject r(oid, posX, posY, sizeXY, static_cast<uint8_t>(layer));
369 tile_objects_.push_back(r);
370
371 for (short stair : stairsObjects) {
372 if (stair == oid) {
373 if (nbr_of_staircase < 4) {
374 tile_objects_.back().set_options(ObjectOption::Stairs |
375 tile_objects_.back().options());
376 z3_staircases_.push_back(staircase(
377 posX, posY,
378 absl::StrCat("To ", staircase_rooms_[nbr_of_staircase])
379 .data()));
380 nbr_of_staircase++;
381 } else {
382 tile_objects_.back().set_options(ObjectOption::Stairs |
383 tile_objects_.back().options());
384 z3_staircases_.push_back(staircase(posX, posY, "To ???"));
385 }
386 }
387 }
388
389 if (oid == 0xF99) {
390 if (chests_in_room_.size() > 0) {
391 tile_objects_.back().set_options(ObjectOption::Chest |
392 tile_objects_.back().options());
393 // chest_list_.push_back(
394 // z3_chest(posX, posY, chests_in_room_.front().itemIn, false));
395 chests_in_room_.erase(chests_in_room_.begin());
396 }
397 } else if (oid == 0xFB1) {
398 if (chests_in_room_.size() > 0) {
399 tile_objects_.back().set_options(ObjectOption::Chest |
400 tile_objects_.back().options());
401 // chest_list_.push_back(
402 // z3_chest(posX + 1, posY, chests_in_room_.front().item_in,
403 // true));
404 chests_in_room_.erase(chests_in_room_.begin());
405 }
406 }
407 } else {
408 // tile_objects_.push_back(z3_object_door(static_cast<short>((b2 << 8) +
409 // b1),
410 // 0, 0, 0,
411 // static_cast<uint8_t>(layer)));
412 }
413 }
414}
415
417 auto rom_data = rom()->vector();
418 int sprite_pointer = (0x04 << 16) +
419 (rom_data[rooms_sprite_pointer + 1] << 8) +
420 (rom_data[rooms_sprite_pointer]);
421 int sprite_address_snes =
422 (0x09 << 16) + (rom_data[sprite_pointer + (room_id_ * 2) + 1] << 8) +
423 rom_data[sprite_pointer + (room_id_ * 2)];
424
425 int sprite_address = SnesToPc(sprite_address_snes);
426 bool sortsprites = rom_data[sprite_address] == 1;
427 sprite_address += 1;
428
429 while (true) {
430 uint8_t b1 = rom_data[sprite_address];
431 uint8_t b2 = rom_data[sprite_address + 1];
432 uint8_t b3 = rom_data[sprite_address + 2];
433
434 if (b1 == 0xFF) {
435 break;
436 }
437
438 sprites_.emplace_back(b3, (b2 & 0x1F), (b1 & 0x1F),
439 ((b2 & 0xE0) >> 5) + ((b1 & 0x60) >> 2),
440 (b1 & 0x80) >> 7);
441
442 if (sprites_.size() > 1) {
443 Sprite &spr = sprites_.back();
444 Sprite &prevSprite = sprites_[sprites_.size() - 2];
445
446 if (spr.id() == 0xE4 && spr.x() == 0x00 && spr.y() == 0x1E &&
447 spr.layer() == 1 && spr.subtype() == 0x18) {
448 prevSprite.set_key_drop(1);
449 sprites_.pop_back();
450 }
451
452 if (spr.id() == 0xE4 && spr.x() == 0x00 && spr.y() == 0x1D &&
453 spr.layer() == 1 && spr.subtype() == 0x18) {
454 prevSprite.set_key_drop(2);
455 sprites_.pop_back();
456 }
457 }
458
459 sprite_address += 3;
460 }
461}
462
464 auto rom_data = rom()->vector();
465 uint32_t cpos = SnesToPc((rom_data[chests_data_pointer1 + 2] << 16) +
466 (rom_data[chests_data_pointer1 + 1] << 8) +
467 (rom_data[chests_data_pointer1]));
468 size_t clength = (rom_data[chests_length_pointer + 1] << 8) +
469 (rom_data[chests_length_pointer]);
470
471 for (int i = 0; i < clength; i++) {
472 if ((((rom_data[cpos + (i * 3) + 1] << 8) + (rom_data[cpos + (i * 3)])) &
473 0x7FFF) == room_id_) {
474 // There's a chest in that room !
475 bool big = false;
476 if ((((rom_data[cpos + (i * 3) + 1] << 8) + (rom_data[cpos + (i * 3)])) &
477 0x8000) == 0x8000) {
478 big = true;
479 }
480
481 chests_in_room_.emplace_back(
482 chest_data(rom_data[cpos + (i * 3) + 2], big));
483 }
484 }
485}
486
487} // namespace zelda3
488} // namespace yaze
auto rom()
Definition rom.h:383
destination pits_
Definition room.h:195
std::vector< RoomObject > tile_objects_
Definition room.h:183
EffectKey effect_
Definition room.h:190
uint8_t palette_
Definition room.h:171
uint8_t staircase_plane_[4]
Definition room.h:165
void LoadChests()
Definition room.cc:463
std::vector< zelda3::Sprite > sprites_
Definition room.h:184
std::vector< uint8_t > current_gfx16_
Definition room.h:154
void CopyRoomGraphicsToBuffer()
Definition room.cc:231
destination stair2_
Definition room.h:197
void LoadRoomGraphics(uint8_t entrance_blockset=0xFF)
Definition room.cc:195
uint8_t layer2_behavior_
Definition room.h:170
uint8_t layer2_mode_
Definition room.h:174
uint8_t holewarp
Definition room.h:145
destination stair4_
Definition room.h:199
void CalculateRoomSize()
Definition room.cc:59
int animated_frame_
Definition room.h:163
uint8_t blockset
Definition room.h:141
void LoadHeader()
Definition room.cc:18
uint8_t layout
Definition room.h:144
uint8_t sprite_tileset_
Definition room.h:169
uint16_t message_id_
Definition room.h:149
uint8_t staircase_rooms_[4]
Definition room.h:166
std::array< uint8_t, 16 > blocks_
Definition room.h:179
void LoadRoomFromROM()
Definition room.cc:125
auto room_size() const
Definition room.h:137
uint8_t floor2_graphics_
Definition room.h:173
background2 bg2_
Definition room.h:194
uint8_t floor1_graphics_
Definition room.h:172
void LoadObjects()
Definition room.cc:275
uint8_t spriteset
Definition room.h:142
int64_t room_size_pointer_
Definition room.h:177
destination stair3_
Definition room.h:198
uint8_t palette
Definition room.h:143
void LoadAnimatedGraphics()
Definition room.cc:255
std::vector< chest_data > chests_in_room_
Definition room.h:186
LayerMergeType layer_merging_
Definition room.h:188
std::vector< staircase > z3_staircases_
Definition room.h:185
void LoadSprites()
Definition room.cc:416
destination stair1_
Definition room.h:196
uint8_t background_tileset_
Definition room.h:168
uint64_t room_size_
Definition room.h:176
CollisionKey collision_
Definition room.h:189
A class for managing sprites in the overworld and underworld.
Definition sprite.h:279
auto id() const
Definition sprite.h:338
auto layer() const
Definition sprite.h:349
auto set_key_drop(int key)
Definition sprite.h:357
auto subtype() const
Definition sprite.h:350
auto y() const
Definition sprite.h:341
auto x() const
Definition sprite.h:340
struct chest_data chest_data
struct staircase staircase
background2
Definition dungeon.h:17
Zelda 3 specific classes and functions.
constexpr int kGfxBufferAnimatedFrameStride
Definition room.cc:225
constexpr int kGfxBufferAnimatedFrameOffset
Definition room.cc:224
constexpr int chests_length_pointer
Definition room.h:46
constexpr int chests_data_pointer1
Definition room.h:47
constexpr int kGfxBufferRoomOffset
Definition room.cc:226
constexpr int rooms_sprite_pointer
Definition room.h:42
constexpr int kGfxBufferRoomSpriteOffset
Definition room.cc:227
constexpr int messages_id_dungeon
Definition room.h:49
constexpr int kGfxBufferRoomSpriteStride
Definition room.cc:228
constexpr uint16_t stairsObjects[]
Definition room.h:82
constexpr int kRoomHeaderPointer
Definition room.h:43
constexpr int kRoomHeaderPointerBank
Definition room.h:44
constexpr int kGfxBufferStride
Definition room.cc:223
constexpr int room_object_pointer
Definition room.h:37
constexpr int kGfxBufferRoomSpriteLastLineOffset
Definition room.cc:229
constexpr int kGfxBufferOffset
Definition room.cc:222
Main namespace for the application.
Definition controller.cc:18
uint32_t SnesToPc(uint32_t addr) noexcept
Definition rom.h:328