Files
yaze/src/zelda3/overworld/overworld_item.h
scawful 1e39df88a3 refactor: enhance overworld entity properties and version handling
- Updated `UpdateMapProperties` methods across various entities (entrances, exits, items, sprites) to include an optional context parameter for improved area size detection.
- Introduced `OverworldVersionHelper` for centralized ROM version detection and feature gating, replacing scattered inline checks.
- Refactored coordinate calculations to utilize normalized map IDs, ensuring consistency and preventing data corruption.
- Enhanced exit properties to sync player positions and calculate scroll/camera values based on the overworld context.

Benefits:
- Streamlines entity property updates and improves compatibility with different ROM versions.
- Reduces code duplication and enhances maintainability by centralizing version checks.
- Ensures accurate coordinate calculations for overworld entities, improving overall functionality.
2025-10-18 00:09:09 -04:00

168 lines
5.1 KiB
C++

#ifndef YAZE_APP_ZELDA3_OVERWORLD_ITEM_H_
#define YAZE_APP_ZELDA3_OVERWORLD_ITEM_H_
#include <algorithm>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "app/rom.h"
#include "zelda3/common.h"
namespace yaze {
namespace zelda3 {
// Forward declaration of OverworldMap class
class OverworldMap;
constexpr int kNumOverworldMapItemPointers = 0x80;
constexpr int kOverworldItemsPointers = 0xDC2F9;
constexpr int kOverworldItemsAddress = 0xDC8B9; // 1BC2F9
constexpr int kOverworldItemsBank = 0xDC8BF;
constexpr int kOverworldItemsEndData = 0xDC89C; // 0DC89E
constexpr int kOverworldBombDoorItemLocationsNew = 0x012644;
constexpr int kOverworldItemsPointersNew = 0x012784;
constexpr int kOverworldItemsStartDataNew = 0x0DC2F9;
constexpr int overworldItemsPointers = 0x0DC2F9;
constexpr int overworldItemsAddress = 0x0DC8B9; // 1BC2F9
constexpr int overworldItemsAddressBank = 0x0DC8BF;
constexpr int overworldItemsEndData = 0x0DC89C; // 0DC89E
constexpr int overworldBombDoorItemLocationsNew = 0x012644;
constexpr int overworldItemsPointersNew = 0x012784;
constexpr int overworldItemsStartDataNew = 0x0DC2F9;
class OverworldItem : public GameEntity {
public:
OverworldItem() = default;
OverworldItem(uint8_t id, uint16_t room_map_id, int x, int y, bool bg2)
: bg2_(bg2), id_(id), room_map_id_(room_map_id) {
x_ = x;
y_ = y;
map_id_ = room_map_id; // Store original map_id
entity_id_ = id;
entity_type_ = kItem;
// Use normalized map_id for coordinate calculations
uint8_t normalized_map_id = room_map_id % 0x40;
int map_x = normalized_map_id % 8;
int map_y = normalized_map_id / 8;
game_x_ = static_cast<uint8_t>(std::abs(x - (map_x * 512)) / 16);
game_y_ = static_cast<uint8_t>(std::abs(y - (map_y * 512)) / 16);
}
void UpdateMapProperties(uint16_t room_map_id, const void* context = nullptr) override {
(void)context; // Not used by items currently
room_map_id_ = room_map_id;
// Use normalized map_id for calculations (don't corrupt stored value)
uint8_t normalized_map_id = room_map_id % 0x40;
int map_x = normalized_map_id % 8;
int map_y = normalized_map_id / 8;
// Update game coordinates from world coordinates
game_x_ = static_cast<uint8_t>(std::abs(x_ - (map_x * 512)) / 16);
game_y_ = static_cast<uint8_t>(std::abs(y_ - (map_y * 512)) / 16);
}
bool bg2_ = false;
uint8_t id_;
uint8_t game_x_;
uint8_t game_y_;
uint16_t room_map_id_;
int unique_id = 0;
bool deleted = false;
};
inline bool CompareOverworldItems(const std::vector<OverworldItem>& items1,
const std::vector<OverworldItem>& items2) {
if (items1.size() != items2.size()) {
return false;
}
const auto is_same_item = [](const OverworldItem& a, const OverworldItem& b) {
return a.x_ == b.x_ && a.y_ == b.y_ && a.id_ == b.id_;
};
return std::all_of(items1.begin(), items1.end(),
[&](const OverworldItem& it) {
return std::any_of(items2.begin(), items2.end(),
[&](const OverworldItem& other) {
return is_same_item(it, other);
});
});
}
inline bool CompareItemsArrays(std::vector<OverworldItem> item_array1,
std::vector<OverworldItem> item_array2) {
if (item_array1.size() != item_array2.size()) {
return false;
}
bool match;
for (size_t i = 0; i < item_array1.size(); i++) {
match = false;
for (size_t j = 0; j < item_array2.size(); j++) {
// Check all sprite in 2nd array if one match
if (item_array1[i].x_ == item_array2[j].x_ &&
item_array1[i].y_ == item_array2[j].y_ &&
item_array1[i].id_ == item_array2[j].id_) {
match = true;
break;
}
}
if (!match) {
return false;
}
}
return true;
}
absl::StatusOr<std::vector<OverworldItem>> LoadItems(Rom* rom, std::vector<OverworldMap>& overworld_maps);
absl::Status SaveItems(Rom* rom, const std::vector<OverworldItem>& items);
const std::vector<std::string> kSecretItemNames = {
"Nothing", // 0
"Green Rupee", // 1
"Rock hoarder", // 2
"Bee", // 3
"Health pack", // 4
"Bomb", // 5
"Heart ", // 6
"Blue Rupee", // 7
"Key", // 8
"Arrow", // 9
"Bomb", // 10
"Heart", // 11
"Magic", // 12
"Full Magic", // 13
"Cucco", // 14
"Green Soldier", // 15
"Bush Stal", // 16
"Blue Soldier", // 17
"Landmine", // 18
"Heart", // 19
"Fairy", // 20
"Heart", // 21
"Nothing ", // 22
"Hole", // 23
"Warp", // 24
"Staircase", // 25
"Bombable", // 26
"Switch" // 27
};
} // namespace zelda3
} // namespace yaze
#endif // YAZE_APP_ZELDA3_OVERWORLD_ITEM_H_