diff --git a/src/app/rom.h b/src/app/rom.h index b2788562..f4f508bd 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -162,6 +162,35 @@ class ROM : public core::ExperimentFlags { return absl::InvalidArgumentError("Invalid write argument type"); } + template + absl::Status ReadTransaction(T& var, int address, Args&&... args) { + absl::Status status = ReadHelper(var, address); + if (!status.ok()) { + return status; + } + + if constexpr (sizeof...(args) > 0) { + status = ReadTransaction(std::forward(args)...); + } + + return status; + } + + template + absl::Status ReadHelper(T& var, int address) { + if constexpr (std::is_same_v) { + ASSIGN_OR_RETURN(auto result, ReadByte(address)); + var = result; + } else if constexpr (std::is_same_v) { + ASSIGN_OR_RETURN(auto result, ReadWord(address)); + var = result; + } else if constexpr (std::is_same_v>) { + ASSIGN_OR_RETURN(auto result, ReadByteVector(address, var.size())); + var = result; + } + return absl::OkStatus(); + } + /** * Loads 2bpp graphics from ROM data. * diff --git a/src/app/zelda3/overworld.cc b/src/app/zelda3/overworld.cc index c2ff4f33..20f6edb0 100644 --- a/src/app/zelda3/overworld.cc +++ b/src/app/zelda3/overworld.cc @@ -917,31 +917,20 @@ absl::Status Overworld::SaveEntrances() { absl::Status Overworld::SaveExits() { for (int i = 0; i < 0x4F; i++) { - RETURN_IF_ERROR( - rom()->WriteShort(OWExitRoomId + (i * 2), all_exits_[i].room_id_)) - RETURN_IF_ERROR(rom()->WriteByte(OWExitMapId + i, all_exits_[i].map_id_)) - RETURN_IF_ERROR( - rom()->WriteShort(OWExitVram + (i * 2), all_exits_[i].map_pos_)) - RETURN_IF_ERROR( - rom()->WriteShort(OWExitYScroll + (i * 2), all_exits_[i].y_scroll_)) - RETURN_IF_ERROR( - rom()->WriteShort(OWExitXScroll + (i * 2), all_exits_[i].x_scroll_)) - RETURN_IF_ERROR( - rom()->WriteShort(OWExitYPlayer + (i * 2), all_exits_[i].y_player_)) - RETURN_IF_ERROR( - rom()->WriteShort(OWExitXPlayer + (i * 2), all_exits_[i].x_player_)) - RETURN_IF_ERROR( - rom()->WriteShort(OWExitYCamera + (i * 2), all_exits_[i].y_camera_)) - RETURN_IF_ERROR( - rom()->WriteShort(OWExitXCamera + (i * 2), all_exits_[i].x_camera_)) - RETURN_IF_ERROR( - rom()->WriteByte(OWExitUnk1 + i, all_exits_[i].scroll_mod_y_)) - RETURN_IF_ERROR( - rom()->WriteByte(OWExitUnk2 + i, all_exits_[i].scroll_mod_x_)) - RETURN_IF_ERROR(rom()->WriteShort(OWExitDoorType1 + (i * 2), - all_exits_[i].door_type_1_)) - RETURN_IF_ERROR(rom()->WriteShort(OWExitDoorType2 + (i * 2), - all_exits_[i].door_type_2_)) + RETURN_IF_ERROR(rom()->RunTransaction( + WriteAction{OWExitRoomId + (i * 2), all_exits_[i].room_id_}, + WriteAction{OWExitMapId + i, all_exits_[i].map_id_}, + WriteAction{OWExitVram + (i * 2), all_exits_[i].map_pos_}, + WriteAction{OWExitYScroll + (i * 2), all_exits_[i].y_scroll_}, + WriteAction{OWExitXScroll + (i * 2), all_exits_[i].x_scroll_}, + WriteAction{OWExitYPlayer + (i * 2), all_exits_[i].y_player_}, + WriteAction{OWExitXPlayer + (i * 2), all_exits_[i].x_player_}, + WriteAction{OWExitYCamera + (i * 2), all_exits_[i].y_camera_}, + WriteAction{OWExitXCamera + (i * 2), all_exits_[i].x_camera_}, + WriteAction{OWExitUnk1 + i, all_exits_[i].scroll_mod_y_}, + WriteAction{OWExitUnk2 + i, all_exits_[i].scroll_mod_x_}, + WriteAction{OWExitDoorType1 + (i * 2), all_exits_[i].door_type_1_}, + WriteAction{OWExitDoorType2 + (i * 2), all_exits_[i].door_type_2_})) } return absl::OkStatus(); @@ -952,35 +941,39 @@ void Overworld::LoadExits() { std::vector exits; for (int i = 0; i < NumberOfOverworldExits; i++) { auto rom_data = rom()->data(); - ushort exit_room_id = (ushort)((rom_data[OWExitRoomId + (i * 2) + 1] << 8) + - rom_data[OWExitRoomId + (i * 2)]); - ushort exit_map_id = rom_data[OWExitMapId + i]; - ushort exit_vram = (ushort)((rom_data[OWExitVram + (i * 2) + 1] << 8) + - rom_data[OWExitVram + (i * 2)]); - ushort exit_y_scroll = - (ushort)((rom_data[OWExitYScroll + (i * 2) + 1] << 8) + - rom_data[OWExitYScroll + (i * 2)]); - ushort exit_x_scroll = - (ushort)((rom_data[OWExitXScroll + (i * 2) + 1] << 8) + - rom_data[OWExitXScroll + (i * 2)]); + + uint16_t exit_room_id; + uint16_t exit_map_id; + uint16_t exit_vram; + uint16_t exit_y_scroll; + uint16_t exit_x_scroll; + uint16_t exit_y_player; + uint16_t exit_x_player; + uint16_t exit_y_camera; + uint16_t exit_x_camera; + uint16_t exit_scroll_mod_y; + uint16_t exit_scroll_mod_x; + uint16_t exit_door_type_1; + uint16_t exit_door_type_2; + rom()->ReadTransaction( + exit_room_id, (OWExitRoomId + (i * 2)), + exit_map_id, OWExitMapId + i, + exit_vram, OWExitVram + (i * 2), + exit_y_scroll, OWExitYScroll + (i * 2), + exit_x_scroll, OWExitXScroll + (i * 2), + exit_y_player, OWExitYPlayer + (i * 2), + exit_x_player, OWExitXPlayer + (i * 2), + exit_y_camera, OWExitYCamera + (i * 2), + exit_x_camera, OWExitXCamera + (i * 2), + exit_scroll_mod_y, OWExitUnk1 + i, + exit_scroll_mod_x, OWExitUnk2 + i, + exit_door_type_1, OWExitDoorType1 + (i * 2), + exit_door_type_2, OWExitDoorType2 + (i * 2)); + ushort py = (ushort)((rom_data[OWExitYPlayer + (i * 2) + 1] << 8) + rom_data[OWExitYPlayer + (i * 2)]); ushort px = (ushort)((rom_data[OWExitXPlayer + (i * 2) + 1] << 8) + rom_data[OWExitXPlayer + (i * 2)]); - ushort exit_y_camera = - (ushort)((rom_data[OWExitYCamera + (i * 2) + 1] << 8) + - rom_data[OWExitYCamera + (i * 2)]); - ushort exit_x_camera = - (ushort)((rom_data[OWExitXCamera + (i * 2) + 1] << 8) + - rom_data[OWExitXCamera + (i * 2)]); - ushort exit_scroll_mod_y = rom_data[OWExitUnk1 + i]; - ushort exit_scroll_mod_x = rom_data[OWExitUnk2 + i]; - ushort exit_door_type_1 = - (ushort)((rom_data[OWExitDoorType1 + (i * 2) + 1] << 8) + - rom_data[OWExitDoorType1 + (i * 2)]); - ushort exit_door_type_2 = - (ushort)((rom_data[OWExitDoorType2 + (i * 2) + 1] << 8) + - rom_data[OWExitDoorType2 + (i * 2)]); OverworldExit exit(exit_room_id, exit_map_id, exit_vram, exit_y_scroll, exit_x_scroll, py, px, exit_y_camera, exit_x_camera, exit_scroll_mod_y, exit_scroll_mod_x, exit_door_type_1, @@ -1065,6 +1058,46 @@ void Overworld::LoadSpritesFromMap(int spriteStart, int spriteCount, } } +absl::Status Overworld::SaveMapProperties() { + for (int i = 0; i < 64; i++) { + RETURN_IF_ERROR(rom()->RunTransaction( + WriteAction{mapGfx + i, overworld_maps_[i].area_graphics()}, + WriteAction{overworldSpriteset + i, + overworld_maps_[i].sprite_graphics(0)}, + WriteAction{overworldSpriteset + 64 + i, + overworld_maps_[i].sprite_graphics(1)}, + WriteAction{overworldSpriteset + 128 + i, + overworld_maps_[i].sprite_graphics(2)}, + WriteAction{overworldMapPalette + i, overworld_maps_[i].area_palette()}, + WriteAction{overworldSpritePalette + i, + overworld_maps_[i].sprite_palette(0)}, + WriteAction{overworldSpritePalette + 64 + i, + overworld_maps_[i].sprite_palette(1)}, + WriteAction{overworldSpritePalette + 128 + i, + overworld_maps_[i].sprite_palette(2)})) + } + + for (int i = 64; i < 128; i++) { + RETURN_IF_ERROR(rom()->RunTransaction( + WriteAction{mapGfx + i, overworld_maps_[i].area_graphics()}, + WriteAction{overworldSpriteset + i, + overworld_maps_[i].sprite_graphics(0)}, + WriteAction{overworldSpriteset + 64 + i, + overworld_maps_[i].sprite_graphics(1)}, + WriteAction{overworldSpriteset + 128 + i, + overworld_maps_[i].sprite_graphics(2)}, + WriteAction{overworldMapPalette + i, overworld_maps_[i].area_palette()}, + WriteAction{overworldSpritePalette + 64 + i, + overworld_maps_[i].sprite_palette(0)}, + WriteAction{overworldSpritePalette + 128 + i, + overworld_maps_[i].sprite_palette(1)}, + WriteAction{overworldSpritePalette + 192 + i, + overworld_maps_[i].sprite_palette(2)})) + } + + return absl::OkStatus(); +} + absl::Status Overworld::LoadPrototype(ROM &rom, const std::string &tilemap_filename) { rom_ = rom; diff --git a/src/app/zelda3/overworld.h b/src/app/zelda3/overworld.h index 6cb2d402..6d864212 100644 --- a/src/app/zelda3/overworld.h +++ b/src/app/zelda3/overworld.h @@ -37,16 +37,6 @@ constexpr int OWExitUnk1 = 0x162C9; constexpr int OWExitUnk2 = 0x16318; constexpr int OWExitDoorType1 = 0x16367; constexpr int OWExitDoorType2 = 0x16405; -constexpr int OWEntranceMap = 0xDB96F; -constexpr int OWEntrancePos = 0xDBA71; -constexpr int OWEntranceEntranceId = 0xDBB73; -constexpr int OWHolePos = 0xDB800; //(0x13 entries, 2 bytes each) modified(less - // 0x400) map16 coordinates for each hole -constexpr int OWHoleArea = - 0xDB826; //(0x13 entries, 2 bytes each) corresponding - // area numbers for each hole -constexpr int OWHoleEntrance = - 0xDB84C; //(0x13 entries, 1 byte each) corresponding entrance numbers constexpr int OWExitMapIdWhirlpool = 0x16AE5; // JP = ;016849 constexpr int OWExitVramWhirlpool = 0x16B07; // JP = ;01686B @@ -74,7 +64,6 @@ class OverworldExit { uchar scroll_mod_x_; ushort door_type_1_; ushort door_type_2_; - ushort room_id_; ushort map_pos_; // Position in the vram uchar entrance_id_; @@ -83,44 +72,46 @@ class OverworldExit { short map_id_; bool is_hole_ = false; bool deleted = false; + bool is_automatic_ = false; - OverworldExit(ushort roomID, uchar mapID, ushort vramLocation, ushort yScroll, - ushort xScroll, ushort playerY, ushort playerX, ushort cameraY, - ushort cameraX, uchar scrollModY, uchar scrollModX, - ushort doorType1, ushort doorType2) - : x_(playerX), - y_(playerY), - map_pos_(vramLocation), + OverworldExit(ushort room_id, uchar map_id, ushort vram_location, + ushort y_scroll, ushort x_scroll, ushort player_y, + ushort player_x, ushort camera_y, ushort camera_x, + uchar scroll_mod_y, uchar scroll_mod_x, ushort door_type_1, + ushort door_type_2) + : x_(player_x), + y_(player_y), + map_pos_(vram_location), entrance_id_(0), area_x_(0), area_y_(0), - map_id_(mapID), + map_id_(map_id), is_hole_(false), - room_id_(roomID), - y_scroll_(yScroll), - x_scroll_(xScroll), - y_player_(playerY), - x_player_(playerX), - y_camera_(cameraY), - x_camera_(cameraX), - scroll_mod_y_(scrollModY), - scroll_mod_x_(scrollModX), - door_type_1_(doorType1), - door_type_2_(doorType2) { + room_id_(room_id), + y_scroll_(y_scroll), + x_scroll_(x_scroll), + y_player_(player_y), + x_player_(player_x), + y_camera_(camera_y), + x_camera_(camera_x), + scroll_mod_y_(scroll_mod_y), + scroll_mod_x_(scroll_mod_x), + door_type_1_(door_type_1), + door_type_2_(door_type_2) { int mapX = (map_id_ - ((map_id_ / 8) * 8)); int mapY = (map_id_ / 8); area_x_ = (uchar)((std::abs(x_ - (mapX * 512)) / 16)); area_y_ = (uchar)((std::abs(y_ - (mapY * 512)) / 16)); - if (doorType1 != 0) { - int p = (doorType1 & 0x7FFF) >> 1; + if (door_type_1 != 0) { + int p = (door_type_1 & 0x7FFF) >> 1; entrance_id_ = (uchar)(p % 64); area_y_ = (uchar)(p >> 6); } - if (doorType2 != 0) { - int p = (doorType2 & 0x7FFF) >> 1; + if (door_type_2 != 0) { + int p = (door_type_2 & 0x7FFF) >> 1; entrance_id_ = (uchar)(p % 64); area_y_ = (uchar)(p >> 6); } @@ -138,85 +129,100 @@ class OverworldExit { map_pos_ = (ushort)((((area_y_) << 6) | (area_x_ & 0x3F)) << 1); } - // void updateMapStuff(uchar mapID, Overworld overworld) { - // map_id_ = mapID; + // Overworld overworld + void UpdateMapProperties(uchar map_id) { + map_id_ = map_id; - // int large = 256; - // int mapid = mapID; + int large = 256; + int mapid = map_id; - // if (mapID < 128) { - // large = overworld.AllMaps[mapID].LargeMap ? 768 : 256; - // if (overworld.AllMaps[mapID].ParentID != mapID) { - // mapid = overworld.AllMaps[mapID].ParentID; - // } - // } + if (map_id < 128) { + // large = overworld.overworld_map(map_id)->IsLargeMap() ? 768 : 256; + // if (overworld.overworld_map(map_id)->Parent() != map_id) { + // mapid = overworld.overworld_map(map_id)->Parent(); + // } + } - // int mapX = mapID - ((mapID / 8) * 8); - // int mapY = mapID / 8; + int mapX = map_id - ((map_id / 8) * 8); + int mapY = map_id / 8; - // area_x_ = (uchar)((std::abs(x_ - (mapX * 512)) / 16)); - // area_y_ = (uchar)((std::abs(y_ - (mapY * 512)) / 16)); + area_x_ = (uchar)((std::abs(x_ - (mapX * 512)) / 16)); + area_y_ = (uchar)((std::abs(y_ - (mapY * 512)) / 16)); - // if (mapID >= 64) { - // mapID -= 64; - // } + if (map_id >= 64) { + map_id -= 64; + } - // int mapx = (mapID & 7) << 9; - // int mapy = (mapID & 56) << 6; + int mapx = (map_id & 7) << 9; + int mapy = (map_id & 56) << 6; - // if (IsAutomatic) { - // x_ = x_ - 120; - // y_ = y_ - 80; + if (is_automatic_) { + x_ = x_ - 120; + y_ = y_ - 80; - // if (x_ < mapx) { - // x_ = mapx; - // } + if (x_ < mapx) { + x_ = mapx; + } - // if (y_ < mapy) { - // y_ = mapy; - // } + if (y_ < mapy) { + y_ = mapy; + } - // if (x_ > mapx + large) { - // x_ = mapx + large; - // } + if (x_ > mapx + large) { + x_ = mapx + large; + } - // if (y_ > mapy + large + 32) { - // y_ = mapy + large + 32; - // } + if (y_ > mapy + large + 32) { + y_ = mapy + large + 32; + } - // cameraX = playerX + 0x07; - // cameraY = playerY + 0x1F; + x_camera_ = x_player_ + 0x07; + y_camera_ = y_player_ + 0x1F; - // if (cameraX < mapx + 127) { - // cameraX = mapx + 127; - // } + if (x_camera_ < mapx + 127) { + x_camera_ = mapx + 127; + } - // if (cameraY < mapy + 111) { - // cameraY = mapy + 111; - // } + if (y_camera_ < mapy + 111) { + y_camera_ = mapy + 111; + } - // if (cameraX > mapx + 127 + large) { - // cameraX = mapx + 127 + large; - // } + if (x_camera_ > mapx + 127 + large) { + x_camera_ = mapx + 127 + large; + } - // if (cameraY > mapy + 143 + large) { - // cameraY = mapy + 143 + large; - // } - // } + if (y_camera_ > mapy + 143 + large) { + y_camera_ = mapy + 143 + large; + } + } - // short vramXScroll = (short)(x_ - mapx); - // short vramYScroll = (short)(y_ - mapy); + short vram_x_scroll = (short)(x_ - mapx); + short vram_y_scroll = (short)(y_ - mapy); - // map_pos_ = - // (ushort)(((vramYScroll & 0xFFF0) << 3) | ((vramXScroll & 0xFFF0) >> - // 3)); + map_pos_ = (ushort)(((vram_y_scroll & 0xFFF0) << 3) | + ((vram_x_scroll & 0xFFF0) >> 3)); - // std::cout << "Exit: " << room_id_ << " MapId: " << std::hex << mapid - // << " X: " << static_cast(area_x_) - // << " Y: " << static_cast(area_y_) << std::endl; - // } + std::cout << "Exit: " << room_id_ << " MapId: " << std::hex << mapid + << " X: " << static_cast(area_x_) + << " Y: " << static_cast(area_y_) << std::endl; + } }; +constexpr int OWEntranceMap = 0xDB96F; +constexpr int OWEntrancePos = 0xDBA71; +constexpr int OWEntranceEntranceId = 0xDBB73; + +// (0x13 entries, 2 bytes each) modified(less 0x400) +// map16 coordinates for each hole +constexpr int OWHolePos = 0xDB800; + +// (0x13 entries, 2 bytes each) corresponding +// area numbers for each hole +constexpr int OWHoleArea = 0xDB826; + +//(0x13 entries, 1 byte each) corresponding entrance numbers +constexpr int OWHoleEntrance = 0xDB84C; + class OverworldEntrance { public: int x_; @@ -249,7 +255,7 @@ class OverworldEntrance { is_hole_); } - void UpdateMapStuff(short map_id) { + void UpdateMapProperties(short map_id) { map_id_ = map_id; if (map_id_ >= 64) { @@ -352,6 +358,8 @@ class Overworld : public SharedROM, public core::ExperimentFlags { absl::Status SaveMap16Tiles(); absl::Status SaveMap32Tiles(); + absl::Status SaveMapProperties(); + auto overworld_maps() const { return overworld_maps_; } auto overworld_map(int i) const { return &overworld_maps_[i]; } auto mutable_overworld_map(int i) { return &overworld_maps_[i]; } @@ -376,7 +384,7 @@ class Overworld : public SharedROM, public core::ExperimentFlags { auto is_loaded() const { return is_loaded_; } void SetCurrentMap(int i) { current_map_ = i; } - auto MapTiles() const { return map_tiles_; } + auto map_tiles() const { return map_tiles_; } auto mutable_map_tiles() { return &map_tiles_; } absl::Status LoadPrototype(ROM &rom_, const std::string &tilemap_filename); diff --git a/src/app/zelda3/overworld_map.h b/src/app/zelda3/overworld_map.h index dddf2e38..7164436b 100644 --- a/src/app/zelda3/overworld_map.h +++ b/src/app/zelda3/overworld_map.h @@ -44,12 +44,16 @@ class OverworldMap { auto sprite_graphics(int i) const { return sprite_graphics_[i]; } auto sprite_palette(int i) const { return sprite_palette_[i]; } auto message_id() const { return message_id_; } + auto area_music(int i) const { return area_music_[i]; } + auto static_graphics(int i) const { return static_graphics_[i]; } auto mutable_area_graphics() { return &area_graphics_; } auto mutable_area_palette() { return &area_palette_; } auto mutable_sprite_graphics(int i) { return &sprite_graphics_[i]; } auto mutable_sprite_palette(int i) { return &sprite_palette_[i]; } auto mutable_message_id() { return &message_id_; } + auto mutable_area_music(int i) { return &area_music_[i]; } + auto mutable_static_graphics(int i) { return &static_graphics_[i]; } private: void LoadAreaInfo(); @@ -71,25 +75,25 @@ class OverworldMap { absl::Status BuildTiles16Gfx(int count); absl::Status BuildBitmap(OWBlockset& world_blockset); + bool built_ = false; + bool large_map_ = false; + bool initialized_ = false; + int parent_ = 0; int index_ = 0; int world_ = 0; - uint8_t message_id_ = 0; + int game_state_ = 0; + int world_index_ = 0; + + uint16_t message_id_ = 0; uint8_t area_graphics_ = 0; uint8_t area_palette_ = 0; - int game_state_ = 0; - - int world_index_ = 0; uchar sprite_graphics_[3]; uchar sprite_palette_[3]; uchar area_music_[4]; uchar static_graphics_[16]; - bool initialized_ = false; - bool built_ = false; - bool large_map_ = false; - ROM rom_; Bytes all_gfx_; Bytes current_blockset_; @@ -98,8 +102,6 @@ class OverworldMap { OWMapTiles map_tiles_; gfx::SNESPalette current_palette_; - // std::vector sprite_graphics_; - std::vector tiles16_; };