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