386 lines
11 KiB
C++
386 lines
11 KiB
C++
#include "overworld.h"
|
|
|
|
#include "app/gfx/snes_tile.h"
|
|
#include "app/rom.h"
|
|
|
|
namespace yaze {
|
|
namespace app {
|
|
namespace zelda3 {
|
|
|
|
namespace {
|
|
|
|
uint GetOwMapGfxHighPtr(const uchar *rom, int index) {
|
|
int map_high_ptr = core::compressedAllMap32PointersHigh;
|
|
int p1 = (rom[(map_high_ptr) + 2 + (3 * index)] << 16) +
|
|
(rom[(map_high_ptr) + 1 + (3 * index)] << 8) +
|
|
(rom[(map_high_ptr + (3 * index))]);
|
|
return core::SnesToPc(p1);
|
|
}
|
|
|
|
uint GetOwMapGfxLowPtr(const uchar *rom, int index) {
|
|
int map_low_ptr = core::compressedAllMap32PointersLow;
|
|
int p2 = (rom[(map_low_ptr) + 2 + (3 * index)] << 16) +
|
|
(rom[(map_low_ptr) + 1 + (3 * index)] << 8) +
|
|
(rom[(map_low_ptr + (3 * index))]);
|
|
return core::SnesToPc(p2);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
absl::Status Overworld::Load(ROM &rom) {
|
|
rom_ = rom;
|
|
|
|
AssembleMap32Tiles();
|
|
AssembleMap16Tiles();
|
|
RETURN_IF_ERROR(DecompressAllMapTiles())
|
|
|
|
for (int map_index = 0; map_index < core::kNumOverworldMaps; ++map_index)
|
|
overworld_maps_.emplace_back(map_index, rom_, tiles16);
|
|
|
|
FetchLargeMaps();
|
|
LoadEntrances();
|
|
LoadSprites();
|
|
|
|
auto size = tiles16.size();
|
|
for (int i = 0; i < core::kNumOverworldMaps; ++i) {
|
|
if (i < 64) {
|
|
RETURN_IF_ERROR(overworld_maps_[i].BuildMap(
|
|
size, game_state_, 0, map_parent_, map_tiles_.light_world))
|
|
} else if (i < 0x80 && i >= 0x40) {
|
|
RETURN_IF_ERROR(overworld_maps_[i].BuildMap(
|
|
size, game_state_, 1, map_parent_, map_tiles_.dark_world))
|
|
} else {
|
|
RETURN_IF_ERROR(overworld_maps_[i].BuildMap(
|
|
size, game_state_, 2, map_parent_, map_tiles_.special_world))
|
|
}
|
|
}
|
|
|
|
is_loaded_ = true;
|
|
return absl::OkStatus();
|
|
}
|
|
|
|
ushort Overworld::GenerateTile32(int i, int k, int dimension) {
|
|
return (ushort)(rom_[map32address[dimension] + k + (i)] +
|
|
(((rom_[map32address[dimension] + (i) + (k <= 1 ? 4 : 5)] >>
|
|
(k % 2 == 0 ? 4 : 0)) &
|
|
0x0F) *
|
|
256));
|
|
}
|
|
|
|
void Overworld::AssembleMap32Tiles() {
|
|
for (int i = 0; i < 0x33F0; i += 6) {
|
|
for (int k = 0; k < 4; k++) {
|
|
tiles32.push_back(gfx::Tile32(
|
|
/*top-left=*/GenerateTile32(i, k, (int)Dimension::map32TilesTL),
|
|
/*top-right=*/GenerateTile32(i, k, (int)Dimension::map32TilesTR),
|
|
/*bottom-left=*/GenerateTile32(i, k, (int)Dimension::map32TilesBL),
|
|
/*bottom-right=*/GenerateTile32(i, k, (int)Dimension::map32TilesBR)));
|
|
}
|
|
}
|
|
map_tiles_.light_world.resize(kTile32Num);
|
|
map_tiles_.dark_world.resize(kTile32Num);
|
|
map_tiles_.special_world.resize(kTile32Num);
|
|
for (int i = 0; i < kTile32Num; i++) {
|
|
map_tiles_.light_world[i].resize(kTile32Num);
|
|
map_tiles_.dark_world[i].resize(kTile32Num);
|
|
map_tiles_.special_world[i].resize(kTile32Num);
|
|
}
|
|
}
|
|
|
|
void Overworld::AssembleMap16Tiles() {
|
|
int tpos = core::map16Tiles;
|
|
for (int i = 0; i < 4096; i += 1) {
|
|
auto t0 = gfx::GetTilesInfo((rom_.toint16(tpos)));
|
|
tpos += 2;
|
|
auto t1 = gfx::GetTilesInfo((rom_.toint16(tpos)));
|
|
tpos += 2;
|
|
auto t2 = gfx::GetTilesInfo((rom_.toint16(tpos)));
|
|
tpos += 2;
|
|
auto t3 = gfx::GetTilesInfo((rom_.toint16(tpos)));
|
|
tpos += 2;
|
|
tiles16.emplace_back(t0, t1, t2, t3);
|
|
}
|
|
}
|
|
|
|
void Overworld::AssignWorldTiles(int x, int y, int sx, int sy, int tpos,
|
|
OWBlockset &world) {
|
|
int position_x1 = (x * 2) + (sx * 32);
|
|
int position_y1 = (y * 2) + (sy * 32);
|
|
int position_x2 = (x * 2) + 1 + (sx * 32);
|
|
int position_y2 = (y * 2) + 1 + (sy * 32);
|
|
world[position_x1][position_y1] = tiles32[tpos].tile0_;
|
|
world[position_x2][position_y1] = tiles32[tpos].tile1_;
|
|
world[position_x1][position_y2] = tiles32[tpos].tile2_;
|
|
world[position_x2][position_y2] = tiles32[tpos].tile3_;
|
|
}
|
|
|
|
void Overworld::OrganizeMapTiles(Bytes &bytes, Bytes &bytes2, int i, int sx,
|
|
int sy, int &ttpos) {
|
|
for (int y = 0; y < 16; y++) {
|
|
for (int x = 0; x < 16; x++) {
|
|
auto tidD = (ushort)((bytes2[ttpos] << 8) + bytes[ttpos]);
|
|
int tpos = tidD;
|
|
if (tpos < tiles32.size()) {
|
|
if (i < 64) {
|
|
AssignWorldTiles(x, y, sx, sy, tpos, map_tiles_.light_world);
|
|
} else if (i < 128 && i >= 64) {
|
|
AssignWorldTiles(x, y, sx, sy, tpos, map_tiles_.dark_world);
|
|
} else {
|
|
AssignWorldTiles(x, y, sx, sy, tpos, map_tiles_.special_world);
|
|
}
|
|
}
|
|
ttpos += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
absl::Status Overworld::DecompressAllMapTiles() {
|
|
int lowest = 0x0FFFFF;
|
|
int highest = 0x0F8000;
|
|
int sx = 0;
|
|
int sy = 0;
|
|
int c = 0;
|
|
for (int i = 0; i < 160; i++) {
|
|
auto p1 = GetOwMapGfxHighPtr(rom_.data(), i);
|
|
auto p2 = GetOwMapGfxLowPtr(rom_.data(), i);
|
|
int ttpos = 0;
|
|
|
|
if (p1 >= highest) {
|
|
highest = p1;
|
|
}
|
|
if (p2 >= highest) {
|
|
highest = p2;
|
|
}
|
|
|
|
if (p1 <= lowest && p1 > 0x0F8000) {
|
|
lowest = p1;
|
|
}
|
|
if (p2 <= lowest && p2 > 0x0F8000) {
|
|
lowest = p2;
|
|
}
|
|
|
|
ASSIGN_OR_RETURN(auto bytes, rom_.DecompressOverworld(p2, 1000))
|
|
ASSIGN_OR_RETURN(auto bytes2, rom_.DecompressOverworld(p1, 1000))
|
|
OrganizeMapTiles(bytes, bytes2, i, sx, sy, ttpos);
|
|
|
|
sx++;
|
|
if (sx >= 8) {
|
|
sy++;
|
|
sx = 0;
|
|
}
|
|
|
|
c++;
|
|
if (c >= 64) {
|
|
sx = 0;
|
|
sy = 0;
|
|
c = 0;
|
|
}
|
|
}
|
|
|
|
std::cout << "MapPointers(lowest) : " << lowest << std::endl;
|
|
std::cout << "MapPointers(highest) : " << highest << std::endl;
|
|
return absl::OkStatus();
|
|
}
|
|
|
|
void Overworld::FetchLargeMaps() {
|
|
for (int i = 128; i < 145; i++) {
|
|
map_parent_[i] = 0;
|
|
}
|
|
|
|
map_parent_[128] = 128;
|
|
map_parent_[129] = 129;
|
|
map_parent_[130] = 129;
|
|
map_parent_[137] = 129;
|
|
map_parent_[138] = 129;
|
|
map_parent_[136] = 136;
|
|
overworld_maps_[136].SetLargeMap(false);
|
|
|
|
bool mapChecked[64];
|
|
for (int i = 0; i < 64; i++) {
|
|
mapChecked[i] = false;
|
|
}
|
|
int xx = 0;
|
|
int yy = 0;
|
|
while (true) {
|
|
int i = xx + (yy * 8);
|
|
if (mapChecked[i] == false) {
|
|
if (overworld_maps_[i].IsLargeMap() == true) {
|
|
mapChecked[i] = true;
|
|
map_parent_[i] = (uchar)i;
|
|
map_parent_[i + 64] = (uchar)(i + 64);
|
|
|
|
mapChecked[i + 1] = true;
|
|
map_parent_[i + 1] = (uchar)i;
|
|
map_parent_[i + 65] = (uchar)(i + 64);
|
|
|
|
mapChecked[i + 8] = true;
|
|
map_parent_[i + 8] = (uchar)i;
|
|
map_parent_[i + 72] = (uchar)(i + 64);
|
|
|
|
mapChecked[i + 9] = true;
|
|
map_parent_[i + 9] = (uchar)i;
|
|
map_parent_[i + 73] = (uchar)(i + 64);
|
|
xx++;
|
|
} else {
|
|
map_parent_[i] = (uchar)i;
|
|
map_parent_[i + 64] = (uchar)(i + 64);
|
|
mapChecked[i] = true;
|
|
}
|
|
}
|
|
|
|
xx++;
|
|
if (xx >= 8) {
|
|
xx = 0;
|
|
yy += 1;
|
|
if (yy >= 8) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Overworld::LoadEntrances() {
|
|
for (int i = 0; i < 129; i++) {
|
|
short mapId = rom_.toint16(core::OWEntranceMap + (i * 2));
|
|
ushort mapPos = rom_.toint16(core::OWEntrancePos + (i * 2));
|
|
uchar entranceId = (rom_[core::OWEntranceEntranceId + i]);
|
|
int p = mapPos >> 1;
|
|
int x = (p % 64);
|
|
int y = (p >> 6);
|
|
bool deleted = false;
|
|
if (mapPos == 0xFFFF) {
|
|
deleted = true;
|
|
}
|
|
all_entrances_.emplace_back(
|
|
(x * 16) + (((mapId % 64) - (((mapId % 64) / 8) * 8)) * 512),
|
|
(y * 16) + (((mapId % 64) / 8) * 512), entranceId, mapId, mapPos,
|
|
deleted);
|
|
}
|
|
|
|
for (int i = 0; i < 0x13; i++) {
|
|
short mapId = (short)((rom_[core::OWHoleArea + (i * 2) + 1] << 8) +
|
|
(rom_[core::OWHoleArea + (i * 2)]));
|
|
short mapPos = (short)((rom_[core::OWHolePos + (i * 2) + 1] << 8) +
|
|
(rom_[core::OWHolePos + (i * 2)]));
|
|
uchar entranceId = (rom_[core::OWHoleEntrance + i]);
|
|
int p = (mapPos + 0x400) >> 1;
|
|
int x = (p % 64);
|
|
int y = (p >> 6);
|
|
all_holes_.emplace_back(
|
|
(x * 16) + (((mapId % 64) - (((mapId % 64) / 8) * 8)) * 512),
|
|
(y * 16) + (((mapId % 64) / 8) * 512), entranceId, mapId,
|
|
(ushort)(mapPos + 0x400), true);
|
|
}
|
|
}
|
|
|
|
void Overworld::LoadSprites() {
|
|
// LW[0] = RainState 0 to 63 there's no data for DW
|
|
// LW[1] = ZeldaState 0 to 128 ; Contains LW and DW <128 or 144 wtf
|
|
// LW[2] = AgahState 0 to ?? ;Contains data for LW and DW
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
all_sprites_.emplace_back(std::vector<Sprite>());
|
|
}
|
|
|
|
// Console.WriteLine(((core::overworldSpritesBegining & 0xFFFF) + (09 <<
|
|
// 16)).ToString("X6"));
|
|
for (int i = 0; i < 64; i++) {
|
|
if (map_parent_[i] == i) {
|
|
// Beginning Sprites
|
|
int ptrPos = core::overworldSpritesBegining + (i * 2);
|
|
int spriteAddress = core::SnesToPc((0x09 << 0x10) + rom_.toint16(ptrPos));
|
|
while (true) {
|
|
uchar b1 = rom_[spriteAddress];
|
|
uchar b2 = rom_[spriteAddress + 1];
|
|
uchar b3 = rom_[spriteAddress + 2];
|
|
if (b1 == 0xFF) {
|
|
break;
|
|
}
|
|
|
|
int mapY = (i / 8);
|
|
int mapX = (i % 8);
|
|
|
|
int realX = ((b2 & 0x3F) * 16) + mapX * 512;
|
|
int realY = ((b1 & 0x3F) * 16) + mapY * 512;
|
|
|
|
all_sprites_[0].emplace_back(overworld_maps_[i].AreaGraphics(),
|
|
(uchar)i, b3, (uchar)(b2 & 0x3F),
|
|
(uchar)(b1 & 0x3F), realX, realY);
|
|
|
|
spriteAddress += 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 144; i++) {
|
|
if (map_parent_[i] == i) {
|
|
// Zelda Saved Sprites
|
|
int ptrPos = core::overworldSpritesZelda + (i * 2);
|
|
int spriteAddress = core::SnesToPc((0x09 << 0x10) + rom_.toint16(ptrPos));
|
|
while (true) {
|
|
uchar b1 = rom_[spriteAddress];
|
|
uchar b2 = rom_[spriteAddress + 1];
|
|
uchar b3 = rom_[spriteAddress + 2];
|
|
if (b1 == 0xFF) {
|
|
break;
|
|
}
|
|
|
|
int editorMapIndex = i;
|
|
if (editorMapIndex >= 128) {
|
|
editorMapIndex = i - 128;
|
|
} else if (editorMapIndex >= 64) {
|
|
editorMapIndex = i - 64;
|
|
}
|
|
|
|
int mapY = (editorMapIndex / 8);
|
|
int mapX = (editorMapIndex % 8);
|
|
|
|
int realX = ((b2 & 0x3F) * 16) + mapX * 512;
|
|
int realY = ((b1 & 0x3F) * 16) + mapY * 512;
|
|
|
|
all_sprites_[1].emplace_back(overworld_maps_[i].AreaGraphics(),
|
|
(uchar)i, b3, (uchar)(b2 & 0x3F),
|
|
(uchar)(b1 & 0x3F), realX, realY);
|
|
|
|
spriteAddress += 3;
|
|
}
|
|
}
|
|
|
|
// Agahnim Dead Sprites
|
|
if (map_parent_[i] == i) {
|
|
int ptrPos = core::overworldSpritesAgahnim + (i * 2);
|
|
int spriteAddress = core::SnesToPc((0x09 << 0x10) + rom_.toint16(ptrPos));
|
|
while (true) {
|
|
uchar b1 = rom_[spriteAddress];
|
|
uchar b2 = rom_[spriteAddress + 1];
|
|
uchar b3 = rom_[spriteAddress + 2];
|
|
if (b1 == 0xFF) {
|
|
break;
|
|
}
|
|
|
|
int editorMapIndex = i;
|
|
if (editorMapIndex >= 128) {
|
|
editorMapIndex = i - 128;
|
|
} else if (editorMapIndex >= 64) {
|
|
editorMapIndex = i - 64;
|
|
}
|
|
|
|
int mapY = (editorMapIndex / 8);
|
|
int mapX = (editorMapIndex % 8);
|
|
|
|
int realX = ((b2 & 0x3F) * 16) + mapX * 512;
|
|
int realY = ((b1 & 0x3F) * 16) + mapY * 512;
|
|
|
|
all_sprites_[2].emplace_back(overworld_maps_[i].AreaGraphics(),
|
|
(uchar)i, b3, (uchar)(b2 & 0x3F),
|
|
(uchar)(b1 & 0x3F), realX, realY);
|
|
|
|
spriteAddress += 3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace zelda3
|
|
} // namespace app
|
|
} // namespace yaze
|