refactor overworld exit to flat functions

This commit is contained in:
scawful
2025-10-17 09:41:10 -04:00
parent 520047b748
commit a662619541
5 changed files with 122 additions and 104 deletions

View File

@@ -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<OverworldExit> 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();
}

View File

@@ -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,

View File

@@ -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 <cstdint>
#include <vector>
#include "zelda3/overworld/overworld_map.h"
namespace yaze::zelda3 {
absl::StatusOr<std::vector<OverworldExit>> LoadExits(Rom* rom) {
const int NumberOfOverworldExits = 0x4F;
std::vector<OverworldExit> 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<OverworldExit>& 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

View File

@@ -4,10 +4,10 @@
#include <cstdint>
#include <iostream>
#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<std::vector<OverworldExit>> LoadExits(Rom* rom);
absl::Status SaveExits(Rom* rom, const std::vector<OverworldExit>& exits);
} // namespace yaze::zelda3
#endif // YAZE_APP_ZELDA3_OVERWORLD_EXIT_H_

View File

@@ -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