From a662619541f33fcac66bca7843554a8aefb65005 Mon Sep 17 00:00:00 2001 From: scawful Date: Fri, 17 Oct 2025 09:41:10 -0400 Subject: [PATCH] refactor overworld exit to flat functions --- src/zelda3/overworld/overworld.cc | 101 +--------------------- src/zelda3/overworld/overworld.h | 1 - src/zelda3/overworld/overworld_exit.cc | 113 +++++++++++++++++++++++++ src/zelda3/overworld/overworld_exit.h | 10 ++- src/zelda3/zelda3_library.cmake | 1 + 5 files changed, 122 insertions(+), 104 deletions(-) create mode 100644 src/zelda3/overworld/overworld_exit.cc diff --git a/src/zelda3/overworld/overworld.cc b/src/zelda3/overworld/overworld.cc index 65cf6675..baabf355 100644 --- a/src/zelda3/overworld/overworld.cc +++ b/src/zelda3/overworld/overworld.cc @@ -89,7 +89,7 @@ absl::Status Overworld::Load(Rom* rom) { { gfx::ScopedTimer exits_timer("LoadExits"); - RETURN_IF_ERROR(LoadExits()); + ASSIGN_OR_RETURN(all_exits_, LoadExits(rom_)); } { @@ -687,50 +687,6 @@ void Overworld::LoadTileTypes() { } } -absl::Status Overworld::LoadExits() { - const int NumberOfOverworldExits = 0x4F; - std::vector exits; - for (int i = 0; i < NumberOfOverworldExits; i++) { - auto rom_data = rom()->data(); - - 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; - RETURN_IF_ERROR(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))); - - uint16_t py = (uint16_t)((rom_data[OWExitYPlayer + (i * 2) + 1] << 8) + - rom_data[OWExitYPlayer + (i * 2)]); - uint16_t px = (uint16_t)((rom_data[OWExitXPlayer + (i * 2) + 1] << 8) + - rom_data[OWExitXPlayer + (i * 2)]); - - exits.emplace_back(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, - exit_door_type_2, (px & py) == 0xFFFF); - } - all_exits_ = exits; - return absl::OkStatus(); -} - absl::Status Overworld::LoadItems() { // Version 0x03 of the OW ASM added item support for the SW. uint8_t asm_version = (*rom_)[zelda3::OverworldCustomASMHasBeenApplied]; @@ -2519,60 +2475,7 @@ absl::Status Overworld::SaveEntrances() { } absl::Status Overworld::SaveExits() { - util::logf("Saving Exits"); - - // ASM version 0x03 added SW support and the exit leading to Zora's Domain specifically - // needs to be updated because its camera values are incorrect. - // We only update it if it was a vanilla ROM though because we don't know if the - // user has already adjusted it or not. - uint8_t asm_version = (*rom_)[OverworldCustomASMHasBeenApplied]; - if (asm_version == 0x00) { - // Apply special fix for Zora's Domain exit (index 0x4D) - // TODO: Implement SpecialUpdatePosition for OverworldExit - // if (all_exits_.size() > 0x4D) { - // all_exits_[0x4D].SpecialUpdatePosition(); - // } - } - - for (int i = 0; i < kNumOverworldExits; 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_)); - - if (all_exits_[i].room_id_ == 0x0180) { - RETURN_IF_ERROR(rom()->WriteByte(OWExitDoorPosition + 0, - all_exits_[i].map_id_ & 0xFF)); - } else if (all_exits_[i].room_id_ == 0x0181) { - RETURN_IF_ERROR(rom()->WriteByte(OWExitDoorPosition + 2, - all_exits_[i].map_id_ & 0xFF)); - } else if (all_exits_[i].room_id_ == 0x0182) { - RETURN_IF_ERROR(rom()->WriteByte(OWExitDoorPosition + 4, - all_exits_[i].map_id_ & 0xFF)); - } - } - + RETURN_IF_ERROR(::yaze::zelda3::SaveExits(rom_, all_exits_)); return absl::OkStatus(); } diff --git a/src/zelda3/overworld/overworld.h b/src/zelda3/overworld/overworld.h index 85f154e5..32ea7210 100644 --- a/src/zelda3/overworld/overworld.h +++ b/src/zelda3/overworld/overworld.h @@ -139,7 +139,6 @@ class Overworld { absl::Status LoadOverworldMaps(); void LoadTileTypes(); - absl::Status LoadExits(); absl::Status LoadItems(); absl::Status LoadSprites(); absl::Status LoadSpritesFromMap(int sprite_start, int sprite_count, diff --git a/src/zelda3/overworld/overworld_exit.cc b/src/zelda3/overworld/overworld_exit.cc new file mode 100644 index 00000000..3908b597 --- /dev/null +++ b/src/zelda3/overworld/overworld_exit.cc @@ -0,0 +1,113 @@ +#include "zelda3/overworld/overworld_exit.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "app/rom.h" +#include "util/macro.h" +#include +#include +#include "zelda3/overworld/overworld_map.h" + +namespace yaze::zelda3 { + +absl::StatusOr> LoadExits(Rom* rom) { + const int NumberOfOverworldExits = 0x4F; + std::vector exits; + for (int i = 0; i < NumberOfOverworldExits; i++) { + auto rom_data = rom->data(); + + 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; + RETURN_IF_ERROR(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))); + + uint16_t py = (uint16_t)((rom_data[OWExitYPlayer + (i * 2) + 1] << 8) + + rom_data[OWExitYPlayer + (i * 2)]); + uint16_t px = (uint16_t)((rom_data[OWExitXPlayer + (i * 2) + 1] << 8) + + rom_data[OWExitXPlayer + (i * 2)]); + + exits.emplace_back(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, + exit_door_type_2, (px & py) == 0xFFFF); + } + return exits; +} + + +absl::Status SaveExits(Rom* rom, const std::vector& exits) { + + // ASM version 0x03 added SW support and the exit leading to Zora's Domain specifically + // needs to be updated because its camera values are incorrect. + // We only update it if it was a vanilla ROM though because we don't know if the + // user has already adjusted it or not. + uint8_t asm_version = (*rom)[OverworldCustomASMHasBeenApplied]; + if (asm_version == 0x00) { + // Apply special fix for Zora's Domain exit (index 0x4D) + // TODO: Implement SpecialUpdatePosition for OverworldExit + // if (all_exits_.size() > 0x4D) { + // all_exits_[0x4D].SpecialUpdatePosition(); + // } + } + + for (int i = 0; i < kNumOverworldExits; i++) { + RETURN_IF_ERROR( + rom->WriteShort(OWExitRoomId + (i * 2), exits[i].room_id_)); + RETURN_IF_ERROR(rom->WriteByte(OWExitMapId + i, exits[i].map_id_)); + RETURN_IF_ERROR( + rom->WriteShort(OWExitVram + (i * 2), exits[i].map_pos_)); + RETURN_IF_ERROR( + rom->WriteShort(OWExitYScroll + (i * 2), exits[i].y_scroll_)); + RETURN_IF_ERROR( + rom->WriteShort(OWExitXScroll + (i * 2), exits[i].x_scroll_)); + RETURN_IF_ERROR( + rom->WriteShort(OWExitYPlayer + (i * 2), exits[i].y_player_)); + RETURN_IF_ERROR( + rom->WriteShort(OWExitXPlayer + (i * 2), exits[i].x_player_)); + RETURN_IF_ERROR( + rom->WriteShort(OWExitYCamera + (i * 2), exits[i].y_camera_)); + RETURN_IF_ERROR( + rom->WriteShort(OWExitXCamera + (i * 2), exits[i].x_camera_)); + RETURN_IF_ERROR( + rom->WriteByte(OWExitUnk1 + i, exits[i].scroll_mod_y_)); + RETURN_IF_ERROR( + rom->WriteByte(OWExitUnk2 + i, exits[i].scroll_mod_x_)); + RETURN_IF_ERROR(rom->WriteShort(OWExitDoorType1 + (i * 2), + exits[i].door_type_1_)); + RETURN_IF_ERROR(rom->WriteShort(OWExitDoorType2 + (i * 2), + exits[i].door_type_2_)); + + if (exits[i].room_id_ == 0x0180) { + RETURN_IF_ERROR(rom->WriteByte(OWExitDoorPosition + 0, + exits[i].map_id_ & 0xFF)); + } else if (exits[i].room_id_ == 0x0181) { + RETURN_IF_ERROR(rom->WriteByte(OWExitDoorPosition + 2, + exits[i].map_id_ & 0xFF)); + } else if (exits[i].room_id_ == 0x0182) { + RETURN_IF_ERROR(rom->WriteByte(OWExitDoorPosition + 4, + exits[i].map_id_ & 0xFF)); + } + } + + return absl::OkStatus(); +} + +} // namespace yaze::zelda3 \ No newline at end of file diff --git a/src/zelda3/overworld/overworld_exit.h b/src/zelda3/overworld/overworld_exit.h index 7616f749..19caeacd 100644 --- a/src/zelda3/overworld/overworld_exit.h +++ b/src/zelda3/overworld/overworld_exit.h @@ -4,10 +4,10 @@ #include #include +#include "app/rom.h" #include "zelda3/common.h" -namespace yaze { -namespace zelda3 { +namespace yaze::zelda3 { constexpr int kNumOverworldExits = 0x4F; constexpr int OWExitRoomId = 0x15D8A; // 0x15E07 Credits sequences @@ -208,7 +208,9 @@ class OverworldExit : public GameEntity { } }; -} // namespace zelda3 -} // namespace yaze +absl::StatusOr> LoadExits(Rom* rom); +absl::Status SaveExits(Rom* rom, const std::vector& exits); + +} // namespace yaze::zelda3 #endif // YAZE_APP_ZELDA3_OVERWORLD_EXIT_H_ diff --git a/src/zelda3/zelda3_library.cmake b/src/zelda3/zelda3_library.cmake index 2dc06b2e..1ce43321 100644 --- a/src/zelda3/zelda3_library.cmake +++ b/src/zelda3/zelda3_library.cmake @@ -11,6 +11,7 @@ set( zelda3/overworld/overworld.cc zelda3/overworld/overworld_map.cc zelda3/overworld/overworld_entrance.cc + zelda3/overworld/overworld_exit.cc zelda3/palette_constants.cc zelda3/screen/dungeon_map.cc zelda3/screen/inventory.cc