mirror of
https://github.com/Fluorohydride/ygopro.git
synced 2026-10-18 22:51:17 +08:00
605 lines
18 KiB
C++
605 lines
18 KiB
C++
#include "data_manager.h"
|
|
#include "game.h"
|
|
#include "client_card.h"
|
|
|
|
namespace ygo {
|
|
|
|
namespace{
|
|
unsigned char scriptBuffer[0x100000]{};
|
|
}
|
|
|
|
DataManager dataManager;
|
|
|
|
static const char SELECT_STMT[] = "SELECT datas.id, datas.ot, datas.alias, datas.setcode, datas.type, datas.atk, datas.def, datas.level, datas.race, datas.attribute, datas.category,"
|
|
" texts.name, texts.desc, texts.str1, texts.str2, texts.str3, texts.str4, texts.str5, texts.str6, texts.str7, texts.str8,"
|
|
" texts.str9, texts.str10, texts.str11, texts.str12, texts.str13, texts.str14, texts.str15, texts.str16 FROM datas INNER JOIN texts ON datas.id = texts.id";
|
|
static constexpr int DATAS_COUNT = 11;
|
|
|
|
static constexpr int CARD_ARTWORK_VERSIONS_OFFSET = 20;
|
|
static inline bool is_alternative(uint32_t code, uint32_t alias) {
|
|
return alias && (alias < code + CARD_ARTWORK_VERSIONS_OFFSET) && (code < alias + CARD_ARTWORK_VERSIONS_OFFSET);
|
|
}
|
|
|
|
DataManager::DataManager() : _datas(32768), _strings(32768) {
|
|
extra_setcode = {
|
|
{8512558u, {0x8f, 0x54, 0x59, 0x82, 0x13a}},
|
|
{55088578u, {0x8f, 0x54, 0x59, 0x82, 0x13a}},
|
|
};
|
|
}
|
|
bool DataManager::ReadDB(sqlite3* pDB) {
|
|
sqlite3_stmt* pStmt = nullptr;
|
|
int texts_offset = DATAS_COUNT;
|
|
if (sqlite3_prepare_v2(pDB, SELECT_STMT, -1, &pStmt, nullptr) != SQLITE_OK)
|
|
return Error(pDB, pStmt);
|
|
wchar_t strBuffer[4096];
|
|
for (int step = sqlite3_step(pStmt); step != SQLITE_DONE; step = sqlite3_step(pStmt)) {
|
|
if (step != SQLITE_ROW)
|
|
return Error(pDB, pStmt);
|
|
uint32_t code = static_cast<uint32_t>(sqlite3_column_int64(pStmt, 0));
|
|
auto& cd = _datas[code];
|
|
cd.code = code;
|
|
cd.ot = sqlite3_column_int(pStmt, 1);
|
|
cd.alias = sqlite3_column_int(pStmt, 2);
|
|
uint64_t setcode = static_cast<uint64_t>(sqlite3_column_int64(pStmt, 3));
|
|
write_setcode(cd.setcode, setcode);
|
|
cd.type = static_cast<decltype(cd.type)>(sqlite3_column_int64(pStmt, 4));
|
|
cd.attack = sqlite3_column_int(pStmt, 5);
|
|
cd.defense = sqlite3_column_int(pStmt, 6);
|
|
if (cd.type & TYPE_LINK) {
|
|
cd.link_marker = cd.defense;
|
|
cd.defense = 0;
|
|
}
|
|
else
|
|
cd.link_marker = 0;
|
|
uint32_t level = static_cast<uint32_t>(sqlite3_column_int64(pStmt, 7));
|
|
cd.level = level & 0xff;
|
|
cd.lscale = (level >> 24) & 0xff;
|
|
cd.rscale = (level >> 16) & 0xff;
|
|
cd.race = static_cast<decltype(cd.race)>(sqlite3_column_int64(pStmt, 8));
|
|
cd.attribute = static_cast<decltype(cd.attribute)>(sqlite3_column_int64(pStmt, 9));
|
|
cd.category = static_cast<decltype(cd.category)>(sqlite3_column_int64(pStmt, 10));
|
|
// rule_code
|
|
if (cd.code == 5405695) {
|
|
cd.rule_code = cd.alias;
|
|
cd.alias = 0;
|
|
}
|
|
else if (cd.alias && !(cd.type & TYPE_TOKEN) && !is_alternative(cd.code, cd.alias)) {
|
|
cd.rule_code = cd.alias;
|
|
cd.alias = 0;
|
|
}
|
|
auto& cs = _strings[code];
|
|
if (const char* text = (const char*)sqlite3_column_text(pStmt, texts_offset + 0)) {
|
|
BufferIO::DecodeUTF8(text, strBuffer);
|
|
cs.name = strBuffer;
|
|
}
|
|
if (const char* text = (const char*)sqlite3_column_text(pStmt, texts_offset + 1)) {
|
|
BufferIO::DecodeUTF8(text, strBuffer);
|
|
cs.text = strBuffer;
|
|
}
|
|
for (int i = 0; i < DESC_COUNT; ++i) {
|
|
if (const char* text = (const char*)sqlite3_column_text(pStmt, (texts_offset + 2) + i)) {
|
|
BufferIO::DecodeUTF8(text, strBuffer);
|
|
cs.desc[i] = strBuffer;
|
|
}
|
|
}
|
|
}
|
|
sqlite3_finalize(pStmt);
|
|
for (auto& entry : _datas) {
|
|
auto& cd = entry.second;
|
|
if (cd.rule_code || !cd.alias || (cd.type & TYPE_TOKEN))
|
|
continue;
|
|
auto it = _datas.find(cd.alias);
|
|
if (it == _datas.end())
|
|
continue;
|
|
cd.rule_code = it->second.rule_code;
|
|
}
|
|
for (const auto& entry : extra_setcode) {
|
|
const auto& code = entry.first;
|
|
const auto& list = entry.second;
|
|
if (list.size() > SIZE_SETCODE || list.empty())
|
|
continue;
|
|
auto it = _datas.find(code);
|
|
if (it == _datas.end())
|
|
continue;
|
|
std::memcpy(it->second.setcode, list.data(), list.size() * sizeof(uint16_t));
|
|
}
|
|
return true;
|
|
}
|
|
bool DataManager::LoadDB(const char* file) {
|
|
auto reader = IrrFileSystem->createAndOpenFile(file);
|
|
if (reader == nullptr) {
|
|
mysnprintf(errmsg, "File does not exist or failed to unzip: %s", file);
|
|
return false;
|
|
}
|
|
|
|
sqlite3* db_handle = nullptr;
|
|
if (sqlite3_open(":memory:", &db_handle) != SQLITE_OK) {
|
|
Error(db_handle, nullptr);
|
|
sqlite3_close(db_handle);
|
|
reader->drop();
|
|
return false;
|
|
}
|
|
|
|
sqlite3_int64 sz = reader->getSize();
|
|
unsigned char* buffer = (unsigned char*)sqlite3_malloc64(sz);
|
|
if (!buffer) {
|
|
Error(db_handle, nullptr);
|
|
sqlite3_close(db_handle);
|
|
reader->drop();
|
|
return false;
|
|
}
|
|
|
|
reader->read(buffer, sz);
|
|
reader->drop();
|
|
// force rollback-journal mode by setting header bytes 18 and 19 to 0x01
|
|
if (sz >= 20 && buffer[18] == 0x02) {
|
|
buffer[18] = 0x01;
|
|
buffer[19] = 0x01;
|
|
}
|
|
int rc = sqlite3_deserialize(
|
|
db_handle,
|
|
nullptr,
|
|
buffer,
|
|
sz,
|
|
sz,
|
|
SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_READONLY
|
|
);
|
|
if (rc != SQLITE_OK) {
|
|
Error(db_handle, nullptr);
|
|
sqlite3_close(db_handle);
|
|
return false;
|
|
}
|
|
bool ret = ReadDB(db_handle);
|
|
sqlite3_close(db_handle);
|
|
return ret;
|
|
}
|
|
bool DataManager::LoadStrings(const char* file) {
|
|
FILE* fp = myfopen(file, "r");
|
|
if(!fp)
|
|
return false;
|
|
char linebuf[TEXT_LINE_SIZE]{};
|
|
while(std::fgets(linebuf, sizeof linebuf, fp)) {
|
|
ReadStringConfLine(linebuf);
|
|
}
|
|
std::fclose(fp);
|
|
return true;
|
|
}
|
|
bool DataManager::LoadStrings(irr::io::IReadFile* reader) {
|
|
char ch{};
|
|
std::string linebuf;
|
|
while (reader->read(&ch, 1)) {
|
|
if (ch == '\0')
|
|
break;
|
|
linebuf.push_back(ch);
|
|
if (ch == '\n' || linebuf.size() >= TEXT_LINE_SIZE - 1) {
|
|
ReadStringConfLine(linebuf.data());
|
|
linebuf.clear();
|
|
}
|
|
}
|
|
reader->drop();
|
|
return true;
|
|
}
|
|
void DataManager::ReadStringConfLine(const char* linebuf) {
|
|
if(linebuf[0] != '!')
|
|
return;
|
|
char strbuf[TEXT_LINE_SIZE]{};
|
|
int value{};
|
|
wchar_t strBuffer[4096]{};
|
|
if (std::sscanf(linebuf, "!%63s", strbuf) != 1)
|
|
return;
|
|
if(!std::strcmp(strbuf, "system")) {
|
|
if (std::sscanf(&linebuf[7], "%d %240[^\n]", &value, strbuf) != 2)
|
|
return;
|
|
BufferIO::DecodeUTF8(strbuf, strBuffer);
|
|
_sysStrings[value] = strBuffer;
|
|
} else if(!std::strcmp(strbuf, "victory")) {
|
|
if (std::sscanf(&linebuf[8], "%x %240[^\n]", &value, strbuf) != 2)
|
|
return;
|
|
BufferIO::DecodeUTF8(strbuf, strBuffer);
|
|
_victoryStrings[value] = strBuffer;
|
|
} else if(!std::strcmp(strbuf, "counter")) {
|
|
if (std::sscanf(&linebuf[8], "%x %240[^\n]", &value, strbuf) != 2)
|
|
return;
|
|
BufferIO::DecodeUTF8(strbuf, strBuffer);
|
|
_counterStrings[value] = strBuffer;
|
|
} else if(!std::strcmp(strbuf, "setname")) {
|
|
//using tab for comment
|
|
if (std::sscanf(&linebuf[8], "%x %240[^\t\n]", &value, strbuf) != 2)
|
|
return;
|
|
BufferIO::DecodeUTF8(strbuf, strBuffer);
|
|
_setnameStrings[value] = strBuffer;
|
|
}
|
|
}
|
|
bool DataManager::Error(sqlite3* pDB, sqlite3_stmt* pStmt) {
|
|
if (const char* msg = sqlite3_errmsg(pDB))
|
|
mysnprintf(errmsg, "sqlite3_errmsg: %s", msg);
|
|
else
|
|
errmsg[0] = '\0';
|
|
sqlite3_finalize(pStmt);
|
|
return false;
|
|
}
|
|
code_pointer DataManager::GetCodePointer(uint32_t code) const {
|
|
return _datas.find(code);
|
|
}
|
|
string_pointer DataManager::GetStringPointer(uint32_t code) const {
|
|
return _strings.find(code);
|
|
}
|
|
bool DataManager::GetData(uint32_t code, CardData* pData) const {
|
|
auto cdit = _datas.find(code);
|
|
if(cdit == _datas.end())
|
|
return false;
|
|
if (pData) {
|
|
std::memcpy(pData, &cdit->second, sizeof(CardData));
|
|
}
|
|
return true;
|
|
}
|
|
bool DataManager::GetString(uint32_t code, CardString* pStr) const {
|
|
auto csit = _strings.find(code);
|
|
if(csit == _strings.end()) {
|
|
pStr->name = unknown_string;
|
|
pStr->text = unknown_string;
|
|
return false;
|
|
}
|
|
*pStr = csit->second;
|
|
return true;
|
|
}
|
|
const wchar_t* DataManager::GetName(uint32_t code) const {
|
|
auto csit = _strings.find(code);
|
|
if(csit == _strings.end())
|
|
return unknown_string;
|
|
if(!csit->second.name.empty())
|
|
return csit->second.name.c_str();
|
|
return unknown_string;
|
|
}
|
|
const wchar_t* DataManager::GetText(uint32_t code) const {
|
|
auto csit = _strings.find(code);
|
|
if(csit == _strings.end())
|
|
return unknown_string;
|
|
if(!csit->second.text.empty())
|
|
return csit->second.text.c_str();
|
|
return unknown_string;
|
|
}
|
|
const wchar_t* DataManager::GetDesc(uint32_t strCode) const {
|
|
if (strCode < (MIN_CARD_ID << 4))
|
|
return GetSysString(strCode);
|
|
unsigned int code = (strCode >> 4) & 0x0fffffff;
|
|
unsigned int offset = strCode & 0xf;
|
|
auto csit = _strings.find(code);
|
|
if(csit == _strings.end())
|
|
return unknown_string;
|
|
if(!csit->second.desc[offset].empty())
|
|
return csit->second.desc[offset].c_str();
|
|
return unknown_string;
|
|
}
|
|
const wchar_t* DataManager::GetMapString(const wstring_map& table, uint32_t code) const {
|
|
auto csit = table.find(code);
|
|
if (csit == table.end())
|
|
return unknown_string;
|
|
return csit->second.c_str();
|
|
}
|
|
const wchar_t* DataManager::GetSysString(uint32_t code) const {
|
|
return GetMapString(_sysStrings, code);
|
|
}
|
|
const wchar_t* DataManager::GetVictoryString(uint32_t code) const {
|
|
return GetMapString(_victoryStrings, code);
|
|
}
|
|
const wchar_t* DataManager::GetCounterName(uint32_t code) const {
|
|
return GetMapString(_counterStrings, code);
|
|
}
|
|
const wchar_t* DataManager::GetSetName(uint32_t code) const {
|
|
return GetMapString(_setnameStrings, code);
|
|
}
|
|
std::vector<uint32_t> DataManager::GetSetCodes(std::wstring setname) const {
|
|
std::vector<uint32_t> matchingCodes;
|
|
for(auto csit = _setnameStrings.begin(); csit != _setnameStrings.end(); ++csit) {
|
|
const std::wstring& setnameString = csit->second;
|
|
size_t start = 0;
|
|
while(start < setnameString.size()) { // handle "setname|another setname"
|
|
auto pos = setnameString.find(L'|', start);
|
|
std::wstring token;
|
|
if(pos == std::wstring::npos)
|
|
token = setnameString.substr(start);
|
|
else
|
|
token = setnameString.substr(start, pos - start);
|
|
if(setname.size() < 2) {
|
|
// exact match for short set names to avoid too many results
|
|
if(token == setname) {
|
|
matchingCodes.push_back(csit->first);
|
|
break;
|
|
}
|
|
} else {
|
|
if(token.find(setname) != std::wstring::npos) {
|
|
matchingCodes.push_back(csit->first);
|
|
break;
|
|
}
|
|
}
|
|
if(pos == std::wstring::npos)
|
|
break;
|
|
start = pos + 1;
|
|
}
|
|
}
|
|
return matchingCodes;
|
|
}
|
|
std::wstring DataManager::GetNumString(int num, bool bracket) const {
|
|
if(!bracket)
|
|
return std::to_wstring(num);
|
|
std::wstring numBuffer{ L"(" };
|
|
numBuffer.append(std::to_wstring(num));
|
|
numBuffer.push_back(L')');
|
|
return numBuffer;
|
|
}
|
|
const wchar_t* DataManager::FormatLocation(int location, int sequence) const {
|
|
if(location == LOCATION_SZONE) {
|
|
if(sequence < 5)
|
|
return GetSysString(1003);
|
|
else if(sequence == 5)
|
|
return GetSysString(1008);
|
|
else
|
|
return GetSysString(1009);
|
|
}
|
|
int string_id = 0;
|
|
for (int i = 0; i < 10; ++i) {
|
|
if ((0x1U << i) == location) {
|
|
string_id = STRING_ID_LOCATION + i;
|
|
break;
|
|
}
|
|
}
|
|
if (string_id)
|
|
return GetSysString(string_id);
|
|
else
|
|
return unknown_string;
|
|
}
|
|
const wchar_t* DataManager::FormatLocation(ClientCard* card) const {
|
|
if (!card)
|
|
return unknown_string;
|
|
return FormatLocation(card->location, card->sequence);
|
|
}
|
|
std::wstring DataManager::FormatAttribute(unsigned int attribute) const {
|
|
std::wstring buffer;
|
|
for (int i = 0; i < ATTRIBUTES_COUNT; ++i) {
|
|
if (attribute & (0x1U << i)) {
|
|
if (!buffer.empty())
|
|
buffer.push_back(L'|');
|
|
buffer.append(GetSysString(STRING_ID_ATTRIBUTE + i));
|
|
}
|
|
}
|
|
if (buffer.empty())
|
|
buffer = unknown_string;
|
|
return buffer;
|
|
}
|
|
std::wstring DataManager::FormatRace(unsigned int race) const {
|
|
std::wstring buffer;
|
|
for(int i = 0; i < RACES_COUNT; ++i) {
|
|
if(race & (0x1U << i)) {
|
|
if (!buffer.empty())
|
|
buffer.push_back(L'|');
|
|
buffer.append(GetSysString(STRING_ID_RACE + i));
|
|
}
|
|
}
|
|
if (buffer.empty())
|
|
buffer = unknown_string;
|
|
return buffer;
|
|
}
|
|
std::wstring DataManager::FormatType(unsigned int type) const {
|
|
std::wstring buffer;
|
|
for (int i = 0; i < TYPES_COUNT; ++i) {
|
|
if (type & (0x1U << i)) {
|
|
if (!buffer.empty())
|
|
buffer.push_back(L'|');
|
|
buffer.append(GetSysString(STRING_ID_TYPE + i));
|
|
}
|
|
}
|
|
if (buffer.empty())
|
|
buffer = unknown_string;
|
|
return buffer;
|
|
}
|
|
std::wstring DataManager::FormatSetName(const uint16_t setcode[]) const {
|
|
std::wstring buffer;
|
|
for(int i = 0; i < 10; ++i) {
|
|
if (!setcode[i])
|
|
break;
|
|
const wchar_t* setname = GetSetName(setcode[i]);
|
|
if (!buffer.empty())
|
|
buffer.push_back(L'|');
|
|
buffer.append(setname);
|
|
}
|
|
if (buffer.empty())
|
|
buffer = unknown_string;
|
|
return buffer;
|
|
}
|
|
std::wstring DataManager::FormatLinkMarker(unsigned int link_marker) const {
|
|
std::wstring buffer;
|
|
if (link_marker & LINK_MARKER_TOP_LEFT)
|
|
buffer.append(L"[\u2196]");
|
|
if (link_marker & LINK_MARKER_TOP)
|
|
buffer.append(L"[\u2191]");
|
|
if (link_marker & LINK_MARKER_TOP_RIGHT)
|
|
buffer.append(L"[\u2197]");
|
|
if (link_marker & LINK_MARKER_LEFT)
|
|
buffer.append(L"[\u2190]");
|
|
if (link_marker & LINK_MARKER_RIGHT)
|
|
buffer.append(L"[\u2192]");
|
|
if (link_marker & LINK_MARKER_BOTTOM_LEFT)
|
|
buffer.append(L"[\u2199]");
|
|
if (link_marker & LINK_MARKER_BOTTOM)
|
|
buffer.append(L"[\u2193]");
|
|
if (link_marker & LINK_MARKER_BOTTOM_RIGHT)
|
|
buffer.append(L"[\u2198]");
|
|
return buffer;
|
|
}
|
|
wchar_t DataManager::NormalizeChar(wchar_t c) {
|
|
// Convert Alphabet characters to uppercase to ignore case.
|
|
if (c >= 0x0061 && c <= 0x007A) {
|
|
return c - 0x0020;
|
|
}
|
|
// Normalize accented characters (Latin-1 Supplement).
|
|
if ((c >= 0x00C0 && c <= 0x00C5) || (c >= 0x00E0 && c <= 0x00E5)) {
|
|
return L'A';
|
|
}
|
|
if (c == 0x00C7 || c == 0x00E7) {
|
|
return L'C';
|
|
}
|
|
if ((c >= 0x00C8 && c <= 0x00CB) || (c >= 0x00E8 && c <= 0x00EB)) {
|
|
return L'E';
|
|
}
|
|
if ((c >= 0x00CC && c <= 0x00CF) || (c >= 0x00EC && c <= 0x00EF)) {
|
|
return L'I';
|
|
}
|
|
if (c == 0x00D1 || c == 0x00F1) {
|
|
return L'N';
|
|
}
|
|
if ((c >= 0x00D2 && c <= 0x00D6) || (c >= 0x00F2 && c <= 0x00F6)) {
|
|
return L'O';
|
|
}
|
|
if ((c >= 0x00D9 && c <= 0x00DC) || (c >= 0x00F9 && c <= 0x00FC)) {
|
|
return L'U';
|
|
}
|
|
if (c == 0x00DD || c == 0x00FD || c == 0x00FF) {
|
|
return L'Y';
|
|
}
|
|
return c;
|
|
}
|
|
void DataManager::NormalizeString(const wchar_t* src, wchar_t* dst, size_t dst_size) {
|
|
size_t i = 0;
|
|
for(; src[i] && i < dst_size - 1; ++i) {
|
|
dst[i] = NormalizeChar(src[i]);
|
|
}
|
|
dst[i] = 0;
|
|
}
|
|
bool DataManager::CardNameContains(const wchar_t* haystack, const wchar_t* needle) {
|
|
if(!needle[0]) {
|
|
return true;
|
|
}
|
|
if(!haystack) {
|
|
return false;
|
|
}
|
|
wchar_t normalized_haystack[TEXT_LINE_SIZE]{};
|
|
wchar_t normalized_needle[TEXT_LINE_SIZE]{};
|
|
NormalizeString(haystack, normalized_haystack, TEXT_LINE_SIZE);
|
|
NormalizeString(needle, normalized_needle, TEXT_LINE_SIZE);
|
|
return std::wcsstr(normalized_haystack, normalized_needle) != nullptr;
|
|
}
|
|
|
|
uint32_t DataManager::CardReader(uint32_t code, card_data* pData) {
|
|
if (!dataManager.GetData(code, pData))
|
|
pData->clear();
|
|
return 0;
|
|
}
|
|
unsigned char* DataManager::ScriptReaderEx(const char* script_path, int* slen) {
|
|
// default script name: ./script/c%d.lua
|
|
if (std::strncmp(script_path, "./script", 8) != 0) // not a card script file
|
|
return ReadScriptFromFile(script_path, slen);
|
|
const char* script_name = script_path + 2;
|
|
char expansions_path[1024]{};
|
|
mysnprintf(expansions_path, "./expansions/%s", script_name);
|
|
if (mainGame->gameConf.prefer_expansion_script) { // debug script with raw file in expansions
|
|
if (ReadScriptFromFile(expansions_path, slen))
|
|
return scriptBuffer;
|
|
if (ReadScriptFromIrrFS(script_name, slen))
|
|
return scriptBuffer;
|
|
if (ReadScriptFromFile(script_path, slen))
|
|
return scriptBuffer;
|
|
} else {
|
|
if (ReadScriptFromIrrFS(script_name, slen))
|
|
return scriptBuffer;
|
|
if (ReadScriptFromFile(script_path, slen))
|
|
return scriptBuffer;
|
|
if (ReadScriptFromFile(expansions_path, slen))
|
|
return scriptBuffer;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
unsigned char* DataManager::ReadScriptFromIrrFS(const char* script_name, int* slen) {
|
|
auto reader = dataManager.IrrFileSystem->createAndOpenFile(script_name);
|
|
if (!reader)
|
|
return nullptr;
|
|
int size = reader->read(scriptBuffer, sizeof scriptBuffer);
|
|
reader->drop();
|
|
if (size >= (int)sizeof scriptBuffer)
|
|
return nullptr;
|
|
*slen = size;
|
|
return scriptBuffer;
|
|
}
|
|
unsigned char* DataManager::ReadScriptFromFile(const char* script_name, int* slen) {
|
|
FILE* fp = myfopen(script_name, "rb");
|
|
if (!fp)
|
|
return nullptr;
|
|
size_t len = std::fread(scriptBuffer, 1, sizeof scriptBuffer, fp);
|
|
std::fclose(fp);
|
|
if (len >= sizeof scriptBuffer)
|
|
return nullptr;
|
|
*slen = (int)len;
|
|
return scriptBuffer;
|
|
}
|
|
bool DataManager::deck_sort_lv(const CardDataC* p1, const CardDataC* p2) {
|
|
if ((p1->type & 0x7) != (p2->type & 0x7))
|
|
return (p1->type & 0x7) < (p2->type & 0x7);
|
|
if ((p1->type & 0x7) == 1) {
|
|
auto type1 = (p1->type & 0x48020c0) ? (p1->type & 0x48020c1) : (p1->type & 0x31);
|
|
auto type2 = (p2->type & 0x48020c0) ? (p2->type & 0x48020c1) : (p2->type & 0x31);
|
|
if (type1 != type2)
|
|
return type1 < type2;
|
|
if (p1->level != p2->level)
|
|
return p1->level > p2->level;
|
|
if (p1->attack != p2->attack)
|
|
return p1->attack > p2->attack;
|
|
if (p1->defense != p2->defense)
|
|
return p1->defense > p2->defense;
|
|
return p1->code < p2->code;
|
|
}
|
|
if ((p1->type & 0xfffffff8) != (p2->type & 0xfffffff8))
|
|
return (p1->type & 0xfffffff8) < (p2->type & 0xfffffff8);
|
|
return p1->code < p2->code;
|
|
}
|
|
bool DataManager::deck_sort_atk(const CardDataC* p1, const CardDataC* p2) {
|
|
if ((p1->type & 0x7) != (p2->type & 0x7))
|
|
return (p1->type & 0x7) < (p2->type & 0x7);
|
|
if ((p1->type & 0x7) == 1) {
|
|
if (p1->attack != p2->attack)
|
|
return p1->attack > p2->attack;
|
|
if (p1->defense != p2->defense)
|
|
return p1->defense > p2->defense;
|
|
if (p1->level != p2->level)
|
|
return p1->level > p2->level;
|
|
auto type1 = (p1->type & 0x48020c0) ? (p1->type & 0x48020c1) : (p1->type & 0x31);
|
|
auto type2 = (p2->type & 0x48020c0) ? (p2->type & 0x48020c1) : (p2->type & 0x31);
|
|
if (type1 != type2)
|
|
return type1 < type2;
|
|
return p1->code < p2->code;
|
|
}
|
|
if ((p1->type & 0xfffffff8) != (p2->type & 0xfffffff8))
|
|
return (p1->type & 0xfffffff8) < (p2->type & 0xfffffff8);
|
|
return p1->code < p2->code;
|
|
}
|
|
bool DataManager::deck_sort_def(const CardDataC* p1, const CardDataC* p2) {
|
|
if ((p1->type & 0x7) != (p2->type & 0x7))
|
|
return (p1->type & 0x7) < (p2->type & 0x7);
|
|
if ((p1->type & 0x7) == 1) {
|
|
if (p1->defense != p2->defense)
|
|
return p1->defense > p2->defense;
|
|
if (p1->attack != p2->attack)
|
|
return p1->attack > p2->attack;
|
|
if (p1->level != p2->level)
|
|
return p1->level > p2->level;
|
|
auto type1 = (p1->type & 0x48020c0) ? (p1->type & 0x48020c1) : (p1->type & 0x31);
|
|
auto type2 = (p2->type & 0x48020c0) ? (p2->type & 0x48020c1) : (p2->type & 0x31);
|
|
if (type1 != type2)
|
|
return type1 < type2;
|
|
return p1->code < p2->code;
|
|
}
|
|
if ((p1->type & 0xfffffff8) != (p2->type & 0xfffffff8))
|
|
return (p1->type & 0xfffffff8) < (p2->type & 0xfffffff8);
|
|
return p1->code < p2->code;
|
|
}
|
|
bool DataManager::deck_sort_name(const CardDataC* p1, const CardDataC* p2) {
|
|
const wchar_t* name1 = dataManager.GetName(p1->code);
|
|
const wchar_t* name2 = dataManager.GetName(p2->code);
|
|
int res = std::wcscmp(name1, name2);
|
|
if (res != 0)
|
|
return res < 0;
|
|
return p1->code < p2->code;
|
|
}
|
|
|
|
}
|