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