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