Commit c8ad16eb authored by fallenstardust's avatar fallenstardust

读取genesys禁卡文件

parent f82b00e7
Pipeline #41930 failed with stages
......@@ -1857,24 +1857,101 @@ void DeckBuilder::pop_side(int seq) {
is_modified = true;
GetHoveredCard();
}
/**
* @brief 检查指定卡片在当前卡组中是否超过限制数量,并处理信用点数消耗逻辑。
*
* 此函数用于判断一张卡片(由 pointer 指定)能否被加入当前卡组,
* 包括常规禁卡表卡片的数量限制以及GeneSys存在的“信用点”数量限制。
*
* @param pointer 指向卡片信息的指针,包含卡片ID及别名等数据。
* @return 如果该卡片可以合法地加入卡组(未超出数量限制、信用点足够),则返回 true;否则返回 false。
*/
bool DeckBuilder::check_limit(code_pointer pointer) {
// 获取实际用于限制检查的卡片编码:如果存在别名则使用别名,否则使用原ID
auto limitcode = pointer->second.alias ? pointer->second.alias : pointer->first;
// 默认每张卡最多允许3张
int limit = 3;
// 查找此卡片是否有自定义的数量限制
auto flit = filterList->content.find(limitcode);
if(flit != filterList->content.end())
limit = flit->second;
for (auto& card : deckManager.current_deck.main) {
if (card->first == limitcode || card->second.alias == limitcode)
// 记录已使用的各类信用点数
std::unordered_map<std::wstring, uint32_t> credit_used;
// Lambda 函数:尝试消费某张卡所需的信用点数,若超限则返回false
auto spend_credit = [&](uint32_t code) {
// 查找该卡所需信用点配置
auto code_credit_it = filterList->credits.find(code);
if(code_credit_it == filterList->credits.end())
return true; // 若无信用要求,默认通过
auto code_credit = code_credit_it->second;
auto valid = true;
// 遍历所有需要扣除的信用类型与数值
for(auto& credit_it : code_credit) {
auto key = credit_it.first;
auto credit_limit_it = filterList->credit_limits.find(key);
if(credit_limit_it == filterList->credit_limits.end())
continue; // 若没有设定上限,则跳过
auto credit_limit = credit_limit_it->second;
// 初始化该信用类型的已用量
if(credit_used.find(key) == credit_used.end())
credit_used[key] = 0;
// 判断是否会超出信用上限
auto credit_after = credit_used[key] + credit_it.second;
if(credit_after > credit_limit)
valid = false;
// 更新已用信用量
credit_used[key] = credit_after;
}
return valid;
};
// Lambda 函数:处理单张卡的计数和信用检查
auto handle_card = [&](ygo::code_pointer& card) {
// 如果是目标卡,则减少其剩余可放数量
if (card->first == limitcode || card->second.alias == limitcode) {
limit--;
if(limit <= 0)
return false; // 已达最大数量限制
}
// 获取真实卡号并尝试扣减信用点
auto code = card->second.alias ? card->second.alias : card->first;
spend_credit(code);
return true;
};
// 遍历主卡组中的所有卡片进行检查
for (auto& card : deckManager.current_deck.main) {
if(!handle_card(card))
return false;
}
// 遍历额外卡组中的所有卡片进行检查
for (auto& card : deckManager.current_deck.extra) {
if (card->first == limitcode || card->second.alias == limitcode)
limit--;
if(!handle_card(card))
return false;
}
// 遍历副卡组中的所有卡片进行检查
for (auto& card : deckManager.current_deck.side) {
if (card->first == limitcode || card->second.alias == limitcode)
limit--;
if(!handle_card(card))
return false;
}
return limit > 0;
// 最后尝试为当前要插入的卡扣除一次信用点数
return spend_credit(limitcode);
}
}
......@@ -7,6 +7,7 @@ namespace ygo {
DeckManager deckManager;
std::vector<std::wstring> DeckManager::deckComments;
void DeckManager::LoadLFListSingle(const char* path) {
auto cur = _lfList.rend();
FILE* fp = myfopen(path, "r");
......@@ -29,24 +30,70 @@ void DeckManager::LoadLFListSingle(const char* path) {
}
if (cur == _lfList.rend())
continue;
if(linebuf[0] == '$') {
char* keyPos = linebuf + 1;
keyPos += std::strspn(keyPos, " \t");
auto keyLen = std::strcspn(keyPos, " \t\r\n");
if(!keyLen)
continue;
char keybuf[256];
if(keyLen >= sizeof keybuf)
keyLen = sizeof keybuf - 1;
std::memcpy(keybuf, keyPos, keyLen);
keybuf[keyLen] = 0;
keyPos += keyLen;
keyPos += std::strspn(keyPos, " \t");
errno = 0;
char* valuePos = keyPos;
auto limitValue = std::strtoul(keyPos, &keyPos, 10);
if(errno || valuePos == keyPos)
continue;
BufferIO::DecodeUTF8(keybuf, strBuffer);
cur->credit_limits[strBuffer] = static_cast<uint32_t>(limitValue);
continue;
}
char* pos = linebuf;
errno = 0;
char* codePos = pos;
auto result = std::strtoul(pos, &pos, 10);
if (errno || result > UINT32_MAX)
if(errno || result > UINT32_MAX || codePos == pos)
continue;
if (pos == linebuf || *pos != ' ')
if(*pos != ' ' && *pos != '\t')
continue;
pos += std::strspn(pos, " \t");
uint32_t code = static_cast<uint32_t>(result);
if(*pos == '$') {
++pos;
pos += std::strspn(pos, " \t");
auto creditKeyLen = std::strcspn(pos, " \t\r\n");
if(!creditKeyLen)
continue;
char keybuf[256];
if(creditKeyLen >= sizeof keybuf)
creditKeyLen = sizeof keybuf - 1;
std::memcpy(keybuf, pos, creditKeyLen);
keybuf[creditKeyLen] = 0;
pos += creditKeyLen;
pos += std::strspn(pos, " \t");
errno = 0;
char* creditValuePos = pos;
auto creditValue = std::strtoul(pos, &pos, 10);
if(errno || creditValuePos == pos)
continue;
BufferIO::DecodeUTF8(keybuf, strBuffer);
cur->credits[code][strBuffer] = static_cast<uint32_t>(creditValue);
continue;
}
errno = 0;
char* countPos = pos;
int count = std::strtol(pos, &pos, 10);
if (errno)
if(errno || countPos == pos)
continue;
if (count < 0 || count > 2)
if(count < 0 || count > 2)
continue;
cur->content[code] = count;
cur->hash = cur->hash ^ ((code << 18) | (code >> 14)) ^ ((code << (27 + count)) | (code >> (5 - count)));
}
std::fclose(fp);
}
}
void DeckManager::LoadLFListSingle(irr::io::IReadFile* reader) {
......@@ -96,22 +143,70 @@ void DeckManager::LoadLFListSingle(irr::io::IReadFile* reader) {
}
if (cur == _lfList.rend())
continue;
if(linebuf[0] == '$') {
char* keyPos = linebuf + 1;
keyPos += std::strspn(keyPos, " \t");
auto keyLen = std::strcspn(keyPos, " \t\r\n");
if(!keyLen)
continue;
char keybuf[256];
if(keyLen >= sizeof keybuf)
keyLen = sizeof keybuf - 1;
std::memcpy(keybuf, keyPos, keyLen);
keybuf[keyLen] = 0;
keyPos += keyLen;
keyPos += std::strspn(keyPos, " \t");
errno = 0;
char* valuePos = keyPos;
auto limitValue = std::strtoul(keyPos, &keyPos, 10);
if(errno || valuePos == keyPos)
continue;
BufferIO::DecodeUTF8(keybuf, strBuffer);
cur->credit_limits[strBuffer] = static_cast<uint32_t>(limitValue);
continue;
}
char* pos = linebuf;
errno = 0;
char* codePos = pos;
auto result = std::strtoul(pos, &pos, 10);
if (errno || result > UINT32_MAX)
if(errno || result > UINT32_MAX || codePos == pos)
continue;
if (pos == linebuf || *pos != ' ')
if(*pos != ' ' && *pos != '\t')
continue;
pos += std::strspn(pos, " \t");
uint32_t code = static_cast<uint32_t>(result);
if(*pos == '$') {
++pos;
pos += std::strspn(pos, " \t");
auto creditKeyLen = std::strcspn(pos, " \t\r\n");
if(!creditKeyLen)
continue;
char keybuf[256];
if(creditKeyLen >= sizeof keybuf)
creditKeyLen = sizeof keybuf - 1;
std::memcpy(keybuf, pos, creditKeyLen);
keybuf[creditKeyLen] = 0;
pos += creditKeyLen;
pos += std::strspn(pos, " \t");
errno = 0;
char* creditValuePos = pos;
auto creditValue = std::strtoul(pos, &pos, 10);
if(errno || creditValuePos == pos)
continue;
BufferIO::DecodeUTF8(keybuf, strBuffer);
cur->credits[code][strBuffer] = static_cast<uint32_t>(creditValue);
continue;
}
errno = 0;
char* countPos = pos;
int count = std::strtol(pos, &pos, 10);
if (errno)
if(errno || countPos == pos)
continue;
if (count < 0 || count > 2)
if(count < 0 || count > 2)
continue;
cur->content[code] = count;
cur->hash = cur->hash ^ ((code << 18) | (code >> 14)) ^ ((code << (27 + count)) | (code >> (5 - count)));
}
}
void DeckManager::LoadLFList(irr::android::InitOptions *options) {
......@@ -161,6 +256,27 @@ unsigned int DeckManager::CheckDeck(const Deck& deck, unsigned int lfhash, int r
if (!lflist)
return 0;
auto& list = lflist->content;
std::unordered_map<std::wstring, uint32_t> credit_used;
auto spend_credit = [&](uint32_t code) {
auto code_credit_it = lflist->credits.find(code);
if(code_credit_it == lflist->credits.end())
return (uint32_t)0;
auto code_credit = code_credit_it->second;
for(auto& credit_it : code_credit) {
auto key = credit_it.first;
auto credit_limit_it = lflist->credit_limits.find(key);
if(credit_limit_it == lflist->credit_limits.end())
continue;
auto credit_limit = credit_limit_it->second;
if(credit_used.find(key) == credit_used.end())
credit_used[key] = 0;
auto credit_after = credit_used[key] + credit_it.second;
if(credit_after > credit_limit)
return (DECKERROR_LFLIST << 28) | code;
credit_used[key] = credit_after;
}
return (uint32_t)0;
};
const unsigned int rule_map[6] = { AVAIL_OCG, AVAIL_TCG, AVAIL_SC, AVAIL_CUSTOM, AVAIL_OCGTCG, 0 };
unsigned int avail = 0;
if (rule >= 0 && rule < (int)(sizeof rule_map / sizeof rule_map[0]))
......@@ -179,6 +295,9 @@ unsigned int DeckManager::CheckDeck(const Deck& deck, unsigned int lfhash, int r
auto it = list.find(code);
if(it != list.end() && dc > it->second)
return (DECKERROR_LFLIST << 28) | cit->first;
auto spend_credit_error = spend_credit(code);
if(spend_credit_error)
return spend_credit_error;
}
for (auto& cit : deck.extra) {
auto gameruleDeckError = checkAvail(cit->second.ot, avail);
......@@ -194,6 +313,9 @@ unsigned int DeckManager::CheckDeck(const Deck& deck, unsigned int lfhash, int r
auto it = list.find(code);
if(it != list.end() && dc > it->second)
return (DECKERROR_LFLIST << 28) | cit->first;
auto spend_credit_error = spend_credit(code);
if(spend_credit_error)
return spend_credit_error;
}
for (auto& cit : deck.side) {
auto gameruleDeckError = checkAvail(cit->second.ot, avail);
......@@ -209,6 +331,9 @@ unsigned int DeckManager::CheckDeck(const Deck& deck, unsigned int lfhash, int r
auto it = list.find(code);
if(it != list.end() && dc > it->second)
return (DECKERROR_LFLIST << 28) | cit->first;
auto spend_credit_error = spend_credit(code);
if(spend_credit_error)
return spend_credit_error;
}
return 0;
}
......
......@@ -28,6 +28,8 @@ struct LFList {
unsigned int hash{};
std::wstring listName;
std::unordered_map<uint32_t, int> content;
std::unordered_map<std::wstring, uint32_t> credit_limits;
std::unordered_map<uint32_t, std::unordered_map<std::wstring, uint32_t>> credits;
};
struct Deck {
std::vector<code_pointer> main;
......
......@@ -1537,7 +1537,33 @@ void Game::DrawThumb(code_pointer cp, irr::core::vector2di pos, const LFList* lf
break;
}
}
auto lfcredit = lflist->credits.find(lcode);
auto current_limitloc = limitloc;
auto credit_max_display = CARD_THUMB_WIDTH / 20;
auto next_limitloc = [&]() {
auto this_limitloc = current_limitloc;
auto width = current_limitloc.getWidth();
current_limitloc.UpperLeftCorner.X += width;
current_limitloc.LowerRightCorner.X += width;
--credit_max_display;
return this_limitloc;
};
if(lfcredit != lflist->credits.end()) {
for(auto& credit_entry : lfcredit->second) {
if(credit_max_display <= 0)
break;
auto value = credit_entry.second;
if(value > 0 && value <= 100) {
auto cvalue = value - 1; // 1-100 => 0-99
// pick the first and second digit
auto digit1 = cvalue / 10;
auto digit2 = cvalue % 10;
auto credit_texture_offset_x = digit2 * 64;
auto credit_texture_offset_y = digit1 * 64;
driver->draw2DImage(imageManager.tLimCredit, next_limitloc(), irr::core::recti(credit_texture_offset_x, credit_texture_offset_y, credit_texture_offset_x + 64, credit_texture_offset_y + 64), 0, 0, true);
}
}
}
// 判断是否需要显示可用性相关图标
bool showAvail = false;
bool showNotAvail = false;
......
......@@ -35,6 +35,7 @@ bool ImageManager::Initial(const path dir) {
tTarget = driver->getTexture((dir + path("/textures/target.png")).c_str());
tChainTarget = driver->getTexture((dir + path("/textures/chaintarget.png")).c_str());
tLim = driver->getTexture((dir + path("/textures/lim.png")).c_str());
tLimCredit = driver->getTexture((dir + path("/textures/limCredit.png")).c_str());
tOT = driver->getTexture((dir + path("/textures/ot.png")).c_str());
tHand[0] = driver->getTexture((dir + path("/textures/f1.jpg")).c_str());
tHand[1] = driver->getTexture((dir + path("/textures/f2.jpg")).c_str());
......
......@@ -47,6 +47,7 @@ public:
irr::video::ITexture* tTarget;
irr::video::ITexture* tChainTarget;
irr::video::ITexture* tLim;
irr::video::ITexture* tLimCredit;
irr::video::ITexture* tOT;
irr::video::ITexture* tHand[3];
irr::video::ITexture* tBackGround;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment