Add zelda3::overworld namespace
This commit is contained in:
1575
src/app/zelda3/overworld/overworld.cc
Normal file
1575
src/app/zelda3/overworld/overworld.cc
Normal file
File diff suppressed because it is too large
Load Diff
638
src/app/zelda3/overworld/overworld.h
Normal file
638
src/app/zelda3/overworld/overworld.h
Normal file
@@ -0,0 +1,638 @@
|
||||
#ifndef YAZE_APP_DATA_OVERWORLD_H
|
||||
#define YAZE_APP_DATA_OVERWORLD_H
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "app/core/common.h"
|
||||
#include "app/core/constants.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/common.h"
|
||||
#include "app/zelda3/overworld/overworld_map.h"
|
||||
#include "app/zelda3/sprite/sprite.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace zelda3 {
|
||||
|
||||
/**
|
||||
* @namespace yaze::app::zelda3::overworld
|
||||
* @brief Represents the Overworld data.
|
||||
*/
|
||||
namespace overworld {
|
||||
|
||||
// List of secret item names
|
||||
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
|
||||
};
|
||||
|
||||
constexpr int overworldItemsPointers = 0xDC2F9;
|
||||
constexpr int kOverworldItemsAddress = 0xDC8B9; // 1BC2F9
|
||||
constexpr int overworldItemsBank = 0xDC8BF;
|
||||
constexpr int overworldItemsEndData = 0xDC89C; // 0DC89E
|
||||
|
||||
class OverworldItem : public OverworldEntity {
|
||||
public:
|
||||
bool bg2 = false;
|
||||
uint8_t game_x;
|
||||
uint8_t game_y;
|
||||
uint8_t id;
|
||||
uint16_t room_map_id;
|
||||
int unique_id = 0;
|
||||
bool deleted = false;
|
||||
OverworldItem() = default;
|
||||
|
||||
OverworldItem(uint8_t id, uint16_t room_map_id, int x, int y, bool bg2) {
|
||||
this->id = id;
|
||||
this->x_ = x;
|
||||
this->y_ = y;
|
||||
this->bg2 = bg2;
|
||||
this->room_map_id = room_map_id;
|
||||
this->map_id_ = room_map_id;
|
||||
this->entity_id_ = id;
|
||||
this->type_ = kItem;
|
||||
|
||||
int map_x = room_map_id - ((room_map_id / 8) * 8);
|
||||
int map_y = room_map_id / 8;
|
||||
|
||||
this->game_x = static_cast<uint8_t>(std::abs(x - (map_x * 512)) / 16);
|
||||
this->game_y = static_cast<uint8_t>(std::abs(y - (map_y * 512)) / 16);
|
||||
// this->unique_id = ROM.unique_item_id++;
|
||||
}
|
||||
|
||||
void UpdateMapProperties(int16_t room_map_id) override {
|
||||
this->room_map_id = static_cast<uint16_t>(room_map_id);
|
||||
|
||||
if (room_map_id >= 64) {
|
||||
room_map_id -= 64;
|
||||
}
|
||||
|
||||
int map_x = room_map_id - ((room_map_id / 8) * 8);
|
||||
int map_y = room_map_id / 8;
|
||||
|
||||
this->game_x =
|
||||
static_cast<uint8_t>(std::abs(this->x_ - (map_x * 512)) / 16);
|
||||
this->game_y =
|
||||
static_cast<uint8_t>(std::abs(this->y_ - (map_y * 512)) / 16);
|
||||
|
||||
std::cout << "Item: " << std::hex << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<int>(this->id) << " MapId: " << std::hex
|
||||
<< std::setw(2) << std::setfill('0')
|
||||
<< static_cast<int>(this->room_map_id)
|
||||
<< " X: " << static_cast<int>(this->game_x)
|
||||
<< " Y: " << static_cast<int>(this->game_y) << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr int OWExitRoomId = 0x15D8A; // 0x15E07 Credits sequences
|
||||
// 105C2 Ending maps
|
||||
// 105E2 Sprite Group Table for Ending
|
||||
constexpr int OWExitMapId = 0x15E28;
|
||||
constexpr int OWExitVram = 0x15E77;
|
||||
constexpr int OWExitYScroll = 0x15F15;
|
||||
constexpr int OWExitXScroll = 0x15FB3;
|
||||
constexpr int OWExitYPlayer = 0x16051;
|
||||
constexpr int OWExitXPlayer = 0x160EF;
|
||||
constexpr int OWExitYCamera = 0x1618D;
|
||||
constexpr int OWExitXCamera = 0x1622B;
|
||||
constexpr int OWExitDoorPosition = 0x15724;
|
||||
constexpr int OWExitUnk1 = 0x162C9;
|
||||
constexpr int OWExitUnk2 = 0x16318;
|
||||
constexpr int OWExitDoorType1 = 0x16367;
|
||||
constexpr int OWExitDoorType2 = 0x16405;
|
||||
|
||||
constexpr int OWExitMapIdWhirlpool = 0x16AE5; // JP = ;016849
|
||||
constexpr int OWExitVramWhirlpool = 0x16B07; // JP = ;01686B
|
||||
constexpr int OWExitYScrollWhirlpool = 0x16B29; // JP = ;01688D
|
||||
constexpr int OWExitXScrollWhirlpool = 0x16B4B; // JP = ;016DE7
|
||||
constexpr int OWExitYPlayerWhirlpool = 0x16B6D; // JP = ;016E09
|
||||
constexpr int OWExitXPlayerWhirlpool = 0x16B8F; // JP = ;016E2B
|
||||
constexpr int OWExitYCameraWhirlpool = 0x16BB1; // JP = ;016E4D
|
||||
constexpr int OWExitXCameraWhirlpool = 0x16BD3; // JP = ;016E6F
|
||||
constexpr int OWExitUnk1Whirlpool = 0x16BF5; // JP = ;016E91
|
||||
constexpr int OWExitUnk2Whirlpool = 0x16C17; // JP = ;016EB3
|
||||
constexpr int OWWhirlpoolPosition = 0x16CF8; // JP = ;016F94
|
||||
|
||||
class OverworldExit : public OverworldEntity {
|
||||
public:
|
||||
uint16_t y_scroll_;
|
||||
uint16_t x_scroll_;
|
||||
uchar y_player_;
|
||||
uchar x_player_;
|
||||
uchar y_camera_;
|
||||
uchar x_camera_;
|
||||
uchar scroll_mod_y_;
|
||||
uchar scroll_mod_x_;
|
||||
uint16_t door_type_1_;
|
||||
uint16_t door_type_2_;
|
||||
uint16_t room_id_;
|
||||
uint16_t map_pos_; // Position in the vram
|
||||
uchar entrance_id_;
|
||||
uchar area_x_;
|
||||
uchar area_y_;
|
||||
bool is_hole_ = false;
|
||||
bool deleted_ = false;
|
||||
bool is_automatic_ = false;
|
||||
bool large_map_ = false;
|
||||
|
||||
OverworldExit() = default;
|
||||
OverworldExit(uint16_t room_id, uchar map_id, uint16_t vram_location,
|
||||
uint16_t y_scroll, uint16_t x_scroll, uint16_t player_y,
|
||||
uint16_t player_x, uint16_t camera_y, uint16_t camera_x,
|
||||
uchar scroll_mod_y, uchar scroll_mod_x, uint16_t door_type_1,
|
||||
uint16_t door_type_2, bool deleted = false)
|
||||
: map_pos_(vram_location),
|
||||
entrance_id_(0),
|
||||
area_x_(0),
|
||||
area_y_(0),
|
||||
is_hole_(false),
|
||||
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),
|
||||
deleted_(deleted) {
|
||||
// Initialize entity variables
|
||||
this->x_ = player_x;
|
||||
this->y_ = player_y;
|
||||
this->map_id_ = map_id;
|
||||
this->type_ = kExit;
|
||||
|
||||
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 (door_type_1 != 0) {
|
||||
int p = (door_type_1 & 0x7FFF) >> 1;
|
||||
entrance_id_ = (uchar)(p % 64);
|
||||
area_y_ = (uchar)(p >> 6);
|
||||
}
|
||||
|
||||
if (door_type_2 != 0) {
|
||||
int p = (door_type_2 & 0x7FFF) >> 1;
|
||||
entrance_id_ = (uchar)(p % 64);
|
||||
area_y_ = (uchar)(p >> 6);
|
||||
}
|
||||
|
||||
if (map_id_ >= 64) {
|
||||
map_id_ -= 64;
|
||||
}
|
||||
|
||||
mapX = (map_id_ - ((map_id_ / 8) * 8));
|
||||
mapY = (map_id_ / 8);
|
||||
|
||||
area_x_ = (uchar)((std::abs(x_ - (mapX * 512)) / 16));
|
||||
area_y_ = (uchar)((std::abs(y_ - (mapY * 512)) / 16));
|
||||
|
||||
map_pos_ = (uint16_t)((((area_y_) << 6) | (area_x_ & 0x3F)) << 1);
|
||||
}
|
||||
|
||||
// Overworld overworld
|
||||
void UpdateMapProperties(short map_id) override {
|
||||
map_id_ = map_id;
|
||||
|
||||
int large = 256;
|
||||
int mapid = map_id;
|
||||
|
||||
if (map_id < 128) {
|
||||
large = large_map_ ? 768 : 256;
|
||||
// if (overworld.overworld_map(map_id)->Parent() != map_id) {
|
||||
// mapid = overworld.overworld_map(map_id)->Parent();
|
||||
// }
|
||||
}
|
||||
|
||||
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 (map_id >= 64) {
|
||||
map_id -= 64;
|
||||
}
|
||||
|
||||
int mapx = (map_id & 7) << 9;
|
||||
int mapy = (map_id & 56) << 6;
|
||||
|
||||
if (is_automatic_) {
|
||||
x_ = x_ - 120;
|
||||
y_ = y_ - 80;
|
||||
|
||||
if (x_ < mapx) {
|
||||
x_ = mapx;
|
||||
}
|
||||
|
||||
if (y_ < mapy) {
|
||||
y_ = mapy;
|
||||
}
|
||||
|
||||
if (x_ > mapx + large) {
|
||||
x_ = mapx + large;
|
||||
}
|
||||
|
||||
if (y_ > mapy + large + 32) {
|
||||
y_ = mapy + large + 32;
|
||||
}
|
||||
|
||||
x_camera_ = x_player_ + 0x07;
|
||||
y_camera_ = y_player_ + 0x1F;
|
||||
|
||||
if (x_camera_ < mapx + 127) {
|
||||
x_camera_ = mapx + 127;
|
||||
}
|
||||
|
||||
if (y_camera_ < mapy + 111) {
|
||||
y_camera_ = mapy + 111;
|
||||
}
|
||||
|
||||
if (x_camera_ > mapx + 127 + large) {
|
||||
x_camera_ = mapx + 127 + large;
|
||||
}
|
||||
|
||||
if (y_camera_ > mapy + 143 + large) {
|
||||
y_camera_ = mapy + 143 + large;
|
||||
}
|
||||
}
|
||||
|
||||
short vram_x_scroll = (short)(x_ - mapx);
|
||||
short vram_y_scroll = (short)(y_ - mapy);
|
||||
|
||||
map_pos_ = (uint16_t)(((vram_y_scroll & 0xFFF0) << 3) |
|
||||
((vram_x_scroll & 0xFFF0) >> 3));
|
||||
|
||||
std::cout << "Exit: " << room_id_ << " MapId: " << std::hex << mapid
|
||||
<< " X: " << static_cast<int>(area_x_)
|
||||
<< " Y: " << static_cast<int>(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 OverworldEntity {
|
||||
public:
|
||||
uint16_t map_pos_;
|
||||
uchar entrance_id_;
|
||||
uchar area_x_;
|
||||
uchar area_y_;
|
||||
bool is_hole_ = false;
|
||||
bool deleted = false;
|
||||
|
||||
OverworldEntrance() = default;
|
||||
OverworldEntrance(int x, int y, uchar entrance_id, short map_id,
|
||||
uint16_t map_pos, bool hole)
|
||||
: map_pos_(map_pos), entrance_id_(entrance_id), is_hole_(hole) {
|
||||
x_ = x;
|
||||
y_ = y;
|
||||
map_id_ = map_id;
|
||||
entity_id_ = entrance_id;
|
||||
type_ = kEntrance;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
auto Copy() {
|
||||
return new OverworldEntrance(x_, y_, entrance_id_, map_id_, map_pos_,
|
||||
is_hole_);
|
||||
}
|
||||
|
||||
void UpdateMapProperties(short map_id) override {
|
||||
map_id_ = map_id;
|
||||
|
||||
if (map_id_ >= 64) {
|
||||
map_id_ -= 64;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
map_pos_ = (uint16_t)((((area_y_) << 6) | (area_x_ & 0x3F)) << 1);
|
||||
}
|
||||
};
|
||||
|
||||
constexpr int kCompressedAllMap32PointersHigh = 0x1794D;
|
||||
constexpr int kCompressedAllMap32PointersLow = 0x17B2D;
|
||||
constexpr int overworldgfxGroups = 0x05D97;
|
||||
constexpr int overworldPalGroup1 = 0xDE6C8;
|
||||
constexpr int overworldPalGroup2 = 0xDE86C;
|
||||
constexpr int overworldPalGroup3 = 0xDE604;
|
||||
constexpr int overworldMapPalette = 0x7D1C;
|
||||
constexpr int overworldSpritePalette = 0x7B41;
|
||||
constexpr int overworldMapPaletteGroup = 0x75504;
|
||||
constexpr int overworldSpritePaletteGroup = 0x75580;
|
||||
constexpr int overworldSpriteset = 0x7A41;
|
||||
constexpr int overworldSpecialGFXGroup = 0x16821;
|
||||
constexpr int overworldSpecialPALGroup = 0x16831;
|
||||
constexpr int overworldSpritesBegining = 0x4C881;
|
||||
constexpr int overworldSpritesAgahnim = 0x4CA21;
|
||||
constexpr int overworldSpritesZelda = 0x4C901;
|
||||
|
||||
constexpr int mapGfx = 0x7C9C;
|
||||
constexpr int overlayPointers = 0x77664;
|
||||
constexpr int overlayPointersBank = 0x0E;
|
||||
|
||||
constexpr int overworldTilesType = 0x71459;
|
||||
constexpr int overworldMessages = 0x3F51D;
|
||||
|
||||
constexpr int overworldMusicBegining = 0x14303;
|
||||
constexpr int overworldMusicZelda = 0x14303 + 0x40;
|
||||
constexpr int overworldMusicMasterSword = 0x14303 + 0x80;
|
||||
constexpr int overworldMusicAgahim = 0x14303 + 0xC0;
|
||||
constexpr int overworldMusicDW = 0x14403;
|
||||
constexpr int overworldEntranceAllowedTilesLeft = 0xDB8C1;
|
||||
constexpr int overworldEntranceAllowedTilesRight = 0xDB917;
|
||||
|
||||
// 0x00 = small maps, 0x20 = large maps
|
||||
constexpr int overworldMapSize = 0x12844;
|
||||
|
||||
// 0x01 = small maps, 0x03 = large maps
|
||||
constexpr int overworldMapSizeHighByte = 0x12884;
|
||||
|
||||
// relative to the WORLD + 0x200 per map
|
||||
// large map that are not == parent id = same position as their parent!
|
||||
// eg for X position small maps :
|
||||
// 0000, 0200, 0400, 0600, 0800, 0A00, 0C00, 0E00
|
||||
// all Large map would be :
|
||||
// 0000, 0000, 0400, 0400, 0800, 0800, 0C00, 0C00
|
||||
constexpr int overworldMapParentId = 0x125EC;
|
||||
constexpr int overworldTransitionPositionY = 0x128C4;
|
||||
constexpr int overworldTransitionPositionX = 0x12944;
|
||||
constexpr int overworldScreenSize = 0x1788D;
|
||||
constexpr int OverworldScreenSizeForLoading = 0x4C635;
|
||||
|
||||
// constexpr int OverworldScreenTileMapChangeByScreen = 0x12634;
|
||||
constexpr int OverworldScreenTileMapChangeByScreen1 = 0x12634;
|
||||
constexpr int OverworldScreenTileMapChangeByScreen2 = 0x126B4;
|
||||
constexpr int OverworldScreenTileMapChangeByScreen3 = 0x12734;
|
||||
constexpr int OverworldScreenTileMapChangeByScreen4 = 0x127B4;
|
||||
|
||||
constexpr int OverworldMapDataOverflow = 0x130000;
|
||||
|
||||
constexpr int transition_target_north = 0x13EE2;
|
||||
constexpr int transition_target_west = 0x13F62;
|
||||
constexpr int overworldCustomMosaicASM = 0x1301D0;
|
||||
constexpr int overworldCustomMosaicArray = 0x1301F0;
|
||||
|
||||
constexpr int OverworldCustomASMHasBeenApplied =
|
||||
0x140145; // 1 byte, not 0 if enabled
|
||||
|
||||
constexpr int OverworldCustomAreaSpecificBGPalette =
|
||||
0x140000; // 2 bytes for each overworld area (0x140)
|
||||
constexpr int OverworldCustomAreaSpecificBGEnabled =
|
||||
0x140140; // 1 byte, not 0 if enabled
|
||||
|
||||
constexpr int OverworldCustomMainPaletteArray =
|
||||
0x140160; // 1 byte for each overworld area (0xA0)
|
||||
constexpr int OverworldCustomMainPaletteEnabled =
|
||||
0x140141; // 1 byte, not 0 if enabled
|
||||
|
||||
constexpr int OverworldCustomMosaicArray =
|
||||
0x140200; // 1 byte for each overworld area (0xA0)
|
||||
constexpr int OverworldCustomMosaicEnabled =
|
||||
0x140142; // 1 byte, not 0 if enabled
|
||||
|
||||
constexpr int OverworldCustomAnimatedGFXArray =
|
||||
0x1402A0; // 1 byte for each overworld area (0xA0)
|
||||
constexpr int OverworldCustomAnimatedGFXEnabled =
|
||||
0x140143; // 1 byte, not 0 if enabled
|
||||
|
||||
constexpr int OverworldCustomSubscreenOverlayArray =
|
||||
0x140340; // 2 bytes for each overworld area (0x140)
|
||||
constexpr int OverworldCustomSubscreenOverlayEnabled =
|
||||
0x140144; // 1 byte, not 0 if enabled
|
||||
|
||||
constexpr int kMap16Tiles = 0x78000;
|
||||
constexpr int kNumOverworldMaps = 160;
|
||||
constexpr int Map32PerScreen = 256;
|
||||
constexpr int NumberOfMap16 = 3752; // 4096
|
||||
constexpr int LimitOfMap32 = 8864;
|
||||
constexpr int NumberOfOWSprites = 352;
|
||||
constexpr int NumberOfMap32 = Map32PerScreen * kNumOverworldMaps;
|
||||
|
||||
struct MapData {
|
||||
std::vector<uint8_t> highData;
|
||||
std::vector<uint8_t> lowData;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Represents the full Overworld data, light and dark world.
|
||||
*
|
||||
* This class is responsible for loading and saving the overworld data,
|
||||
* as well as creating the tilesets and tilemaps for the overworld.
|
||||
*/
|
||||
class Overworld : public SharedROM, public core::ExperimentFlags {
|
||||
public:
|
||||
OWBlockset &GetMapTiles(int world_type);
|
||||
absl::Status Load(ROM &rom);
|
||||
absl::Status LoadOverworldMaps();
|
||||
void LoadTileTypes();
|
||||
void LoadEntrances();
|
||||
|
||||
absl::Status LoadExits();
|
||||
absl::Status LoadItems();
|
||||
absl::Status LoadSprites();
|
||||
absl::Status LoadSpritesFromMap(int spriteStart, int spriteCount,
|
||||
int spriteIndex);
|
||||
|
||||
absl::Status Save(ROM &rom);
|
||||
absl::Status SaveOverworldMaps();
|
||||
absl::Status SaveLargeMaps();
|
||||
absl::Status SaveEntrances();
|
||||
absl::Status SaveExits();
|
||||
absl::Status SaveItems();
|
||||
|
||||
absl::Status CreateTile32Tilemap();
|
||||
absl::Status SaveMap16Tiles();
|
||||
absl::Status SaveMap32Tiles();
|
||||
|
||||
absl::Status SaveMapProperties();
|
||||
absl::Status LoadPrototype(ROM &rom_, const std::string &tilemap_filename);
|
||||
|
||||
void Destroy() {
|
||||
for (auto &map : overworld_maps_) {
|
||||
map.Destroy();
|
||||
}
|
||||
overworld_maps_.clear();
|
||||
all_entrances_.clear();
|
||||
all_exits_.clear();
|
||||
all_items_.clear();
|
||||
all_sprites_.clear();
|
||||
is_loaded_ = false;
|
||||
}
|
||||
|
||||
int current_world_ = 0;
|
||||
int GetTileFromPosition(ImVec2 position) const {
|
||||
if (current_world_ == 0) {
|
||||
return map_tiles_.light_world[position.x][position.y];
|
||||
} else if (current_world_ == 1) {
|
||||
return map_tiles_.dark_world[position.x][position.y];
|
||||
} else {
|
||||
return map_tiles_.special_world[position.x][position.y];
|
||||
}
|
||||
}
|
||||
|
||||
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]; }
|
||||
auto exits() const { return &all_exits_; }
|
||||
auto mutable_exits() { return &all_exits_; }
|
||||
std::vector<gfx::Tile16> tiles16() const { return tiles16_; }
|
||||
|
||||
auto Sprites(int state) const { return all_sprites_[state]; }
|
||||
auto mutable_sprites(int state) { return &all_sprites_[state]; }
|
||||
auto current_graphics() const {
|
||||
return overworld_maps_[current_map_].current_graphics();
|
||||
}
|
||||
auto &entrances() { return all_entrances_; }
|
||||
auto mutable_entrances() { return &all_entrances_; }
|
||||
auto &holes() { return all_holes_; }
|
||||
auto mutable_holes() { return &all_holes_; }
|
||||
auto deleted_entrances() const { return deleted_entrances_; }
|
||||
auto mutable_deleted_entrances() { return &deleted_entrances_; }
|
||||
auto AreaPalette() const {
|
||||
return overworld_maps_[current_map_].current_palette();
|
||||
}
|
||||
auto AreaPaletteById(int id) const {
|
||||
return overworld_maps_[id].current_palette();
|
||||
}
|
||||
auto BitmapData() const {
|
||||
return overworld_maps_[current_map_].bitmap_data();
|
||||
}
|
||||
auto Tile16Blockset() const {
|
||||
return overworld_maps_[current_map_].current_tile16_blockset();
|
||||
}
|
||||
auto is_loaded() const { return is_loaded_; }
|
||||
void set_current_map(int i) { current_map_ = i; }
|
||||
|
||||
auto map_tiles() const { return map_tiles_; }
|
||||
auto mutable_map_tiles() { return &map_tiles_; }
|
||||
auto all_items() const { return all_items_; }
|
||||
auto mutable_all_items() { return &all_items_; }
|
||||
auto &ref_all_items() { return all_items_; }
|
||||
auto all_tiles_types() const { return all_tiles_types_; }
|
||||
auto mutable_all_tiles_types() { return &all_tiles_types_; }
|
||||
|
||||
private:
|
||||
enum Dimension {
|
||||
map32TilesTL = 0,
|
||||
map32TilesTR = 1,
|
||||
map32TilesBL = 2,
|
||||
map32TilesBR = 3
|
||||
};
|
||||
|
||||
void FetchLargeMaps();
|
||||
void AssembleMap32Tiles();
|
||||
void AssembleMap16Tiles();
|
||||
void AssignWorldTiles(int x, int y, int sx, int sy, int tpos,
|
||||
OWBlockset &world);
|
||||
void OrganizeMapTiles(Bytes &bytes, Bytes &bytes2, int i, int sx, int sy,
|
||||
int &ttpos);
|
||||
absl::Status DecompressAllMapTiles();
|
||||
|
||||
absl::Status DecompressProtoMapTiles(const std::string &filename);
|
||||
|
||||
bool is_loaded_ = false;
|
||||
|
||||
int game_state_ = 0;
|
||||
int current_map_ = 0;
|
||||
uchar map_parent_[160];
|
||||
|
||||
ROM rom_;
|
||||
OWMapTiles map_tiles_;
|
||||
|
||||
uint8_t all_tiles_types_[0x200];
|
||||
|
||||
std::vector<gfx::Tile16> tiles16_;
|
||||
std::vector<gfx::Tile32> tiles32_;
|
||||
std::vector<uint16_t> tiles32_list_;
|
||||
std::vector<gfx::Tile32> tiles32_unique_;
|
||||
std::vector<OverworldMap> overworld_maps_;
|
||||
std::vector<OverworldEntrance> all_entrances_;
|
||||
std::vector<OverworldEntrance> all_holes_;
|
||||
std::vector<OverworldExit> all_exits_;
|
||||
std::vector<OverworldItem> all_items_;
|
||||
std::vector<std::vector<Sprite>> all_sprites_;
|
||||
|
||||
std::vector<uint64_t> deleted_entrances_;
|
||||
|
||||
std::vector<std::vector<uint8_t>> map_data_p1 =
|
||||
std::vector<std::vector<uint8_t>>(kNumOverworldMaps);
|
||||
std::vector<std::vector<uint8_t>> map_data_p2 =
|
||||
std::vector<std::vector<uint8_t>>(kNumOverworldMaps);
|
||||
|
||||
std::vector<int> map_pointers1_id = std::vector<int>(kNumOverworldMaps);
|
||||
std::vector<int> map_pointers2_id = std::vector<int>(kNumOverworldMaps);
|
||||
|
||||
std::vector<int> map_pointers1 = std::vector<int>(kNumOverworldMaps);
|
||||
std::vector<int> map_pointers2 = std::vector<int>(kNumOverworldMaps);
|
||||
|
||||
std::vector<absl::flat_hash_map<uint16_t, int>> usage_stats_;
|
||||
absl::flat_hash_map<int, MapData> proto_map_data_;
|
||||
};
|
||||
|
||||
} // namespace overworld
|
||||
} // namespace zelda3
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif
|
||||
564
src/app/zelda3/overworld/overworld_map.cc
Normal file
564
src/app/zelda3/overworld/overworld_map.cc
Normal file
@@ -0,0 +1,564 @@
|
||||
#include "overworld_map.h"
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "app/core/common.h"
|
||||
#include "app/editor/context/gfx_context.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
#include "app/rom.h"
|
||||
#include "app/zelda3/overworld/overworld.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace zelda3 {
|
||||
namespace overworld {
|
||||
|
||||
OverworldMap::OverworldMap(int index, ROM& rom,
|
||||
std::vector<gfx::Tile16>& tiles16)
|
||||
: parent_(index), index_(index), rom_(rom), tiles16_(tiles16) {
|
||||
LoadAreaInfo();
|
||||
}
|
||||
|
||||
absl::Status OverworldMap::BuildMap(int count, int game_state, int world,
|
||||
OWBlockset& world_blockset) {
|
||||
game_state_ = game_state;
|
||||
world_ = world;
|
||||
if (large_map_) {
|
||||
if (parent_ != index_ && !initialized_) {
|
||||
if (index_ >= 0x80 && index_ <= 0x8A && index_ != 0x88) {
|
||||
area_graphics_ = rom_[overworldSpecialGFXGroup + (parent_ - 0x80)];
|
||||
area_palette_ = rom_[overworldSpecialPALGroup + 1];
|
||||
} else if (index_ == 0x88) {
|
||||
area_graphics_ = 0x51;
|
||||
area_palette_ = 0x00;
|
||||
} else {
|
||||
area_graphics_ = rom_[mapGfx + parent_];
|
||||
area_palette_ = rom_[overworldMapPalette + parent_];
|
||||
}
|
||||
|
||||
initialized_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
LoadAreaGraphics();
|
||||
RETURN_IF_ERROR(BuildTileset())
|
||||
RETURN_IF_ERROR(BuildTiles16Gfx(count))
|
||||
RETURN_IF_ERROR(LoadPalette());
|
||||
RETURN_IF_ERROR(BuildBitmap(world_blockset))
|
||||
built_ = true;
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
void OverworldMap::LoadAreaInfo() {
|
||||
if (index_ != 0x80) {
|
||||
if (index_ <= 128)
|
||||
large_map_ = (rom_[overworldMapSize + (index_ & 0x3F)] != 0);
|
||||
else {
|
||||
large_map_ =
|
||||
index_ == 129 || index_ == 130 || index_ == 137 || index_ == 138;
|
||||
}
|
||||
}
|
||||
|
||||
message_id_ = rom_.toint16(overworldMessages + (parent_ * 2));
|
||||
|
||||
if (index_ < 0x40) {
|
||||
area_graphics_ = rom_[mapGfx + parent_];
|
||||
area_palette_ = rom_[overworldMapPalette + parent_];
|
||||
|
||||
area_music_[0] = rom_[overworldMusicBegining + parent_];
|
||||
area_music_[1] = rom_[overworldMusicZelda + parent_];
|
||||
area_music_[2] = rom_[overworldMusicMasterSword + parent_];
|
||||
area_music_[3] = rom_[overworldMusicAgahim + parent_];
|
||||
|
||||
sprite_graphics_[0] = rom_[overworldSpriteset + parent_];
|
||||
sprite_graphics_[1] = rom_[overworldSpriteset + parent_ + 0x40];
|
||||
sprite_graphics_[2] = rom_[overworldSpriteset + parent_ + 0x80];
|
||||
|
||||
sprite_palette_[0] = rom_[overworldSpritePalette + parent_];
|
||||
sprite_palette_[1] = rom_[overworldSpritePalette + parent_ + 0x40];
|
||||
sprite_palette_[2] = rom_[overworldSpritePalette + parent_ + 0x80];
|
||||
} else if (index_ < 0x80) {
|
||||
area_graphics_ = rom_[mapGfx + parent_];
|
||||
area_palette_ = rom_[overworldMapPalette + parent_];
|
||||
area_music_[0] = rom_[overworldMusicDW + (parent_ - 64)];
|
||||
|
||||
sprite_graphics_[0] = rom_[overworldSpriteset + parent_ + 0x80];
|
||||
sprite_graphics_[1] = rom_[overworldSpriteset + parent_ + 0x80];
|
||||
sprite_graphics_[2] = rom_[overworldSpriteset + parent_ + 0x80];
|
||||
|
||||
sprite_palette_[0] = rom_[overworldSpritePalette + parent_ + 0x80];
|
||||
sprite_palette_[1] = rom_[overworldSpritePalette + parent_ + 0x80];
|
||||
sprite_palette_[2] = rom_[overworldSpritePalette + parent_ + 0x80];
|
||||
} else {
|
||||
if (index_ == 0x94) {
|
||||
parent_ = 0x80;
|
||||
} else if (index_ == 0x95) {
|
||||
parent_ = 0x03;
|
||||
} else if (index_ == 0x96) {
|
||||
parent_ = 0x5B; // pyramid bg use 0x5B map
|
||||
} else if (index_ == 0x97) {
|
||||
parent_ = 0x00; // pyramid bg use 0x5B map
|
||||
} else if (index_ == 0x9C) {
|
||||
parent_ = 0x43;
|
||||
} else if (index_ == 0x9D) {
|
||||
parent_ = 0x00;
|
||||
} else if (index_ == 0x9E) {
|
||||
parent_ = 0x00;
|
||||
} else if (index_ == 0x9F) {
|
||||
parent_ = 0x2C;
|
||||
} else if (index_ == 0x88) {
|
||||
parent_ = 0x88;
|
||||
} else if (index_ == 129 || index_ == 130 || index_ == 137 ||
|
||||
index_ == 138) {
|
||||
parent_ = 129;
|
||||
}
|
||||
|
||||
area_palette_ = rom_[overworldSpecialPALGroup + parent_ - 0x80];
|
||||
if ((index_ >= 0x80 && index_ <= 0x8A && index_ != 0x88) ||
|
||||
index_ == 0x94) {
|
||||
area_graphics_ = rom_[overworldSpecialGFXGroup + (parent_ - 0x80)];
|
||||
area_palette_ = rom_[overworldSpecialPALGroup + 1];
|
||||
} else if (index_ == 0x88) {
|
||||
area_graphics_ = 0x51;
|
||||
area_palette_ = 0x00;
|
||||
} else {
|
||||
// pyramid bg use 0x5B map
|
||||
area_graphics_ = rom_[mapGfx + parent_];
|
||||
area_palette_ = rom_[overworldMapPalette + parent_];
|
||||
}
|
||||
|
||||
sprite_graphics_[0] = rom_[overworldSpriteset + parent_ + 0x80];
|
||||
sprite_graphics_[1] = rom_[overworldSpriteset + parent_ + 0x80];
|
||||
sprite_graphics_[2] = rom_[overworldSpriteset + parent_ + 0x80];
|
||||
|
||||
sprite_palette_[0] = rom_[overworldSpritePalette + parent_ + 0x80];
|
||||
sprite_palette_[1] = rom_[overworldSpritePalette + parent_ + 0x80];
|
||||
sprite_palette_[2] = rom_[overworldSpritePalette + parent_ + 0x80];
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
void OverworldMap::LoadWorldIndex() {
|
||||
if (parent_ < 0x40) {
|
||||
world_index_ = 0x20;
|
||||
} else if (parent_ >= 0x40 && parent_ < 0x80) {
|
||||
world_index_ = 0x21;
|
||||
} else if (parent_ == 0x88) {
|
||||
world_index_ = 0x24;
|
||||
}
|
||||
}
|
||||
|
||||
void OverworldMap::LoadSpritesBlocksets() {
|
||||
int static_graphics_base = 0x73;
|
||||
static_graphics_[8] = static_graphics_base + 0x00;
|
||||
static_graphics_[9] = static_graphics_base + 0x01;
|
||||
static_graphics_[10] = static_graphics_base + 0x06;
|
||||
static_graphics_[11] = static_graphics_base + 0x07;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
static_graphics_[12 + i] =
|
||||
(rom_[rom_.version_constants().kSpriteBlocksetPointer +
|
||||
(sprite_graphics_[game_state_] * 4) + i] +
|
||||
static_graphics_base);
|
||||
}
|
||||
}
|
||||
|
||||
void OverworldMap::LoadMainBlocksets() {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
static_graphics_[i] = rom_[rom_.version_constants().kOverworldGfxGroups2 +
|
||||
(world_index_ * 8) + i];
|
||||
}
|
||||
}
|
||||
|
||||
// For animating water tiles on the overworld map.
|
||||
// We want to swap out static_graphics_[07] with the next sheet
|
||||
// Usually it is 5A, so we make it 5B instead.
|
||||
// There is a middle frame which contains tiles from the bottom half
|
||||
// of the 5A sheet, so this will need some special manipulation to make work
|
||||
// during the BuildBitmap step (or a new one specifically for animating).
|
||||
void OverworldMap::DrawAnimatedTiles() {
|
||||
std::cout << "static_graphics_[6] = "
|
||||
<< core::UppercaseHexByte(static_graphics_[6]) << std::endl;
|
||||
std::cout << "static_graphics_[7] = "
|
||||
<< core::UppercaseHexByte(static_graphics_[7]) << std::endl;
|
||||
std::cout << "static_graphics_[8] = "
|
||||
<< core::UppercaseHexByte(static_graphics_[8]) << std::endl;
|
||||
if (static_graphics_[7] == 0x5B) {
|
||||
static_graphics_[7] = 0x5A;
|
||||
} else {
|
||||
if (static_graphics_[7] == 0x59) {
|
||||
static_graphics_[7] = 0x58;
|
||||
}
|
||||
static_graphics_[7] = 0x5B;
|
||||
}
|
||||
}
|
||||
|
||||
void OverworldMap::LoadAreaGraphicsBlocksets() {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
uchar value = rom_[rom_.version_constants().kOverworldGfxGroups1 +
|
||||
(area_graphics_ * 4) + i];
|
||||
if (value != 0) {
|
||||
static_graphics_[3 + i] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OverworldMap::LoadDeathMountainGFX() {
|
||||
static_graphics_[7] = (((parent_ >= 0x03 && parent_ <= 0x07) ||
|
||||
(parent_ >= 0x0B && parent_ <= 0x0E)) ||
|
||||
((parent_ >= 0x43 && parent_ <= 0x47) ||
|
||||
(parent_ >= 0x4B && parent_ <= 0x4E)))
|
||||
? 0x59
|
||||
: 0x5B;
|
||||
}
|
||||
|
||||
void OverworldMap::LoadAreaGraphics() {
|
||||
LoadWorldIndex();
|
||||
LoadSpritesBlocksets();
|
||||
LoadMainBlocksets();
|
||||
LoadAreaGraphicsBlocksets();
|
||||
LoadDeathMountainGFX();
|
||||
}
|
||||
|
||||
namespace palette_internal {
|
||||
|
||||
absl::Status SetColorsPalette(ROM& rom, int index, gfx::SnesPalette& current,
|
||||
gfx::SnesPalette main, gfx::SnesPalette animated,
|
||||
gfx::SnesPalette aux1, gfx::SnesPalette aux2,
|
||||
gfx::SnesPalette hud, gfx::SnesColor bgrcolor,
|
||||
gfx::SnesPalette spr, gfx::SnesPalette spr2) {
|
||||
// Palettes infos, color 0 of a palette is always transparent (the arrays
|
||||
// contains 7 colors width wide) There is 16 color per line so 16*Y
|
||||
|
||||
// Left side of the palette - Main, Animated
|
||||
std::vector<gfx::SnesColor> new_palette(256);
|
||||
|
||||
// Main Palette, Location 0,2 : 35 colors [7x5]
|
||||
int k = 0;
|
||||
for (int y = 2; y < 7; y++) {
|
||||
for (int x = 1; x < 8; x++) {
|
||||
new_palette[x + (16 * y)] = main[k];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
// Animated Palette, Location 0,7 : 7colors
|
||||
for (int x = 1; x < 8; x++) {
|
||||
new_palette[(16 * 7) + (x)] = animated[(x - 1)];
|
||||
}
|
||||
|
||||
// Right side of the palette - Aux1, Aux2
|
||||
|
||||
// Aux1 Palette, Location 8,2 : 21 colors [7x3]
|
||||
k = 0;
|
||||
for (int y = 2; y < 5; y++) {
|
||||
for (int x = 9; x < 16; x++) {
|
||||
new_palette[x + (16 * y)] = aux1[k];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
// Aux2 Palette, Location 8,5 : 21 colors [7x3]
|
||||
k = 0;
|
||||
for (int y = 5; y < 8; y++) {
|
||||
for (int x = 9; x < 16; x++) {
|
||||
new_palette[x + (16 * y)] = aux2[k];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
// Hud Palette, Location 0,0 : 32 colors [16x2]
|
||||
for (int i = 0; i < 32; i++) {
|
||||
new_palette[i] = hud[i];
|
||||
}
|
||||
|
||||
// Hardcoded grass color (that might change to become invisible instead)
|
||||
for (int i = 0; i < 8; i++) {
|
||||
new_palette[(i * 16)] = bgrcolor;
|
||||
new_palette[(i * 16) + 8] = bgrcolor;
|
||||
}
|
||||
|
||||
// Sprite Palettes
|
||||
k = 0;
|
||||
for (int y = 8; y < 9; y++) {
|
||||
for (int x = 1; x < 8; x++) {
|
||||
auto pal_group = rom.palette_group().sprites_aux1;
|
||||
new_palette[x + (16 * y)] = pal_group[1][k];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
// Sprite Palettes
|
||||
k = 0;
|
||||
for (int y = 8; y < 9; y++) {
|
||||
for (int x = 9; x < 16; x++) {
|
||||
auto pal_group = rom.palette_group().sprites_aux3;
|
||||
new_palette[x + (16 * y)] = pal_group[0][k];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
// Sprite Palettes
|
||||
k = 0;
|
||||
for (int y = 9; y < 13; y++) {
|
||||
for (int x = 1; x < 16; x++) {
|
||||
auto pal_group = rom.palette_group().global_sprites;
|
||||
new_palette[x + (16 * y)] = pal_group[0][k];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
// Sprite Palettes
|
||||
k = 0;
|
||||
for (int y = 13; y < 14; y++) {
|
||||
for (int x = 1; x < 8; x++) {
|
||||
new_palette[x + (16 * y)] = spr[k];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
// Sprite Palettes
|
||||
k = 0;
|
||||
for (int y = 14; y < 15; y++) {
|
||||
for (int x = 1; x < 8; x++) {
|
||||
new_palette[x + (16 * y)] = spr2[k];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
// Sprite Palettes
|
||||
k = 0;
|
||||
for (int y = 15; y < 16; y++) {
|
||||
for (int x = 1; x < 16; x++) {
|
||||
auto pal_group = rom.palette_group().armors;
|
||||
new_palette[x + (16 * y)] = pal_group[0][k];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
current.Create(new_palette);
|
||||
for (int i = 0; i < 256; i++) {
|
||||
current[(i / 16) * 16].set_transparent(true);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
} // namespace palette_internal
|
||||
|
||||
// New helper function to get a palette from the ROM.
|
||||
absl::StatusOr<gfx::SnesPalette> OverworldMap::GetPalette(
|
||||
const gfx::PaletteGroup& palette_group, int index, int previous_index,
|
||||
int limit) {
|
||||
if (index == 255) {
|
||||
index = rom_[rom_.version_constants().overworldMapPaletteGroup +
|
||||
(previous_index * 4)];
|
||||
}
|
||||
if (index >= limit) {
|
||||
index = limit - 1;
|
||||
}
|
||||
return palette_group[index];
|
||||
}
|
||||
|
||||
absl::Status OverworldMap::LoadPalette() {
|
||||
int previousPalId = index_ > 0 ? rom_[overworldMapPalette + parent_ - 1] : 0;
|
||||
int previousSprPalId =
|
||||
index_ > 0 ? rom_[overworldSpritePalette + parent_ - 1] : 0;
|
||||
|
||||
area_palette_ = std::min((int)area_palette_, 0xA3);
|
||||
|
||||
uchar pal0 = 0;
|
||||
uchar pal1 = rom_[rom_.version_constants().overworldMapPaletteGroup +
|
||||
(area_palette_ * 4)];
|
||||
uchar pal2 = rom_[rom_.version_constants().overworldMapPaletteGroup +
|
||||
(area_palette_ * 4) + 1];
|
||||
uchar pal3 = rom_[rom_.version_constants().overworldMapPaletteGroup +
|
||||
(area_palette_ * 4) + 2];
|
||||
uchar pal4 =
|
||||
rom_[overworldSpritePaletteGroup + (sprite_palette_[game_state_] * 2)];
|
||||
uchar pal5 = rom_[overworldSpritePaletteGroup +
|
||||
(sprite_palette_[game_state_] * 2) + 1];
|
||||
|
||||
auto grass_pal_group = rom_.palette_group().grass;
|
||||
ASSIGN_OR_RETURN(gfx::SnesColor bgr, grass_pal_group[0].GetColor(0));
|
||||
|
||||
auto ow_aux_pal_group = rom_.palette_group().overworld_aux;
|
||||
ASSIGN_OR_RETURN(gfx::SnesPalette aux1,
|
||||
GetPalette(ow_aux_pal_group, pal1, previousPalId, 20));
|
||||
ASSIGN_OR_RETURN(gfx::SnesPalette aux2,
|
||||
GetPalette(ow_aux_pal_group, pal2, previousPalId, 20));
|
||||
|
||||
// Additional handling of `pal3` and `parent_`
|
||||
if (pal3 == 255) {
|
||||
pal3 = rom_[rom_.version_constants().overworldMapPaletteGroup +
|
||||
(previousPalId * 4) + 2];
|
||||
}
|
||||
|
||||
if (parent_ < 0x40) {
|
||||
pal0 = parent_ == 0x03 || parent_ == 0x05 || parent_ == 0x07 ? 2 : 0;
|
||||
ASSIGN_OR_RETURN(bgr, grass_pal_group[0].GetColor(0));
|
||||
} else if (parent_ >= 0x40 && parent_ < 0x80) {
|
||||
pal0 = parent_ == 0x43 || parent_ == 0x45 || parent_ == 0x47 ? 3 : 1;
|
||||
ASSIGN_OR_RETURN(bgr, grass_pal_group[0].GetColor(1));
|
||||
} else if (parent_ >= 128 && parent_ < kNumOverworldMaps) {
|
||||
pal0 = 0;
|
||||
ASSIGN_OR_RETURN(bgr, grass_pal_group[0].GetColor(2));
|
||||
}
|
||||
|
||||
if (parent_ == 0x88) {
|
||||
pal0 = 4;
|
||||
}
|
||||
|
||||
auto ow_main_pal_group = rom_.palette_group().overworld_main;
|
||||
ASSIGN_OR_RETURN(gfx::SnesPalette main,
|
||||
GetPalette(ow_main_pal_group, pal0, previousPalId, 255));
|
||||
auto ow_animated_pal_group = rom_.palette_group().overworld_animated;
|
||||
ASSIGN_OR_RETURN(gfx::SnesPalette animated,
|
||||
GetPalette(ow_animated_pal_group, std::min((int)pal3, 13),
|
||||
previousPalId, 14));
|
||||
|
||||
auto hud_pal_group = rom_.palette_group().hud;
|
||||
gfx::SnesPalette hud = hud_pal_group[0];
|
||||
|
||||
ASSIGN_OR_RETURN(gfx::SnesPalette spr,
|
||||
GetPalette(rom_.palette_group().sprites_aux3, pal4,
|
||||
previousSprPalId, 24));
|
||||
ASSIGN_OR_RETURN(gfx::SnesPalette spr2,
|
||||
GetPalette(rom_.palette_group().sprites_aux3, pal5,
|
||||
previousSprPalId, 24));
|
||||
|
||||
RETURN_IF_ERROR(palette_internal::SetColorsPalette(
|
||||
rom_, parent_, current_palette_, main, animated, aux1, aux2, hud, bgr,
|
||||
spr, spr2));
|
||||
|
||||
if (palettesets_.count(area_palette_) == 0) {
|
||||
palettesets_[area_palette_] = gfx::Paletteset{
|
||||
main, animated, aux1, aux2, bgr, hud, spr, spr2, current_palette_};
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
// New helper function to process graphics buffer.
|
||||
void OverworldMap::ProcessGraphicsBuffer(int index, int static_graphics_offset,
|
||||
int size) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
auto byte = all_gfx_[i + (static_graphics_offset * size)];
|
||||
switch (index) {
|
||||
case 0:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
byte += 0x88;
|
||||
break;
|
||||
}
|
||||
current_gfx_[(index * size) + i] = byte;
|
||||
}
|
||||
}
|
||||
|
||||
absl::Status OverworldMap::BuildTileset() {
|
||||
all_gfx_ = rom_.graphics_buffer();
|
||||
if (current_gfx_.size() == 0) current_gfx_.resize(0x10000, 0x00);
|
||||
|
||||
for (int i = 0; i < 0x10; i++) {
|
||||
ProcessGraphicsBuffer(i, static_graphics_[i], 0x1000);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status OverworldMap::BuildTiles16Gfx(int count) {
|
||||
if (current_blockset_.size() == 0) current_blockset_.resize(0x100000, 0x00);
|
||||
|
||||
const int offsets[] = {0x00, 0x08, 0x400, 0x408};
|
||||
auto yy = 0;
|
||||
auto xx = 0;
|
||||
|
||||
for (auto i = 0; i < count; i++) {
|
||||
for (auto tile = 0; tile < 0x04; tile++) {
|
||||
gfx::TileInfo info = tiles16_[i].tiles_info[tile];
|
||||
int offset = offsets[tile];
|
||||
for (auto y = 0; y < 0x08; ++y) {
|
||||
for (auto x = 0; x < 0x08; ++x) {
|
||||
int mx = x;
|
||||
int my = y;
|
||||
|
||||
if (info.horizontal_mirror_ != 0) {
|
||||
mx = 0x07 - x;
|
||||
}
|
||||
|
||||
if (info.vertical_mirror_ != 0) {
|
||||
my = 0x07 - y;
|
||||
}
|
||||
|
||||
int xpos = ((info.id_ % 0x10) * 0x08);
|
||||
int ypos = (((info.id_ / 0x10)) * 0x400);
|
||||
int source = ypos + xpos + (x + (y * 0x80));
|
||||
|
||||
auto destination = xx + yy + offset + (mx + (my * 0x80));
|
||||
current_blockset_[destination] =
|
||||
(current_gfx_[source] & 0x0F) + (info.palette_ * 0x10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xx += 0x10;
|
||||
if (xx >= 0x80) {
|
||||
yy += 0x800;
|
||||
xx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void CopyTile8bpp16(int x, int y, int tile, Bytes& bitmap, Bytes& blockset) {
|
||||
int src_pos =
|
||||
((tile - ((tile / 0x08) * 0x08)) * 0x10) + ((tile / 0x08) * 2048);
|
||||
int dest_pos = (x + (y * 0x200));
|
||||
for (int yy = 0; yy < 0x10; yy++) {
|
||||
for (int xx = 0; xx < 0x10; xx++) {
|
||||
bitmap[dest_pos + xx + (yy * 0x200)] =
|
||||
blockset[src_pos + xx + (yy * 0x80)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
absl::Status OverworldMap::BuildBitmap(OWBlockset& world_blockset) {
|
||||
if (bitmap_data_.size() != 0) {
|
||||
bitmap_data_.clear();
|
||||
}
|
||||
bitmap_data_.reserve(0x40000);
|
||||
for (int i = 0; i < 0x40000; i++) {
|
||||
bitmap_data_.push_back(0x00);
|
||||
}
|
||||
|
||||
int superY = ((index_ - (world_ * 0x40)) / 0x08);
|
||||
int superX = index_ - (world_ * 0x40) - (superY * 0x08);
|
||||
|
||||
for (int y = 0; y < 0x20; y++) {
|
||||
for (int x = 0; x < 0x20; x++) {
|
||||
auto xt = x + (superX * 0x20);
|
||||
auto yt = y + (superY * 0x20);
|
||||
CopyTile8bpp16((x * 0x10), (y * 0x10), world_blockset[xt][yt],
|
||||
bitmap_data_, current_blockset_);
|
||||
}
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
} // namespace overworld
|
||||
} // namespace zelda3
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
153
src/app/zelda3/overworld/overworld_map.h
Normal file
153
src/app/zelda3/overworld/overworld_map.h
Normal file
@@ -0,0 +1,153 @@
|
||||
#ifndef YAZE_APP_ZELDA3_OVERWORLD_MAP_H
|
||||
#define YAZE_APP_ZELDA3_OVERWORLD_MAP_H
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "app/core/common.h"
|
||||
#include "app/editor/context/gfx_context.h"
|
||||
#include "app/gfx/bitmap.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
#include "app/gfx/snes_tile.h"
|
||||
#include "app/rom.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace zelda3 {
|
||||
namespace overworld {
|
||||
|
||||
static constexpr int kTileOffsets[] = {0, 8, 4096, 4104};
|
||||
|
||||
/**
|
||||
* @brief Represents a single Overworld map screen.
|
||||
*/
|
||||
class OverworldMap : public editor::context::GfxContext {
|
||||
public:
|
||||
OverworldMap() = default;
|
||||
OverworldMap(int index, ROM& rom, std::vector<gfx::Tile16>& tiles16);
|
||||
|
||||
absl::Status BuildMap(int count, int game_state, int world,
|
||||
OWBlockset& world_blockset);
|
||||
|
||||
void LoadAreaGraphics();
|
||||
absl::Status LoadPalette();
|
||||
absl::Status BuildTileset();
|
||||
absl::Status BuildTiles16Gfx(int count);
|
||||
absl::Status BuildBitmap(OWBlockset& world_blockset);
|
||||
|
||||
void DrawAnimatedTiles();
|
||||
|
||||
auto current_tile16_blockset() const { return current_blockset_; }
|
||||
auto current_graphics() const { return current_gfx_; }
|
||||
auto current_palette() const { return current_palette_; }
|
||||
auto bitmap_data() const { return bitmap_data_; }
|
||||
auto is_large_map() const { return large_map_; }
|
||||
auto is_initialized() const { return initialized_; }
|
||||
auto parent() const { return parent_; }
|
||||
|
||||
auto mutable_current_palette() { return ¤t_palette_; }
|
||||
|
||||
auto area_graphics() const { return area_graphics_; }
|
||||
auto area_palette() const { return area_palette_; }
|
||||
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 large_index() const { return large_index_; }
|
||||
|
||||
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]; }
|
||||
|
||||
auto set_area_graphics(uint8_t value) { area_graphics_ = value; }
|
||||
auto set_area_palette(uint8_t value) { area_palette_ = value; }
|
||||
auto set_sprite_graphics(int i, uint8_t value) {
|
||||
sprite_graphics_[i] = value;
|
||||
}
|
||||
auto set_sprite_palette(int i, uint8_t value) { sprite_palette_[i] = value; }
|
||||
auto set_message_id(uint16_t value) { message_id_ = value; }
|
||||
|
||||
void SetAsLargeMap(int parent_index, int quadrant) {
|
||||
parent_ = parent_index;
|
||||
large_index_ = quadrant;
|
||||
large_map_ = true;
|
||||
}
|
||||
|
||||
void SetAsSmallMap(int index = -1) {
|
||||
if (index != -1)
|
||||
parent_ = index;
|
||||
else
|
||||
parent_ = index_;
|
||||
large_index_ = 0;
|
||||
large_map_ = false;
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
current_blockset_.clear();
|
||||
current_gfx_.clear();
|
||||
bitmap_data_.clear();
|
||||
tiles16_.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
void LoadAreaInfo();
|
||||
|
||||
void LoadWorldIndex();
|
||||
void LoadSpritesBlocksets();
|
||||
void LoadMainBlocksets();
|
||||
void LoadAreaGraphicsBlocksets();
|
||||
void LoadDeathMountainGFX();
|
||||
|
||||
void ProcessGraphicsBuffer(int index, int static_graphics_offset, int size);
|
||||
absl::StatusOr<gfx::SnesPalette> GetPalette(const gfx::PaletteGroup& group,
|
||||
int index, int previous_index,
|
||||
int limit);
|
||||
|
||||
bool built_ = false;
|
||||
bool large_map_ = false;
|
||||
bool initialized_ = false;
|
||||
|
||||
int index_ = 0; // Map index
|
||||
int parent_ = 0; // Parent map index
|
||||
int large_index_ = 0; // Quadrant ID [0-3]
|
||||
int world_ = 0; // World ID [0-2]
|
||||
int game_state_ = 0; // Game state [0-2]
|
||||
int world_index_ = 0; // Spr Pal Modifier
|
||||
|
||||
uint16_t message_id_ = 0;
|
||||
uint8_t area_graphics_ = 0;
|
||||
uint8_t area_palette_ = 0;
|
||||
|
||||
uchar sprite_graphics_[3];
|
||||
uchar sprite_palette_[3];
|
||||
uchar area_music_[4];
|
||||
uchar static_graphics_[16];
|
||||
|
||||
ROM rom_;
|
||||
Bytes all_gfx_;
|
||||
Bytes current_blockset_;
|
||||
Bytes current_gfx_;
|
||||
Bytes bitmap_data_;
|
||||
OWMapTiles map_tiles_;
|
||||
|
||||
gfx::SnesPalette current_palette_;
|
||||
std::vector<gfx::Tile16> tiles16_;
|
||||
};
|
||||
|
||||
} // namespace overworld
|
||||
} // namespace zelda3
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user