Commit f64a2ac2 authored by fallenstardust's avatar fallenstardust

ygopro添加点数筛选查询功能

添加注释
parent eff384e6
......@@ -1429,10 +1429,22 @@ void DeckBuilder::GetHoveredCard() {
imageManager.RemoveTexture(pre_code);
}
}
/**
* @brief 开始卡片过滤操作
*
* 该函数用于启动卡片过滤流程,根据用户界面中选择的过滤条件来筛选卡片。
* 首先获取基本的过滤类型、二级类型和限制条件,如果是一般怪兽过滤类型,
* 还会进一步获取属性、种族、攻击力、守备力、等级和刻度等详细过滤条件,
* 最后调用FilterCards函数执行实际的卡片过滤操作。
*/
void DeckBuilder::StartFilter() {
// 获取基础过滤条件:卡片类型、二级类型和限制条件
filter_type = mainGame->cbCardType->getSelected();
filter_type2 = mainGame->cbCardType2->getItemData(mainGame->cbCardType2->getSelected());
filter_lm = mainGame->cbLimit->getSelected();
// 当选择的过滤类型为1时,获取详细的怪兽卡片过滤条件
if(filter_type == 1) {
filter_attrib = mainGame->cbAttribute->getItemData(mainGame->cbAttribute->getSelected());
filter_race = mainGame->cbRace->getItemData(mainGame->cbRace->getSelected());
......@@ -1441,40 +1453,70 @@ void DeckBuilder::StartFilter() {
filter_lv = parse_filter(mainGame->ebStar->getText(), &filter_lvtype);
filter_scl = parse_filter(mainGame->ebScale->getText(), &filter_scltype);
}
// 执行卡片过滤操作
FilterCards();
}
/**
* @brief 根据用户输入的关键字和其他筛选条件过滤卡牌数据,并将结果存储在results中。
*
* 此函数首先解析用户输入的搜索关键字(支持多关键字、排除模式等),然后遍历所有卡牌,
* 应用类型、种族、属性、攻击力、守备力、等级、灵摆刻度、效果分类、连接标记、限制状态等多种筛选条件,
* 最终筛选出符合条件的卡牌并更新界面显示。
*
* @note 该函数会清空之前的筛选结果(results),并对结果进行排序和分页处理。
*/
void DeckBuilder::FilterCards() {
// 清除上一次的筛选结果
results.clear();
/**
* 定义用于解析查询字符串的结构体元素
* 包含关键字(keyword)、对应的系列码(setcodes)、匹配类型(type)以及是否排除(exclude)
*/
struct element_t {
std::wstring keyword;
std::vector<unsigned int> setcodes;
std::wstring keyword; ///< 搜索关键词
std::vector<unsigned int> setcodes; ///< 对应的系列码列表
enum class type_t {
all,
name,
setcode
} type{ type_t::all };
bool exclude{ false };
all, ///< 全字段匹配
name, ///< 名称匹配
setcode ///< 字段码匹配
} type{ type_t::all }; ///< 当前匹配类型,默认为全字段匹配
bool exclude{ false }; ///< 是否是排除项
};
// 获取用户输入的文本内容
const wchar_t* pstr = mainGame->ebCardName->getText();
int trycode = BufferIO::GetVal(pstr);
std::wstring str{ pstr };
std::vector<element_t> query_elements;
int trycode = BufferIO::GetVal(pstr); // 尝试将输入转换为卡号
std::wstring str{ pstr }; // 转换为宽字符字符串便于处理
std::vector<element_t> query_elements; // 存储解析后的查询元素
// 处理多个关键字的情况(根据配置决定使用空格还是+作为分隔符)
if(mainGame->gameConf.search_multiple_keywords) {
const wchar_t separator = mainGame->gameConf.search_multiple_keywords == 1 ? L' ' : L'+';
const wchar_t minussign = L'-';
const wchar_t quotation = L'\"';
const wchar_t minussign = L'-'; // 表示排除的关键字
const wchar_t quotation = L'\"'; // 引号表示精确匹配范围
size_t element_start = 0;
// 循环解析每一个关键字片段
for(;;) {
element_start = str.find_first_not_of(separator, element_start);
if(element_start == std::wstring::npos)
break;
element_t element;
// 判断是否有排除标志 '-'
if(str[element_start] == minussign) {
element.exclude = true;
element_start++;
}
if(element_start >= str.size())
break;
// 判断匹配方式:$表示名称匹配,@表示系列码匹配
if(str[element_start] == L'$') {
element.type = element_t::type_t::name;
element_start++;
......@@ -1484,26 +1526,37 @@ void DeckBuilder::FilterCards() {
}
if(element_start >= str.size())
break;
// 判断是否存在引号包裹的内容
wchar_t delimiter = separator;
if(str[element_start] == quotation) {
delimiter = quotation;
element_start++;
}
// 提取关键字部分
size_t element_end = str.find_first_of(delimiter, element_start);
if(element_end != std::wstring::npos) {
size_t length = element_end - element_start;
element.keyword = str.substr(element_start, length);
} else
} else {
element.keyword = str.substr(element_start);
}
// 获取对应系列码
element.setcodes = dataManager.GetSetCodes(element.keyword);
query_elements.push_back(element);
if(element_end == std::wstring::npos)
break;
element_start = element_end + 1;
}
} else {
// 不启用多关键字时只处理第一个关键字
element_t element;
size_t element_start = 0;
// 同样判断匹配方式
if(str[element_start] == L'$') {
element.type = element_t::type_t::name;
element_start++;
......@@ -1511,67 +1564,97 @@ void DeckBuilder::FilterCards() {
element.type = element_t::type_t::setcode;
element_start++;
}
if(element_start < str.size()) {
element.keyword = str.substr(element_start);
element.setcodes = dataManager.GetSetCodes(element.keyword);
query_elements.push_back(element);
}
}
// 获取卡牌数据库中的数据表与字符串表
auto& _datas = dataManager.GetDataTable();
auto& _strings = dataManager.GetStringTable();
// 遍历每一张卡牌进行筛选
for (code_pointer ptr = _datas.begin(); ptr != _datas.end(); ++ptr) {
auto& code = ptr->first;
auto& data = ptr->second;
auto strpointer = _strings.find(code);
if (strpointer == _strings.end())
continue;
const CardString& strings = strpointer->second;
// 排除TOKEN类型的卡片
if(data.type & TYPE_TOKEN)
continue;
// 根据主类别进行初步筛选
switch(filter_type) {
case 1: {
case 1: { // 怪兽卡筛选逻辑
if(!(data.type & TYPE_MONSTER) || (data.type & filter_type2) != filter_type2)
continue;
if(filter_race && data.race != filter_race)
continue;
if(filter_attrib && data.attribute != filter_attrib)
continue;
// 攻击力筛选
if(filter_atktype) {
if((filter_atktype == 1 && data.attack != filter_atk) || (filter_atktype == 2 && data.attack < filter_atk)
|| (filter_atktype == 3 && data.attack <= filter_atk) || (filter_atktype == 4 && (data.attack > filter_atk || data.attack < 0))
|| (filter_atktype == 5 && (data.attack >= filter_atk || data.attack < 0)) || (filter_atktype == 6 && data.attack != -2))
if((filter_atktype == 1 && data.attack != filter_atk) ||
(filter_atktype == 2 && data.attack < filter_atk) ||
(filter_atktype == 3 && data.attack <= filter_atk) ||
(filter_atktype == 4 && (data.attack > filter_atk || data.attack < 0)) ||
(filter_atktype == 5 && (data.attack >= filter_atk || data.attack < 0)) ||
(filter_atktype == 6 && data.attack != -2))
continue;
}
// 守备力筛选
if(filter_deftype) {
if((filter_deftype == 1 && data.defense != filter_def) || (filter_deftype == 2 && data.defense < filter_def)
|| (filter_deftype == 3 && data.defense <= filter_def) || (filter_deftype == 4 && (data.defense > filter_def || data.defense < 0))
|| (filter_deftype == 5 && (data.defense >= filter_def || data.defense < 0)) || (filter_deftype == 6 && data.defense != -2)
|| (data.type & TYPE_LINK))
if((filter_deftype == 1 && data.defense != filter_def) ||
(filter_deftype == 2 && data.defense < filter_def) ||
(filter_deftype == 3 && data.defense <= filter_def) ||
(filter_deftype == 4 && (data.defense > filter_def || data.defense < 0)) ||
(filter_deftype == 5 && (data.defense >= filter_def || data.defense < 0)) ||
(filter_deftype == 6 && data.defense != -2) ||
(data.type & TYPE_LINK))
continue;
}
// 等级/阶级筛选
if(filter_lvtype) {
if((filter_lvtype == 1 && data.level != filter_lv) || (filter_lvtype == 2 && data.level < filter_lv)
|| (filter_lvtype == 3 && data.level <= filter_lv) || (filter_lvtype == 4 && data.level > filter_lv)
|| (filter_lvtype == 5 && data.level >= filter_lv) || filter_lvtype == 6)
if((filter_lvtype == 1 && data.level != filter_lv) ||
(filter_lvtype == 2 && data.level < filter_lv) ||
(filter_lvtype == 3 && data.level <= filter_lv) ||
(filter_lvtype == 4 && data.level > filter_lv) ||
(filter_lvtype == 5 && data.level >= filter_lv) ||
filter_lvtype == 6)
continue;
}
// 灵摆刻度筛选
if(filter_scltype) {
if((filter_scltype == 1 && data.lscale != filter_scl) || (filter_scltype == 2 && data.lscale < filter_scl)
|| (filter_scltype == 3 && data.lscale <= filter_scl) || (filter_scltype == 4 && (data.lscale > filter_scl))
|| (filter_scltype == 5 && (data.lscale >= filter_scl)) || filter_scltype == 6
|| !(data.type & TYPE_PENDULUM))
if((filter_scltype == 1 && data.lscale != filter_scl) ||
(filter_scltype == 2 && data.lscale < filter_scl) ||
(filter_scltype == 3 && data.lscale <= filter_scl) ||
(filter_scltype == 4 && (data.lscale > filter_scl)) ||
(filter_scltype == 5 && (data.lscale >= filter_scl)) ||
filter_scltype == 6 ||
!(data.type & TYPE_PENDULUM))
continue;
}
break;
}
case 2: {
case 2: { // 魔法卡筛选逻辑
if(!(data.type & TYPE_SPELL))
continue;
if(filter_type2 && data.type != filter_type2)
continue;
break;
}
case 3: {
case 3: { // 陷阱卡筛选逻辑
if(!(data.type & TYPE_TRAP))
continue;
if(filter_type2 && data.type != filter_type2)
......@@ -1579,51 +1662,96 @@ void DeckBuilder::FilterCards() {
break;
}
}
// 效果分类筛选
if(filter_effect && !(data.category & filter_effect))
continue;
// 连接标记筛选
if(filter_marks && (data.link_marker & filter_marks) != filter_marks)
continue;
// 限制状态筛选
if(filter_lm) {
// 检查当前卡片是否符合指定的禁限状态
if(filter_lm <= 4) {
// 普通禁限卡检查
if(filter_lm <= 3 && (!filterList->content.count(ptr->first) || filterList->content.at(ptr->first) != filter_lm - 1))
continue;
if(filter_lm == 4 && !(data.ot & AVAIL_OCG))
// genesys点数检查 (filter_lm == 4 对应点数限制)
else if(filter_lm == 4) {
// 检查该卡片是否在genesys禁卡表中有点数限制
auto credit_it = filterList->credits.find(ptr->first);
// 同时检查卡片的alias是否在genesys禁卡表中有点数限制
auto alias_credit_it = (ptr->second.alias != 0) ? filterList->credits.find(ptr->second.alias) : filterList->credits.end();
// 如果卡片本身和alias都不在genesys列表中,则不符合筛选条件
if(credit_it == filterList->credits.end() && alias_credit_it == filterList->credits.end())
continue; // 如果不在genesys列表中,则不符合筛选条件
}
}
// filter_lm == 5 表示只显示OCG卡
if(filter_lm == 5 && !(data.ot & AVAIL_OCG))
continue;
if(filter_lm == 5 && !(data.ot & AVAIL_TCG))
// filter_lm == 6 表示只显示TCG卡
if(filter_lm == 6 && !(data.ot & AVAIL_TCG))
continue;
if(filter_lm == 6 && !(data.ot & AVAIL_SC))
// filter_lm == 7 表示只显示SC卡(可能是简体中文卡)
if(filter_lm == 7 && !(data.ot & AVAIL_SC))
continue;
if(filter_lm == 7 && !(data.ot & AVAIL_CUSTOM))
// filter_lm == 8 表示只显示CUSTOM卡(自定义卡)
if(filter_lm == 8 && !(data.ot & AVAIL_CUSTOM))
continue;
if(filter_lm == 8 && ((data.ot & AVAIL_OCGTCG) != AVAIL_OCGTCG))
// filter_lm == 9 表示只显示同时属于OCG和TCG的卡片
if(filter_lm == 9 && ((data.ot & AVAIL_OCGTCG) != AVAIL_OCGTCG))
continue;
}
// 关键词匹配检查
bool is_target = true;
for (auto elements_iterator = query_elements.begin(); elements_iterator != query_elements.end(); ++elements_iterator) {
bool match = false;
// 根据不同匹配类型执行不同的比较操作
if (elements_iterator->type == element_t::type_t::name) {
match = CardNameContains(strings.name.c_str(), elements_iterator->keyword.c_str());
} else if (elements_iterator->type == element_t::type_t::setcode) {
match = data.is_setcodes(elements_iterator->setcodes);
} else if (trycode && (data.code == trycode || data.alias == trycode && is_alternative(data.code, data.alias))){
} else if (trycode && (data.code == trycode || data.alias == trycode && is_alternative(data.code, data.alias))) {
match = true;
} else {
match = CardNameContains(strings.name.c_str(), elements_iterator->keyword.c_str())
|| strings.text.find(elements_iterator->keyword) != std::wstring::npos
|| data.is_setcodes(elements_iterator->setcodes);
}
// 若为排除项则反转匹配结果
if(elements_iterator->exclude)
match = !match;
if(!match) {
is_target = false;
break;
}
}
// 符合所有条件则加入结果集
if(is_target)
results.push_back(ptr);
else
continue;
}
// 更新结果数量显示
myswprintf(result_string, L"%d", results.size());
// 控制滚动条可见性及位置设置
if(results.size() > 7) {
mainGame->scrFilter->setVisible(true);
mainGame->scrFilter->setMax(results.size() - 7);
......@@ -1632,8 +1760,11 @@ void DeckBuilder::FilterCards() {
mainGame->scrFilter->setVisible(false);
mainGame->scrFilter->setPos(0);
}
// 对最终结果进行排序
SortList();
}
void DeckBuilder::InstantSearch() {
if(mainGame->gameConf.auto_search_limit >= 0 && ((int)std::wcslen(mainGame->ebCardName->getText()) >= mainGame->gameConf.auto_search_limit))
StartFilter();
......
......@@ -1568,13 +1568,13 @@ void Game::DrawThumb(code_pointer cp, irr::core::vector2di pos, const LFList* lf
bool showAvail = false;
bool showNotAvail = false;
int filter_lm = cbLimit->getSelected();
bool avail = !((filter_lm == 4 && !(cp->second.ot & AVAIL_OCG)
|| (filter_lm == 5 && !(cp->second.ot & AVAIL_TCG))
|| (filter_lm == 6 && !(cp->second.ot & AVAIL_SC))
|| (filter_lm == 7 && !(cp->second.ot & AVAIL_CUSTOM))
|| (filter_lm == 8 && (cp->second.ot & AVAIL_OCGTCG) != AVAIL_OCGTCG)));
bool avail = !((filter_lm == 5 && !(cp->second.ot & AVAIL_OCG)
|| (filter_lm == 6 && !(cp->second.ot & AVAIL_TCG))
|| (filter_lm == 7 && !(cp->second.ot & AVAIL_SC))
|| (filter_lm == 8 && !(cp->second.ot & AVAIL_CUSTOM))
|| (filter_lm == 9 && (cp->second.ot & AVAIL_OCGTCG) != AVAIL_OCGTCG)));
if(filter_lm >= 4) {
if(filter_lm >= 5) {
showAvail = avail;
showNotAvail = !avail;
} else if(!(cp->second.ot & gameConf.defaultOT)) {
......@@ -1766,10 +1766,10 @@ void Game::DrawDeckBd() {
driver->draw2DRectangleOutline(Resize(805, 136, 930,157));
// 显示“搜索结果”标题
DrawShadowText(guiFont, dataManager.GetSysString(1333),Resize(795, 136, 930,156),Resize(0, 1, 2, 0), 0xffffffff,0xff000000, true, false);
DrawShadowText(guiFont, dataManager.GetSysString(1333),Resize(810, 136, 875,156),Resize(0, 1, 2, 0), 0xffffffff,0xff000000,false, false);
// 显示搜索结果数量
DrawShadowText(numFont, deckBuilder.result_string,Resize(865, 136, 930,156),Resize(0, 1, 2, 0), 0xffffffff,0xff000000, true, false);
DrawShadowText(numFont, deckBuilder.result_string,Resize(880, 136, 930,156),Resize(0, 1, 2, 0), 0xffffffff,0xff000000,false, false);
// 搜索结果内容区背景与边框
driver->draw2DRectangle(Resize(806, 160, 1020, 630), 0x400000ff, 0x400000ff, 0x40000000, 0x40000000);
......
......@@ -1121,39 +1121,48 @@ bool Game::Initialize(ANDROID_APP app, irr::android::InitOptions *options) {
cbLimit->addItem(dataManager.GetSysString(1316));// 禁止
cbLimit->addItem(dataManager.GetSysString(1317));// 限制
cbLimit->addItem(dataManager.GetSysString(1318));// 准限制
cbLimit->addItem(dataManager.GetSysString(1699));// 点数
cbLimit->addItem(dataManager.GetSysString(1481));// OCG
cbLimit->addItem(dataManager.GetSysString(1482));// TCG
cbLimit->addItem(dataManager.GetSysString(1483));// 简体中文
cbLimit->addItem(dataManager.GetSysString(1484));// 自定义卡片
cbLimit->addItem(dataManager.GetSysString(1485));// 无独有卡
// 筛选卡片的条件:属性
stAttribute = env->addStaticText(dataManager.GetSysString(1319)/*属性:*/, Resize(10, 28, 70, 48), false, false, wFilter);
cbAttribute = irr::gui::CAndroidGUIComboBox::addAndroidComboBox(env, Resize(60, 26, 190, 46), wFilter, COMBOBOX_ATTRIBUTE);
cbAttribute->setMaxSelectionRows(10);
cbAttribute->addItem(dataManager.GetSysString(1310)/*(无)*/, 0);
for (int i = 0; i < ATTRIBUTES_COUNT; ++i)
cbAttribute->addItem(dataManager.GetSysString(DataManager::STRING_ID_ATTRIBUTE + i), 0x1U << i);
// 筛选卡片的条件:种族
env->addStaticText(dataManager.GetSysString(1321)/*种族:*/, Resize(10, 51, 70, 71), false, false, wFilter);
cbRace = irr::gui::CAndroidGUIComboBox::addAndroidComboBox(env, Resize(60, 40 + 75 / 6, 190, 60 + 75 / 6), wFilter, COMBOBOX_RACE);
cbRace->setMaxSelectionRows(10);
cbRace->addItem(dataManager.GetSysString(1310)/*(无)*/, 0);
for (int i = 0; i < RACES_COUNT; ++i)
cbRace->addItem(dataManager.GetSysString(DataManager::STRING_ID_RACE + i), 0x1U << i);
// 筛选卡片的条件:攻击力
env->addStaticText(dataManager.GetSysString(1322)/*攻击:*/, Resize(205, 28, 280, 48), false, false, wFilter);
ebAttack = irr::gui::CAndroidGUIEditBox::addAndroidEditBox(L"", true, env, Resize(260, 26, 340, 46), wFilter, EDITBOX_INPUTS);
ebAttack->setTextAlignment(irr::gui::EGUIA_CENTER, irr::gui::EGUIA_CENTER);
// 筛选卡片的条件:防御力
env->addStaticText(dataManager.GetSysString(1323)/*守备:*/, Resize(205, 51, 280, 71), false, false, wFilter);
ebDefense = irr::gui::CAndroidGUIEditBox::addAndroidEditBox(L"", true, env, Resize(260, 49, 340, 69), wFilter, EDITBOX_INPUTS);
ebDefense->setTextAlignment(irr::gui::EGUIA_CENTER, irr::gui::EGUIA_CENTER);
// 筛选卡片的条件:星数
env->addStaticText(dataManager.GetSysString(1324)/*星数:*/, Resize(10, 74, 80, 94), false, false, wFilter);
ebStar = irr::gui::CAndroidGUIEditBox::addAndroidEditBox(L"", true, env, Resize(60, 60 + 100 / 6, 100, 80 + 100 / 6), wFilter, EDITBOX_INPUTS);
ebStar->setTextAlignment(irr::gui::EGUIA_CENTER, irr::gui::EGUIA_CENTER);
// 筛选卡片的条件:刻度
env->addStaticText(dataManager.GetSysString(1336)/*刻度:*/, Resize(101, 60 + 100 / 6, 150 * xScale, 82 + 100 / 6), false, false, wFilter);
ebScale = irr::gui::CAndroidGUIEditBox::addAndroidEditBox(L"", true, env, Resize(150, 60 + 100 / 6, 190, 80 + 100 / 6), wFilter, EDITBOX_INPUTS);
ebScale->setTextAlignment(irr::gui::EGUIA_CENTER, irr::gui::EGUIA_CENTER);
// 筛选卡片的条件:关键字
env->addStaticText(dataManager.GetSysString(1325)/*关键字:*/, Resize(205, 60 + 100 / 6, 280, 82 + 100 / 6), false, false, wFilter);
ebCardName = irr::gui::CAndroidGUIEditBox::addAndroidEditBox(L"", true, env, Resize(260, 72, 390, 92), wFilter, EDITBOX_KEYWORD);
ebCardName->setTextAlignment(irr::gui::EGUIA_CENTER, irr::gui::EGUIA_CENTER);
btnEffectFilter = env->addButton(Resize(345, 28, 390, 69), wFilter, BUTTON_EFFECT_FILTER, dataManager.GetSysString(1326));
// 筛选卡片的条件:效果
btnEffectFilter = env->addButton(Resize(345, 28, 390, 69), wFilter, BUTTON_EFFECT_FILTER, dataManager.GetSysString(1326)/*效果*/);
ChangeToIGUIImageButton(btnEffectFilter, imageManager.tButton_C, imageManager.tButton_C_pressed);
btnStartFilter = env->addButton(Resize(210, 96, 390, 118), wFilter, BUTTON_START_FILTER, dataManager.GetSysString(1327));
ChangeToIGUIImageButton(btnStartFilter, imageManager.tButton_L, imageManager.tButton_L_pressed);
......
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