2017-06-28 19:00:08 -04:00
|
|
|
#include "stdafx.h"
|
2017-07-23 13:47:10 -04:00
|
|
|
#include <algorithm>
|
2017-06-28 19:00:08 -04:00
|
|
|
#include <unordered_map>
|
2017-07-30 09:03:54 -04:00
|
|
|
#include "../Utilities/ZipReader.h"
|
2017-06-28 19:00:08 -04:00
|
|
|
#include "../Utilities/FolderUtilities.h"
|
|
|
|
#include "../Utilities/StringUtilities.h"
|
|
|
|
#include "../Utilities/HexUtilities.h"
|
|
|
|
#include "../Utilities/PNGHelper.h"
|
|
|
|
#include "Console.h"
|
|
|
|
#include "HdPackLoader.h"
|
2018-02-17 23:44:25 -05:00
|
|
|
#include "HdPackConditions.h"
|
|
|
|
#include "HdNesPack.h"
|
|
|
|
|
|
|
|
#define checkConstraint(x, y) if(!(x)) { MessageManager::Log(y); return; }
|
2017-06-28 19:00:08 -04:00
|
|
|
|
2021-06-04 11:51:16 +01:00
|
|
|
static const char windowsSlash = '\\';
|
|
|
|
static const char unixSlash = '/';
|
|
|
|
#if defined(_WIN32)
|
|
|
|
#define convertPathToNative(filepath) std::replace(filepath.begin(), filepath.end(), unixSlash, windowsSlash)
|
|
|
|
#else
|
|
|
|
#define convertPathToNative(filepath) std::replace(filepath.begin(), filepath.end(), windowsSlash, unixSlash)
|
|
|
|
#endif
|
|
|
|
#define convertPathToNativeVector(vector, idx) if (vector.size() > idx) { convertPathToNative(vector[idx]); }
|
|
|
|
|
2017-07-30 09:03:54 -04:00
|
|
|
HdPackLoader::HdPackLoader()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool HdPackLoader::InitializeLoader(VirtualFile &romFile, HdPackData *data)
|
2017-06-28 19:00:08 -04:00
|
|
|
{
|
|
|
|
_data = data;
|
2017-07-30 09:03:54 -04:00
|
|
|
|
|
|
|
string romName = FolderUtilities::GetFilename(romFile.GetFileName(), false);
|
|
|
|
string hdPackFolder = FolderUtilities::GetHdPackFolder();
|
|
|
|
string zipName = romName + ".hdn";
|
|
|
|
string definitionPath = FolderUtilities::CombinePath(romName, "hires.txt");
|
|
|
|
|
|
|
|
string legacyPath = FolderUtilities::CombinePath(hdPackFolder, definitionPath);
|
|
|
|
if(ifstream(legacyPath)) {
|
|
|
|
_loadFromZip = false;
|
|
|
|
_hdPackFolder = FolderUtilities::GetFolderName(legacyPath);
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
vector<string> hdnPackages = FolderUtilities::GetFilesInFolder(romFile.GetFolderPath(), { ".hdn" }, false);
|
|
|
|
vector<string> more = FolderUtilities::GetFilesInFolder(hdPackFolder, { ".hdn", ".zip" }, false);
|
|
|
|
hdnPackages.insert(hdnPackages.end(), more.begin(), more.end());
|
|
|
|
|
|
|
|
string sha1Hash = romFile.GetSha1Hash();
|
|
|
|
for(string path : hdnPackages) {
|
|
|
|
_reader.LoadArchive(path);
|
|
|
|
|
|
|
|
vector<uint8_t> hdDefinition;
|
|
|
|
if(_reader.ExtractFile("hires.txt", hdDefinition)) {
|
|
|
|
if(FolderUtilities::GetFilename(path, false) == romName) {
|
|
|
|
_loadFromZip = true;
|
|
|
|
_hdPackFolder = path;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
for(string line : StringUtilities::Split(string(hdDefinition.data(), hdDefinition.data() + hdDefinition.size()), '\n')) {
|
|
|
|
std::transform(line.begin(), line.end(), line.begin(), ::tolower);
|
|
|
|
if(line.find("<supportedrom>") != string::npos && line.find(sha1Hash) != string::npos) {
|
|
|
|
_loadFromZip = true;
|
|
|
|
_hdPackFolder = path;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool HdPackLoader::LoadHdNesPack(string definitionFile, HdPackData &outData)
|
|
|
|
{
|
|
|
|
HdPackLoader loader;
|
|
|
|
if(ifstream(definitionFile)) {
|
|
|
|
loader._data = &outData;
|
|
|
|
loader._loadFromZip = false;
|
|
|
|
loader._hdPackFolder = FolderUtilities::GetFolderName(definitionFile);
|
|
|
|
return loader.LoadPack();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool HdPackLoader::LoadHdNesPack(VirtualFile &romFile, HdPackData &outData)
|
|
|
|
{
|
|
|
|
HdPackLoader loader;
|
|
|
|
if(loader.InitializeLoader(romFile, &outData)) {
|
|
|
|
return loader.LoadPack();
|
|
|
|
}
|
|
|
|
return false;
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
2017-08-19 16:46:57 -04:00
|
|
|
bool HdPackLoader::CheckFile(string filename)
|
|
|
|
{
|
|
|
|
if(_loadFromZip) {
|
|
|
|
return _reader.CheckFile(filename);
|
|
|
|
} else {
|
|
|
|
ifstream file(FolderUtilities::CombinePath(_hdPackFolder, filename), ios::in | ios::binary);
|
|
|
|
if(file.good()) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-07-30 09:03:54 -04:00
|
|
|
bool HdPackLoader::LoadFile(string filename, vector<uint8_t> &fileData)
|
2017-06-28 19:00:08 -04:00
|
|
|
{
|
2017-07-30 09:03:54 -04:00
|
|
|
fileData.clear();
|
2017-06-28 19:00:08 -04:00
|
|
|
|
2017-07-30 09:03:54 -04:00
|
|
|
if(_loadFromZip) {
|
|
|
|
if(_reader.ExtractFile(filename, fileData)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ifstream file(FolderUtilities::CombinePath(_hdPackFolder, filename), ios::in | ios::binary);
|
|
|
|
if(file.good()) {
|
|
|
|
file.seekg(0, ios::end);
|
|
|
|
uint32_t fileSize = (uint32_t)file.tellg();
|
|
|
|
file.seekg(0, ios::beg);
|
|
|
|
|
|
|
|
fileData = vector<uint8_t>(fileSize, 0);
|
|
|
|
file.read((char*)fileData.data(), fileSize);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
bool HdPackLoader::LoadPack()
|
|
|
|
{
|
2017-12-28 12:47:26 -05:00
|
|
|
string currentLine;
|
2017-06-28 19:00:08 -04:00
|
|
|
try {
|
2017-07-30 09:03:54 -04:00
|
|
|
vector<uint8_t> hdDefinition;
|
|
|
|
if(!LoadFile("hires.txt", hdDefinition)) {
|
2017-06-28 19:00:08 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-08-15 20:25:25 -04:00
|
|
|
InitializeGlobalConditions();
|
|
|
|
|
2017-07-30 09:03:54 -04:00
|
|
|
for(string lineContent : StringUtilities::Split(string(hdDefinition.data(), hdDefinition.data() + hdDefinition.size()), '\n')) {
|
2018-01-06 08:07:37 -05:00
|
|
|
if(lineContent.empty()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-12-28 12:47:26 -05:00
|
|
|
if(lineContent[lineContent.size() - 1] == '\r') {
|
|
|
|
lineContent = lineContent.substr(0, lineContent.size() - 1);
|
|
|
|
}
|
|
|
|
currentLine = lineContent;
|
2017-06-28 19:00:08 -04:00
|
|
|
|
|
|
|
vector<HdPackCondition*> conditions;
|
|
|
|
if(lineContent.substr(0, 1) == "[") {
|
|
|
|
size_t endOfCondition = lineContent.find_first_of(']', 1);
|
|
|
|
conditions = ParseConditionString(lineContent.substr(1, endOfCondition - 1), _data->Conditions);
|
|
|
|
lineContent = lineContent.substr(endOfCondition + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<string> tokens;
|
|
|
|
if(lineContent.substr(0, 5) == "<ver>") {
|
|
|
|
_data->Version = stoi(lineContent.substr(5));
|
2018-02-17 23:44:25 -05:00
|
|
|
if(_data->Version > HdNesPack::CurrentVersion) {
|
|
|
|
MessageManager::Log("[HDPack] This HD Pack was built with a more recent version of Mesen - update Mesen to the latest version and try again.");
|
|
|
|
return false;
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
} else if(lineContent.substr(0, 7) == "<scale>") {
|
|
|
|
lineContent = lineContent.substr(7);
|
|
|
|
_data->Scale = std::stoi(lineContent);
|
2017-08-12 21:21:55 -04:00
|
|
|
} else if(lineContent.substr(0, 10) == "<overscan>") {
|
|
|
|
tokens = StringUtilities::Split(lineContent.substr(10), ',');
|
|
|
|
ProcessOverscanTag(tokens);
|
2017-06-28 19:00:08 -04:00
|
|
|
} else if(lineContent.substr(0, 5) == "<img>") {
|
|
|
|
lineContent = lineContent.substr(5);
|
2021-06-04 11:51:16 +01:00
|
|
|
convertPathToNative(lineContent);
|
2017-07-30 09:03:54 -04:00
|
|
|
if(!ProcessImgTag(lineContent)) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
} else if(lineContent.substr(0, 7) == "<patch>") {
|
|
|
|
tokens = StringUtilities::Split(lineContent.substr(7), ',');
|
2021-06-04 11:51:16 +01:00
|
|
|
convertPathToNativeVector(tokens, 0);
|
2017-06-28 19:00:08 -04:00
|
|
|
ProcessPatchTag(tokens);
|
|
|
|
} else if(lineContent.substr(0, 12) == "<background>") {
|
|
|
|
tokens = StringUtilities::Split(lineContent.substr(12), ',');
|
2021-06-04 11:51:16 +01:00
|
|
|
convertPathToNativeVector(tokens, 0);
|
2017-06-28 19:00:08 -04:00
|
|
|
ProcessBackgroundTag(tokens, conditions);
|
|
|
|
} else if(lineContent.substr(0, 11) == "<condition>") {
|
|
|
|
tokens = StringUtilities::Split(lineContent.substr(11), ',');
|
2018-02-25 17:03:06 -05:00
|
|
|
ProcessConditionTag(tokens, false);
|
|
|
|
ProcessConditionTag(tokens, true);
|
2017-06-28 19:00:08 -04:00
|
|
|
} else if(lineContent.substr(0, 6) == "<tile>") {
|
|
|
|
tokens = StringUtilities::Split(lineContent.substr(6), ',');
|
|
|
|
ProcessTileTag(tokens, conditions);
|
|
|
|
} else if(lineContent.substr(0, 9) == "<options>") {
|
|
|
|
tokens = StringUtilities::Split(lineContent.substr(9), ',');
|
|
|
|
ProcessOptionTag(tokens);
|
2017-08-19 16:46:57 -04:00
|
|
|
} else if(lineContent.substr(0, 5) == "<bgm>") {
|
|
|
|
tokens = StringUtilities::Split(lineContent.substr(5), ',');
|
2021-06-04 11:51:16 +01:00
|
|
|
convertPathToNativeVector(tokens, 2);
|
2017-08-19 16:46:57 -04:00
|
|
|
ProcessBgmTag(tokens);
|
|
|
|
} else if(lineContent.substr(0, 5) == "<sfx>") {
|
|
|
|
tokens = StringUtilities::Split(lineContent.substr(5), ',');
|
2021-06-04 11:51:16 +01:00
|
|
|
convertPathToNativeVector(tokens, 2);
|
2017-08-19 16:46:57 -04:00
|
|
|
ProcessSfxTag(tokens);
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LoadCustomPalette();
|
|
|
|
InitializeHdPack();
|
|
|
|
|
|
|
|
return true;
|
2019-11-13 18:30:05 -05:00
|
|
|
} catch(std::exception &ex) {
|
2017-12-28 12:47:26 -05:00
|
|
|
MessageManager::Log(string("[HDPack] Error loading HDPack: ") + ex.what() + " on line: " + currentLine);
|
2017-06-28 19:00:08 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-30 09:03:54 -04:00
|
|
|
bool HdPackLoader::ProcessImgTag(string src)
|
|
|
|
{
|
|
|
|
HdPackBitmapInfo bitmapInfo;
|
|
|
|
vector<uint8_t> fileData;
|
2018-06-19 20:43:16 -04:00
|
|
|
vector<uint8_t> pixelData;
|
2017-07-30 09:03:54 -04:00
|
|
|
LoadFile(src, fileData);
|
2018-06-19 20:43:16 -04:00
|
|
|
if(PNGHelper::ReadPNG(fileData, pixelData, bitmapInfo.Width, bitmapInfo.Height)) {
|
|
|
|
bitmapInfo.PixelData.resize(pixelData.size() / 4);
|
|
|
|
memcpy(bitmapInfo.PixelData.data(), pixelData.data(), bitmapInfo.PixelData.size() * sizeof(bitmapInfo.PixelData[0]));
|
2020-02-01 09:52:49 -05:00
|
|
|
PremultiplyAlpha(bitmapInfo.PixelData);
|
2017-07-30 09:03:54 -04:00
|
|
|
_hdNesBitmaps.push_back(bitmapInfo);
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
MessageManager::Log("[HDPack] Error loading HDPack: PNG file " + src + " could not be read.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-01 09:52:49 -05:00
|
|
|
void HdPackLoader::PremultiplyAlpha(vector<uint32_t> &pixelData)
|
|
|
|
{
|
2020-02-01 11:19:07 -05:00
|
|
|
for(size_t i = 0; i < pixelData.size(); i++) {
|
2020-02-01 09:52:49 -05:00
|
|
|
if(pixelData[i] < 0xFF000000) {
|
|
|
|
uint8_t* output = (uint8_t*)(pixelData.data() + i);
|
|
|
|
uint8_t alpha = output[3] + 1;
|
|
|
|
output[0] = (uint8_t)((alpha * output[0]) >> 8);
|
|
|
|
output[1] = (uint8_t)((alpha * output[1]) >> 8);
|
|
|
|
output[2] = (uint8_t)((alpha * output[2]) >> 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-15 20:25:25 -04:00
|
|
|
void HdPackLoader::InitializeGlobalConditions()
|
|
|
|
{
|
2018-02-17 23:44:25 -05:00
|
|
|
HdPackCondition* hmirror = new HdPackHorizontalMirroringCondition();
|
2017-08-15 20:25:25 -04:00
|
|
|
hmirror->Name = "hmirror";
|
|
|
|
_data->Conditions.push_back(unique_ptr<HdPackCondition>(hmirror));
|
|
|
|
|
2018-02-25 17:03:06 -05:00
|
|
|
HdPackCondition* invHmirror = new HdPackHorizontalMirroringCondition();
|
|
|
|
invHmirror->Name = "!hmirror";
|
|
|
|
_data->Conditions.push_back(unique_ptr<HdPackCondition>(invHmirror));
|
|
|
|
|
2018-02-17 23:44:25 -05:00
|
|
|
HdPackCondition* vmirror = new HdPackVerticalMirroringCondition();
|
2017-08-15 20:25:25 -04:00
|
|
|
vmirror->Name = "vmirror";
|
|
|
|
_data->Conditions.push_back(unique_ptr<HdPackCondition>(vmirror));
|
|
|
|
|
2018-02-25 17:03:06 -05:00
|
|
|
HdPackCondition* invVmirror = new HdPackVerticalMirroringCondition();
|
|
|
|
invVmirror->Name = "!vmirror";
|
|
|
|
_data->Conditions.push_back(unique_ptr<HdPackCondition>(invVmirror));
|
|
|
|
|
2018-02-17 23:44:25 -05:00
|
|
|
HdPackCondition* bgpriority = new HdPackBgPriorityCondition();
|
2017-08-15 20:25:25 -04:00
|
|
|
bgpriority->Name = "bgpriority";
|
|
|
|
_data->Conditions.push_back(unique_ptr<HdPackCondition>(bgpriority));
|
2018-02-25 17:03:06 -05:00
|
|
|
|
|
|
|
HdPackCondition* invBgpriority = new HdPackBgPriorityCondition();
|
|
|
|
invBgpriority->Name = "!bgpriority";
|
|
|
|
_data->Conditions.push_back(unique_ptr<HdPackCondition>(invBgpriority));
|
2021-08-11 09:52:55 +08:00
|
|
|
|
|
|
|
HdPackCondition* sppalette0 = new HdPackSpPalette0Condition();
|
|
|
|
sppalette0->Name = "sppalette0";
|
|
|
|
_data->Conditions.push_back(unique_ptr<HdPackCondition>(sppalette0));
|
|
|
|
|
|
|
|
HdPackCondition* invSppalette0 = new HdPackSpPalette0Condition();
|
|
|
|
invSppalette0->Name = "!sppalette0";
|
|
|
|
_data->Conditions.push_back(unique_ptr<HdPackCondition>(invSppalette0));
|
|
|
|
|
|
|
|
HdPackCondition* sppalette1 = new HdPackSpPalette1Condition();
|
|
|
|
sppalette1->Name = "sppalette1";
|
|
|
|
_data->Conditions.push_back(unique_ptr<HdPackCondition>(sppalette1));
|
|
|
|
|
|
|
|
HdPackCondition* invSppalette1 = new HdPackSpPalette1Condition();
|
|
|
|
invSppalette1->Name = "!sppalette1";
|
|
|
|
_data->Conditions.push_back(unique_ptr<HdPackCondition>(invSppalette1));
|
|
|
|
|
|
|
|
HdPackCondition* sppalette2 = new HdPackSpPalette2Condition();
|
|
|
|
sppalette2->Name = "sppalette2";
|
|
|
|
_data->Conditions.push_back(unique_ptr<HdPackCondition>(sppalette2));
|
|
|
|
|
|
|
|
HdPackCondition* invSppalette2 = new HdPackSpPalette2Condition();
|
|
|
|
invSppalette2->Name = "!sppalette2";
|
|
|
|
_data->Conditions.push_back(unique_ptr<HdPackCondition>(invSppalette2));
|
|
|
|
|
|
|
|
HdPackCondition* sppalette3 = new HdPackSpPalette3Condition();
|
|
|
|
sppalette3->Name = "sppalette3";
|
|
|
|
_data->Conditions.push_back(unique_ptr<HdPackCondition>(sppalette3));
|
|
|
|
|
|
|
|
HdPackCondition* invSppalette3 = new HdPackSpPalette3Condition();
|
|
|
|
invSppalette3->Name = "!sppalette3";
|
|
|
|
_data->Conditions.push_back(unique_ptr<HdPackCondition>(invSppalette3));
|
2017-08-15 20:25:25 -04:00
|
|
|
}
|
|
|
|
|
2017-08-12 21:21:55 -04:00
|
|
|
void HdPackLoader::ProcessOverscanTag(vector<string> &tokens)
|
|
|
|
{
|
|
|
|
OverscanDimensions overscan;
|
|
|
|
overscan.Top = std::stoi(tokens[0]);
|
|
|
|
overscan.Right = std::stoi(tokens[1]);
|
|
|
|
overscan.Bottom = std::stoi(tokens[2]);
|
|
|
|
overscan.Left = std::stoi(tokens[3]);
|
|
|
|
_data->HasOverscanConfig = true;
|
|
|
|
_data->Overscan = overscan;
|
|
|
|
}
|
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
void HdPackLoader::ProcessPatchTag(vector<string> &tokens)
|
|
|
|
{
|
2018-02-17 23:44:25 -05:00
|
|
|
checkConstraint(tokens.size() >= 2, "[HDPack] Patch tag requires more parameters");
|
|
|
|
checkConstraint(tokens[1].size() == 40, string("[HDPack] Invalid SHA1 hash for patch (" + tokens[0] + "): " + tokens[1]));
|
|
|
|
|
2017-07-30 09:03:54 -04:00
|
|
|
vector<uint8_t> fileData;
|
|
|
|
if(!LoadFile(tokens[0], fileData)) {
|
2017-06-28 19:00:08 -04:00
|
|
|
MessageManager::Log(string("[HDPack] Patch file not found: " + tokens[1]));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-19 23:08:23 -05:00
|
|
|
std::transform(tokens[1].begin(), tokens[1].end(), tokens[1].begin(), ::toupper);
|
2017-07-30 09:03:54 -04:00
|
|
|
if(_loadFromZip) {
|
|
|
|
_data->PatchesByHash[tokens[1]] = VirtualFile(_hdPackFolder, tokens[0]);
|
|
|
|
} else {
|
|
|
|
_data->PatchesByHash[tokens[1]] = FolderUtilities::CombinePath(_hdPackFolder, tokens[0]);
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void HdPackLoader::ProcessTileTag(vector<string> &tokens, vector<HdPackCondition*> conditions)
|
|
|
|
{
|
|
|
|
HdPackTileInfo *tileInfo = new HdPackTileInfo();
|
2017-07-25 19:46:25 -04:00
|
|
|
size_t index = 0;
|
2017-06-28 19:00:08 -04:00
|
|
|
if(_data->Version < 100) {
|
|
|
|
tileInfo->TileIndex = std::stoi(tokens[index++]);
|
|
|
|
tileInfo->BitmapIndex = std::stoi(tokens[index++]);
|
|
|
|
tileInfo->PaletteColors = std::stoi(tokens[index + 2]) | (std::stoi(tokens[index + 1]) << 8) | (std::stoi(tokens[index]) << 16);
|
|
|
|
index += 3;
|
|
|
|
} else {
|
|
|
|
tileInfo->BitmapIndex = std::stoi(tokens[index++]);
|
|
|
|
string tileData = tokens[index++];
|
|
|
|
if(tileData.size() >= 32) {
|
|
|
|
//CHR RAM tile, read the tile data
|
|
|
|
for(int i = 0; i < 16; i++) {
|
|
|
|
tileInfo->TileData[i] = HexUtilities::FromHex(tileData.substr(i * 2, 2));
|
|
|
|
}
|
|
|
|
tileInfo->IsChrRamTile = true;
|
2018-03-24 11:22:43 -04:00
|
|
|
tileInfo->TileIndex = -1;
|
2017-06-28 19:00:08 -04:00
|
|
|
} else {
|
2018-09-15 09:59:17 -04:00
|
|
|
if(_data->Version <= 102) {
|
|
|
|
tileInfo->TileIndex = std::stoi(tileData);
|
|
|
|
} else {
|
|
|
|
tileInfo->TileIndex = HexUtilities::FromHex(tileData);
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
tileInfo->IsChrRamTile = false;
|
|
|
|
}
|
|
|
|
tileInfo->PaletteColors = HexUtilities::FromHex(tokens[index++]);
|
|
|
|
}
|
|
|
|
tileInfo->X = std::stoi(tokens[index++]);
|
|
|
|
tileInfo->Y = std::stoi(tokens[index++]);
|
|
|
|
tileInfo->Conditions = conditions;
|
2018-02-17 23:44:25 -05:00
|
|
|
tileInfo->ForceDisableCache = false;
|
|
|
|
for(HdPackCondition* condition : conditions) {
|
|
|
|
if(dynamic_cast<HdPackSpriteNearbyCondition*>(condition)) {
|
|
|
|
tileInfo->ForceDisableCache = true;
|
|
|
|
break;
|
|
|
|
} else if(dynamic_cast<HdPackTileNearbyCondition*>(condition)) {
|
|
|
|
HdPackTileNearbyCondition* tileNearby = dynamic_cast<HdPackTileNearbyCondition*>(condition);
|
|
|
|
if(tileNearby->TileX % 8 > 0 || tileNearby->TileY % 8 > 0) {
|
|
|
|
tileInfo->ForceDisableCache = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
|
2019-12-20 13:53:13 -05:00
|
|
|
if(_data->Version >= 105) {
|
|
|
|
tileInfo->Brightness = (int)(std::stof(tokens[index++]) * 255);
|
|
|
|
} else if(_data->Version > 0) {
|
2017-06-28 19:00:08 -04:00
|
|
|
tileInfo->Brightness = (uint8_t)(std::stof(tokens[index++]) * 255);
|
|
|
|
} else {
|
|
|
|
tileInfo->Brightness = 255;
|
|
|
|
}
|
|
|
|
tileInfo->DefaultTile = (tokens[index++] == "Y");
|
|
|
|
|
|
|
|
//For CHR ROM tiles, the ID is just the bank number in chr rom (4k banks)
|
|
|
|
tileInfo->ChrBankId = tileInfo->TileIndex / 256;
|
|
|
|
|
|
|
|
if(_data->Version < 100) {
|
|
|
|
if(tokens.size() >= 24) {
|
|
|
|
//CHR RAM tile, read the tile data
|
|
|
|
for(int i = 0; i < 16; i++) {
|
|
|
|
tileInfo->TileData[i] = std::stoi(tokens[index++]);
|
|
|
|
}
|
|
|
|
tileInfo->IsChrRamTile = true;
|
|
|
|
} else {
|
|
|
|
tileInfo->IsChrRamTile = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if(tileInfo->IsChrRamTile && tokens.size() > index) {
|
|
|
|
tileInfo->ChrBankId = std::stoul(tokens[index++]);
|
|
|
|
}
|
|
|
|
if(tileInfo->IsChrRamTile && tokens.size() > index) {
|
|
|
|
tileInfo->TileIndex = std::stoi(tokens[index++]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-17 23:44:25 -05:00
|
|
|
checkConstraint(tileInfo->BitmapIndex < _hdNesBitmaps.size(), "[HDPack] Invalid bitmap index: " + std::to_string(tileInfo->BitmapIndex));
|
2017-06-28 19:00:08 -04:00
|
|
|
|
|
|
|
HdPackBitmapInfo &bitmapInfo = _hdNesBitmaps[tileInfo->BitmapIndex];
|
|
|
|
uint32_t bitmapOffset = tileInfo->Y * bitmapInfo.Width + tileInfo->X;
|
|
|
|
uint32_t* pngData = (uint32_t*)bitmapInfo.PixelData.data();
|
2018-03-07 21:56:10 -05:00
|
|
|
|
|
|
|
tileInfo->HdTileData.resize(64 * _data->Scale * _data->Scale);
|
2017-06-28 19:00:08 -04:00
|
|
|
for(uint32_t y = 0; y < 8 * _data->Scale; y++) {
|
2018-03-07 21:56:10 -05:00
|
|
|
memcpy(tileInfo->HdTileData.data() + (y * 8 * _data->Scale), pngData + bitmapOffset, 8 * _data->Scale * sizeof(uint32_t));
|
|
|
|
bitmapOffset += bitmapInfo.Width;
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
2017-07-25 19:46:25 -04:00
|
|
|
tileInfo->UpdateFlags();
|
2017-06-28 19:00:08 -04:00
|
|
|
|
|
|
|
_data->Tiles.push_back(unique_ptr<HdPackTileInfo>(tileInfo));
|
|
|
|
}
|
|
|
|
|
|
|
|
void HdPackLoader::ProcessOptionTag(vector<string> &tokens)
|
|
|
|
{
|
|
|
|
for(string token : tokens) {
|
|
|
|
if(token == "disableSpriteLimit") {
|
|
|
|
_data->OptionFlags |= (int)HdPackOptions::NoSpriteLimit;
|
2017-08-19 16:46:57 -04:00
|
|
|
} else if(token == "alternateRegisterRange") {
|
|
|
|
_data->OptionFlags |= (int)HdPackOptions::AlternateRegisterRange;
|
2018-02-17 23:44:25 -05:00
|
|
|
} else if(token == "disableCache") {
|
|
|
|
_data->OptionFlags |= (int)HdPackOptions::DisableCache;
|
2019-12-20 13:53:13 -05:00
|
|
|
} else if(token == "disableOriginalTiles") {
|
|
|
|
_data->OptionFlags |= (int)HdPackOptions::DontRenderOriginalTiles;
|
2018-02-17 23:44:25 -05:00
|
|
|
} else {
|
|
|
|
MessageManager::Log("[HDPack] Invalid option: " + token);
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-25 17:03:06 -05:00
|
|
|
void HdPackLoader::ProcessConditionTag(vector<string> &tokens, bool createInvertedCondition)
|
2017-06-28 19:00:08 -04:00
|
|
|
{
|
2018-02-17 23:44:25 -05:00
|
|
|
checkConstraint(tokens.size() >= 4, "[HDPack] Condition tag should contain at least 4 parameters");
|
2018-02-25 17:03:06 -05:00
|
|
|
checkConstraint(tokens[0].size() > 0, "[HDPack] Condition name may not be empty");
|
|
|
|
checkConstraint(tokens[0].find_last_of('!') == string::npos, "[HDPack] Condition name may not contain '!' characters");
|
2017-09-06 22:05:04 -04:00
|
|
|
|
2018-02-17 23:44:25 -05:00
|
|
|
unique_ptr<HdPackCondition> condition;
|
2018-02-25 17:03:06 -05:00
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
if(tokens[1] == "tileAtPosition") {
|
2018-02-17 23:44:25 -05:00
|
|
|
condition.reset(new HdPackTileAtPositionCondition());
|
2017-06-28 19:00:08 -04:00
|
|
|
} else if(tokens[1] == "tileNearby") {
|
2018-02-17 23:44:25 -05:00
|
|
|
condition.reset(new HdPackTileNearbyCondition());
|
2017-06-28 19:00:08 -04:00
|
|
|
} else if(tokens[1] == "spriteAtPosition") {
|
2018-02-17 23:44:25 -05:00
|
|
|
condition.reset(new HdPackSpriteAtPositionCondition());
|
2017-06-28 19:00:08 -04:00
|
|
|
} else if(tokens[1] == "spriteNearby") {
|
2018-02-17 23:44:25 -05:00
|
|
|
condition.reset(new HdPackSpriteNearbyCondition());
|
2018-03-14 23:25:06 -04:00
|
|
|
} else if(tokens[1] == "memoryCheck" || tokens[1] == "ppuMemoryCheck") {
|
2018-02-17 23:44:25 -05:00
|
|
|
condition.reset(new HdPackMemoryCheckCondition());
|
2018-03-14 23:25:06 -04:00
|
|
|
} else if(tokens[1] == "memoryCheckConstant" || tokens[1] == "ppuMemoryCheckConstant") {
|
2018-02-17 23:44:25 -05:00
|
|
|
condition.reset(new HdPackMemoryCheckConstantCondition());
|
|
|
|
} else if(tokens[1] == "frameRange") {
|
|
|
|
condition.reset(new HdPackFrameRangeCondition());
|
Add sprite frame range condition
A new condition named "spriteFrameRange" is added. It works like frameRange except it follows frame counters assigned to each sprite. Frame counter picks up the nearest frame counter within 6x6 pixels from the last frame and resets if graphics, palette, bg priority or orientation has changed. The condition can by used by sprite tiles only. For example:
<condition>myCondition,spriteFrameRange,301,60
[myCondition]<tile>0,1001,FF0F3600,8,0,1,N
2021-04-15 19:54:01 +08:00
|
|
|
} else if(tokens[1] == "spriteFrameRange") {
|
|
|
|
condition.reset(new HdPackSpriteFrameRangeCondition());
|
2017-09-06 22:27:31 -04:00
|
|
|
} else {
|
|
|
|
MessageManager::Log("[HDPack] Invalid condition type: " + tokens[1]);
|
|
|
|
return;
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
2018-02-17 23:44:25 -05:00
|
|
|
tokens[0].erase(tokens[0].find_last_not_of(" \n\r\t") + 1);
|
|
|
|
condition->Name = tokens[0];
|
|
|
|
|
2018-02-25 17:03:06 -05:00
|
|
|
if(createInvertedCondition) {
|
|
|
|
condition->Name = "!" + condition->Name;
|
|
|
|
}
|
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
int index = 2;
|
2018-02-17 23:44:25 -05:00
|
|
|
if(dynamic_cast<HdPackBaseTileCondition*>(condition.get())) {
|
|
|
|
checkConstraint(tokens.size() >= 6, "[HDPack] Condition tag should contain at least 6 parameters");
|
|
|
|
|
|
|
|
int x = std::stoi(tokens[index++]);
|
|
|
|
int y = std::stoi(tokens[index++]);
|
|
|
|
string token = tokens[index++];
|
|
|
|
int32_t tileIndex = -1;
|
|
|
|
string tileData;
|
|
|
|
if(token.size() == 32) {
|
|
|
|
tileData = token;
|
|
|
|
} else {
|
2018-12-12 20:46:23 -05:00
|
|
|
if(_data->Version < 104) {
|
|
|
|
tileIndex = std::stoi(token);
|
|
|
|
} else {
|
|
|
|
//Tile indexes are stored as hex starting from version 104+
|
|
|
|
tileIndex = HexUtilities::FromHex(token);
|
|
|
|
}
|
2018-02-17 23:44:25 -05:00
|
|
|
}
|
|
|
|
uint32_t palette = HexUtilities::FromHex(tokens[index++]);
|
|
|
|
|
|
|
|
((HdPackBaseTileCondition*)condition.get())->Initialize(x, y, palette, tileIndex, tileData);
|
|
|
|
} else if(dynamic_cast<HdPackBaseMemoryCondition*>(condition.get())) {
|
|
|
|
checkConstraint(_data->Version >= 101, "[HDPack] This feature requires version 101+ of HD Packs");
|
|
|
|
checkConstraint(tokens.size() >= 5, "[HDPack] Condition tag should contain at least 5 parameters");
|
|
|
|
|
2018-03-14 23:25:06 -04:00
|
|
|
bool usePpuMemory = tokens[1].substr(0, 3) == "ppu";
|
|
|
|
uint32_t operandA = HexUtilities::FromHex(tokens[index++]);
|
|
|
|
|
|
|
|
if(usePpuMemory) {
|
2018-06-25 16:21:15 -04:00
|
|
|
checkConstraint(operandA <= 0x3FFF, "[HDPack] Out of range memoryCheck operand");
|
2018-03-14 23:25:06 -04:00
|
|
|
operandA |= HdPackBaseMemoryCondition::PpuMemoryMarker;
|
|
|
|
} else {
|
2018-06-25 16:21:15 -04:00
|
|
|
checkConstraint(operandA <= 0xFFFF, "[HDPack] Out of range memoryCheck operand");
|
2018-03-14 23:25:06 -04:00
|
|
|
}
|
2018-02-17 23:44:25 -05:00
|
|
|
|
|
|
|
HdPackConditionOperator op;
|
|
|
|
string opString = tokens[index++];
|
|
|
|
if(opString == "==") {
|
|
|
|
op = HdPackConditionOperator::Equal;
|
|
|
|
} else if(opString == "!=") {
|
|
|
|
op = HdPackConditionOperator::NotEqual;
|
|
|
|
} else if(opString == ">") {
|
|
|
|
op = HdPackConditionOperator::GreaterThan;
|
|
|
|
} else if(opString == "<") {
|
|
|
|
op = HdPackConditionOperator::LowerThan;
|
2018-03-25 17:39:17 -04:00
|
|
|
} else if(opString == "<=") {
|
|
|
|
op = HdPackConditionOperator::LowerThanOrEqual;
|
|
|
|
} else if(opString == ">=") {
|
|
|
|
op = HdPackConditionOperator::GreaterThanOrEqual;
|
2018-03-24 11:22:43 -04:00
|
|
|
} else {
|
|
|
|
checkConstraint(false, "[HDPack] Invalid operator.");
|
2018-02-17 23:44:25 -05:00
|
|
|
}
|
|
|
|
|
2018-03-14 23:25:06 -04:00
|
|
|
uint32_t operandB = HexUtilities::FromHex(tokens[index++]);
|
2018-09-15 09:49:02 -04:00
|
|
|
uint32_t mask = 0xFF;
|
|
|
|
if(tokens.size() > 5 && _data->Version >= 103) {
|
|
|
|
checkConstraint(operandB <= 0xFF, "[HDPack] Out of range memoryCheck mask");
|
|
|
|
mask = HexUtilities::FromHex(tokens[index++]);
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
|
2018-02-17 23:44:25 -05:00
|
|
|
if(dynamic_cast<HdPackMemoryCheckCondition*>(condition.get())) {
|
2018-03-14 23:25:06 -04:00
|
|
|
if(usePpuMemory) {
|
2018-06-25 16:21:15 -04:00
|
|
|
checkConstraint(operandB <= 0x3FFF, "[HDPack] Out of range memoryCheck operand");
|
2018-03-14 23:25:06 -04:00
|
|
|
operandB |= HdPackBaseMemoryCondition::PpuMemoryMarker;
|
|
|
|
} else {
|
2018-06-25 16:21:15 -04:00
|
|
|
checkConstraint(operandB <= 0xFFFF, "[HDPack] Out of range memoryCheck operand");
|
2018-03-14 23:25:06 -04:00
|
|
|
}
|
|
|
|
_data->WatchedMemoryAddresses.emplace(operandB);
|
2018-02-17 23:44:25 -05:00
|
|
|
} else if(dynamic_cast<HdPackMemoryCheckConstantCondition*>(condition.get())) {
|
2018-06-25 16:21:15 -04:00
|
|
|
checkConstraint(operandB <= 0xFF, "[HDPack] Out of range memoryCheckConstant operand");
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
2018-03-14 23:25:06 -04:00
|
|
|
_data->WatchedMemoryAddresses.emplace(operandA);
|
2018-09-15 09:49:02 -04:00
|
|
|
((HdPackBaseMemoryCondition*)condition.get())->Initialize(operandA, op, operandB, (uint8_t)mask);
|
2018-02-17 23:44:25 -05:00
|
|
|
} else if(dynamic_cast<HdPackFrameRangeCondition*>(condition.get())) {
|
|
|
|
checkConstraint(_data->Version >= 101, "[HDPack] This feature requires version 101+ of HD Packs");
|
|
|
|
checkConstraint(tokens.size() >= 4, "[HDPack] Condition tag should contain at least 4 parameters");
|
2017-06-28 19:00:08 -04:00
|
|
|
|
2018-06-25 16:21:15 -04:00
|
|
|
int32_t operandA;
|
|
|
|
int32_t operandB;
|
|
|
|
if(_data->Version == 101) {
|
|
|
|
operandA = HexUtilities::FromHex(tokens[index++]);
|
|
|
|
operandB = HexUtilities::FromHex(tokens[index++]);
|
|
|
|
} else {
|
|
|
|
//Version 102+
|
|
|
|
operandA = std::stoi(tokens[index++]);
|
|
|
|
operandB = std::stoi(tokens[index++]);
|
|
|
|
}
|
2018-02-17 23:44:25 -05:00
|
|
|
|
2018-06-25 16:21:15 -04:00
|
|
|
checkConstraint(operandA >= 0 && operandA <= 0xFFFF, "[HDPack] Out of range frameRange operand");
|
2018-02-17 23:44:25 -05:00
|
|
|
checkConstraint(operandB >= 0 && operandB <= 0xFFFF, "[HDPack] Out of range frameRange operand");
|
|
|
|
|
|
|
|
((HdPackFrameRangeCondition*)condition.get())->Initialize(operandA, operandB);
|
|
|
|
}
|
Add sprite frame range condition
A new condition named "spriteFrameRange" is added. It works like frameRange except it follows frame counters assigned to each sprite. Frame counter picks up the nearest frame counter within 6x6 pixels from the last frame and resets if graphics, palette, bg priority or orientation has changed. The condition can by used by sprite tiles only. For example:
<condition>myCondition,spriteFrameRange,301,60
[myCondition]<tile>0,1001,FF0F3600,8,0,1,N
2021-04-15 19:54:01 +08:00
|
|
|
else if (dynamic_cast<HdPackSpriteFrameRangeCondition*>(condition.get())) {
|
|
|
|
checkConstraint(_data->Version >= 101, "[HDPack] This feature requires version 101+ of HD Packs");
|
|
|
|
checkConstraint(tokens.size() >= 4, "[HDPack] Condition tag should contain at least 4 parameters");
|
|
|
|
|
|
|
|
int32_t operandA;
|
|
|
|
int32_t operandB;
|
|
|
|
if (_data->Version == 101) {
|
|
|
|
operandA = HexUtilities::FromHex(tokens[index++]);
|
|
|
|
operandB = HexUtilities::FromHex(tokens[index++]);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
//Version 102+
|
|
|
|
operandA = std::stoi(tokens[index++]);
|
|
|
|
operandB = std::stoi(tokens[index++]);
|
|
|
|
}
|
|
|
|
|
|
|
|
checkConstraint(operandA >= 0 && operandA <= 0xFFFF, "[HDPack] Out of range spriteFrameRange operand");
|
|
|
|
checkConstraint(operandB >= 0 && operandB <= 0xFFFF, "[HDPack] Out of range spriteFrameRange operand");
|
|
|
|
|
|
|
|
((HdPackSpriteFrameRangeCondition*)condition.get())->Initialize(operandA, operandB);
|
|
|
|
}
|
2018-02-17 23:44:25 -05:00
|
|
|
|
|
|
|
HdPackCondition *cond = condition.get();
|
|
|
|
condition.release();
|
|
|
|
_data->Conditions.emplace_back(unique_ptr<HdPackCondition>(cond));
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void HdPackLoader::ProcessBackgroundTag(vector<string> &tokens, vector<HdPackCondition*> conditions)
|
|
|
|
{
|
2018-02-17 23:44:25 -05:00
|
|
|
checkConstraint(tokens.size() >= 2, "[HDPack] Background tag should contain at least 2 parameters");
|
2017-07-30 09:03:54 -04:00
|
|
|
HdBackgroundFileData* bgFileData = nullptr;
|
2017-06-28 19:00:08 -04:00
|
|
|
for(unique_ptr<HdBackgroundFileData> &bgData : _data->BackgroundFileData) {
|
|
|
|
if(bgData->PngName == tokens[0]) {
|
2017-07-30 09:03:54 -04:00
|
|
|
bgFileData = bgData.get();
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-30 09:03:54 -04:00
|
|
|
if(!bgFileData) {
|
2017-06-28 19:00:08 -04:00
|
|
|
vector<uint8_t> pixelData;
|
|
|
|
uint32_t width, height;
|
2017-07-30 09:03:54 -04:00
|
|
|
vector<uint8_t> fileContent;
|
|
|
|
if(LoadFile(tokens[0], fileContent)) {
|
|
|
|
if(PNGHelper::ReadPNG(fileContent, pixelData, width, height)) {
|
|
|
|
_data->BackgroundFileData.push_back(unique_ptr<HdBackgroundFileData>(new HdBackgroundFileData()));
|
|
|
|
bgFileData = _data->BackgroundFileData.back().get();
|
2018-06-19 20:43:16 -04:00
|
|
|
bgFileData->PixelData.resize(pixelData.size() / 4);
|
|
|
|
memcpy(bgFileData->PixelData.data(), pixelData.data(), bgFileData->PixelData.size() * sizeof(bgFileData->PixelData[0]));
|
2020-02-01 09:52:49 -05:00
|
|
|
PremultiplyAlpha(bgFileData->PixelData);
|
|
|
|
|
2017-07-30 09:03:54 -04:00
|
|
|
bgFileData->Width = width;
|
|
|
|
bgFileData->Height = height;
|
|
|
|
bgFileData->PngName = tokens[0];
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
HdBackgroundInfo backgroundInfo;
|
2017-07-30 09:03:54 -04:00
|
|
|
if(bgFileData) {
|
|
|
|
backgroundInfo.Data = bgFileData;
|
2019-12-20 13:53:13 -05:00
|
|
|
if (_data->Version >= 105) {
|
|
|
|
backgroundInfo.Brightness = (int)(std::stof(tokens[1]) * 255);
|
|
|
|
} else {
|
|
|
|
backgroundInfo.Brightness = (uint8_t)(std::stof(tokens[1]) * 255);
|
|
|
|
}
|
2018-02-17 23:44:25 -05:00
|
|
|
backgroundInfo.HorizontalScrollRatio = 0;
|
|
|
|
backgroundInfo.VerticalScrollRatio = 0;
|
2020-05-08 20:08:41 -04:00
|
|
|
backgroundInfo.Priority = 10;
|
2019-12-20 13:53:13 -05:00
|
|
|
backgroundInfo.Left = 0;
|
|
|
|
backgroundInfo.Top = 0;
|
2018-02-17 23:44:25 -05:00
|
|
|
|
|
|
|
for(HdPackCondition* condition : conditions) {
|
|
|
|
if(
|
|
|
|
!dynamic_cast<HdPackTileAtPositionCondition*>(condition) &&
|
|
|
|
!dynamic_cast<HdPackSpriteAtPositionCondition*>(condition) &&
|
|
|
|
!dynamic_cast<HdPackMemoryCheckCondition*>(condition) &&
|
|
|
|
!dynamic_cast<HdPackMemoryCheckConstantCondition*>(condition) &&
|
|
|
|
!dynamic_cast<HdPackFrameRangeCondition*>(condition)
|
|
|
|
) {
|
2017-06-28 19:00:08 -04:00
|
|
|
MessageManager::Log("[HDPack] Invalid condition type for background: " + tokens[0]);
|
2018-02-17 23:44:25 -05:00
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
backgroundInfo.Conditions.push_back(condition);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(tokens.size() > 2) {
|
|
|
|
checkConstraint(_data->Version >= 101, "[HDPack] This feature requires version 101+ of HD Packs");
|
|
|
|
|
|
|
|
backgroundInfo.HorizontalScrollRatio = std::stof(tokens[2]);
|
|
|
|
if(tokens.size() > 3) {
|
|
|
|
backgroundInfo.VerticalScrollRatio = std::stof(tokens[3]);
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
2018-06-19 22:17:00 -04:00
|
|
|
if(tokens.size() > 4) {
|
|
|
|
checkConstraint(_data->Version >= 102, "[HDPack] This feature requires version 102+ of HD Packs");
|
2020-05-08 20:08:41 -04:00
|
|
|
if(_data->Version >= 106) {
|
|
|
|
backgroundInfo.Priority = std::stoi(tokens[4]);
|
|
|
|
checkConstraint(backgroundInfo.Priority >= 0 && backgroundInfo.Priority < 40, "[HDPack] Invalid background priority value");
|
|
|
|
} else {
|
|
|
|
backgroundInfo.Priority = tokens[4] == "Y" ? 0 : 10;
|
|
|
|
}
|
2018-06-19 22:17:00 -04:00
|
|
|
}
|
2019-12-20 13:53:13 -05:00
|
|
|
if(tokens.size() > 6) {
|
|
|
|
checkConstraint(_data->Version >= 105, "[HDPack] This feature requires version 105+ of HD Packs");
|
|
|
|
backgroundInfo.Left = std::max(0, std::stoi(tokens[5]));
|
|
|
|
backgroundInfo.Top = std::max(0, std::stoi(tokens[6]));
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
_data->Backgrounds.push_back(backgroundInfo);
|
|
|
|
} else {
|
|
|
|
MessageManager::Log("[HDPack] Error while loading background: " + tokens[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-19 16:46:57 -04:00
|
|
|
int HdPackLoader::ProcessSoundTrack(string albumString, string trackString, string filename)
|
|
|
|
{
|
|
|
|
int album = std::stoi(albumString);
|
|
|
|
if(album < 0 || album > 255) {
|
|
|
|
MessageManager::Log("[HDPack] Invalid album value: " + albumString);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int track = std::stoi(trackString);
|
|
|
|
if(track < 0 || track > 255) {
|
|
|
|
MessageManager::Log("[HDPack] Invalid track value: " + trackString);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!CheckFile(filename)) {
|
|
|
|
MessageManager::Log("[HDPack] OGG file not found: " + filename);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return album * 256 + track;
|
|
|
|
}
|
|
|
|
|
|
|
|
void HdPackLoader::ProcessBgmTag(vector<string> &tokens)
|
|
|
|
{
|
|
|
|
int trackId = ProcessSoundTrack(tokens[0], tokens[1], tokens[2]);
|
|
|
|
if(trackId >= 0) {
|
|
|
|
if(_loadFromZip) {
|
|
|
|
VirtualFile file(_hdPackFolder, tokens[2]);
|
2020-12-20 22:26:12 +08:00
|
|
|
_data->BgmFilesById[trackId].File = file;
|
2017-08-19 16:46:57 -04:00
|
|
|
} else {
|
2020-12-20 22:26:12 +08:00
|
|
|
_data->BgmFilesById[trackId].File = FolderUtilities::CombinePath(_hdPackFolder, tokens[2]);
|
2017-08-19 16:46:57 -04:00
|
|
|
}
|
2020-12-20 22:26:12 +08:00
|
|
|
_data->BgmFilesById[trackId].LoopPoint = 0;
|
|
|
|
_data->BgmFilesById[trackId].PlaybackOptions = -1;
|
|
|
|
_data->BgmFilesById[trackId].Volume = -1;
|
|
|
|
if (tokens.size() >= 4) {
|
2020-11-15 01:59:13 +08:00
|
|
|
stringstream pt(tokens[3]);
|
|
|
|
uint32_t loopPoint;
|
|
|
|
pt >> loopPoint;
|
2020-12-20 22:26:12 +08:00
|
|
|
_data->BgmFilesById[trackId].LoopPoint = loopPoint;
|
|
|
|
if (tokens.size() >= 5) {
|
|
|
|
stringstream pt(tokens[4]);
|
|
|
|
int16_t pbo;
|
|
|
|
pt >> pbo;
|
|
|
|
_data->BgmFilesById[trackId].PlaybackOptions = pbo;
|
|
|
|
if (tokens.size() >= 6) {
|
|
|
|
stringstream pt(tokens[5]);
|
|
|
|
int16_t vol;
|
|
|
|
pt >> vol;
|
|
|
|
_data->BgmFilesById[trackId].Volume = vol;
|
|
|
|
}
|
|
|
|
}
|
2020-11-15 17:10:55 +08:00
|
|
|
}
|
2017-08-19 16:46:57 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HdPackLoader::ProcessSfxTag(vector<string> &tokens)
|
|
|
|
{
|
|
|
|
int trackId = ProcessSoundTrack(tokens[0], tokens[1], tokens[2]);
|
|
|
|
if(trackId >= 0) {
|
|
|
|
if(_loadFromZip) {
|
|
|
|
VirtualFile file(_hdPackFolder, tokens[2]);
|
|
|
|
_data->SfxFilesById[trackId] = file;
|
|
|
|
} else {
|
|
|
|
_data->SfxFilesById[trackId] = FolderUtilities::CombinePath(_hdPackFolder, tokens[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
vector<HdPackCondition*> HdPackLoader::ParseConditionString(string conditionString, vector<unique_ptr<HdPackCondition>> &conditions)
|
|
|
|
{
|
|
|
|
vector<string> conditionNames = StringUtilities::Split(conditionString, '&');
|
|
|
|
|
|
|
|
vector<HdPackCondition*> result;
|
|
|
|
for(string conditionName : conditionNames) {
|
|
|
|
conditionName.erase(conditionName.find_last_not_of(" \n\r\t") + 1);
|
|
|
|
|
|
|
|
bool found = false;
|
|
|
|
for(unique_ptr<HdPackCondition> &condition : conditions) {
|
|
|
|
if(conditionName == condition->Name) {
|
|
|
|
result.push_back(condition.get());
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!found) {
|
|
|
|
MessageManager::Log("[HDPack] Condition not found: " + conditionName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void HdPackLoader::LoadCustomPalette()
|
|
|
|
{
|
2017-07-30 09:03:54 -04:00
|
|
|
vector<uint8_t> fileData;
|
|
|
|
if(LoadFile("palette.dat", fileData)) {
|
2017-06-28 19:00:08 -04:00
|
|
|
vector<uint32_t> paletteData;
|
|
|
|
|
2017-08-06 11:55:23 -04:00
|
|
|
for(size_t i = 0; i < fileData.size(); i+= 3){
|
2017-07-30 09:03:54 -04:00
|
|
|
paletteData.push_back(0xFF000000 | (fileData[i] << 16) | (fileData[i+1] << 8) | fileData[i+2]);
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if(paletteData.size() == 0x40) {
|
|
|
|
_data->Palette = paletteData;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HdPackLoader::InitializeHdPack()
|
|
|
|
{
|
|
|
|
for(unique_ptr<HdPackTileInfo> &tileInfo : _data->Tiles) {
|
|
|
|
auto tiles = _data->TileByKey.find(tileInfo->GetKey(false));
|
|
|
|
if(tiles == _data->TileByKey.end()) {
|
|
|
|
_data->TileByKey[tileInfo->GetKey(false)] = vector<HdPackTileInfo*>();
|
|
|
|
}
|
|
|
|
_data->TileByKey[tileInfo->GetKey(false)].push_back(tileInfo.get());
|
|
|
|
|
|
|
|
if(tileInfo->DefaultTile) {
|
|
|
|
auto tiles = _data->TileByKey.find(tileInfo->GetKey(true));
|
|
|
|
if(tiles == _data->TileByKey.end()) {
|
2017-08-07 22:52:27 -04:00
|
|
|
_data->TileByKey[tileInfo->GetKey(true)] = vector<HdPackTileInfo*>();
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
_data->TileByKey[tileInfo->GetKey(true)].push_back(tileInfo.get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|