feat: 肉鸽商店支持按优先级购买

This commit is contained in:
MistEO
2022-07-29 00:37:27 +08:00
parent fdbc4561ee
commit df7fac94fe
12 changed files with 648 additions and 4 deletions

View File

@@ -0,0 +1,413 @@
[
{
"name": "金酒之杯"
},
{
"name": "骑士戒律·新编"
},
{
"name": "投币玩具"
},
{
"name": "锈蚀的铁锤"
},
{
"name": "幸运硬币"
},
{
"name": "“时光之末”"
},
{
"name": "人事部密信"
},
{
"name": "四叶草化石"
},
{
"name": "全局作战文件"
},
{
"name": "《旧高卢地名源流考》"
},
{
"name": "赤金的远征"
},
{
"name": "长生者之证"
},
{
"name": "假面舞会面具"
},
{
"name": "“逝者垂泪”"
},
{
"name": "血魔的寝床"
},
{
"name": "石像鬼塑像"
},
{
"name": "特殊抑制器"
},
{
"name": "《杜林地上环游记》"
},
{
"name": "维多利亚蛋糕"
},
{
"name": "试制巧克力"
},
{
"name": "乌萨斯列巴"
},
{
"name": "源石鸢尾花"
},
{
"name": "铁棍面包"
},
{
"name": "高卢小圆饼"
},
{
"name": "苦行者泡芙"
},
{
"name": "玻璃小鸟"
},
{
"name": "《第二经济改革法》"
},
{
"name": "高卢银行支票"
},
{
"name": "爱丽舍钱袋"
},
{
"name": "古高卢银币"
},
{
"name": "迷迭香之拥"
},
{
"name": "古怪的长笛"
},
{
"name": "镶金骨骰"
},
{
"name": "独奏八音盒"
},
{
"name": "银餐叉"
},
{
"name": "猩红剧团票根"
},
{
"name": "“黑夜呢喃”"
},
{
"name": "蓝色丝巾"
},
{
"name": "贵族刺剑"
},
{
"name": "赶车夫的长鞭"
},
{
"name": "空白名片"
},
{
"name": "红色蝴蝶结"
},
{
"name": "破损的面具"
},
{
"name": "黄铜指南针"
},
{
"name": "073号安全试剂"
},
{
"name": "昏暗的提灯"
},
{
"name": "绿叶菜罐头"
},
{
"name": "女皇之愿"
},
{
"name": "路线说明图"
},
{
"name": "莱塔尼亚荣誉勋章"
},
{
"name": "至宝指环"
},
{
"name": "维多利亚“废铁”勋章"
},
{
"name": "远程协议-遥击"
},
{
"name": "远程协议-克敌"
},
{
"name": "破坏协议-消除"
},
{
"name": "破坏协议-压制"
},
{
"name": "万能钥匙"
},
{
"name": "突击协议-利刃"
},
{
"name": "解约协议"
},
{
"name": "折戟-浴血",
"role": "WARRIOR"
},
{
"name": "古旧乐谱残章"
},
{
"name": "被撬开的道具箱"
},
{
"name": "“聚焦”"
},
{
"name": "Miss.Christine摸摸券"
},
{
"name": "尖笑鬼牌"
},
{
"name": "开裂的束缚带"
},
{
"name": "老蒲扇"
},
{
"name": "地区行动方案"
},
{
"name": "“噤声”"
},
{
"name": "折戟-典训",
"role": "WARRIOR"
},
{
"name": "“迷醉荷谟伊”"
},
{
"name": "残弩-典训",
"role": "SNIPER"
},
{
"name": "断杖-典训",
"role": "CASTER"
},
{
"name": "支柱-典训",
"role": "SUPPORT"
},
{
"name": "钝爪-典训",
"role": "PIONEER"
},
{
"name": "安洁莉娜的创想"
},
{
"name": "食腐者手杖"
},
{
"name": "“绽放”"
},
{
"name": "折戟-突破",
"role": "WARRIOR"
},
{
"name": "折戟-锋刃",
"role": "WARRIOR"
},
{
"name": "皇家利口酒"
},
{
"name": "“童趣玩偶”"
},
{
"name": "悬丝傀儡"
},
{
"name": "“当红歌手”"
},
{
"name": "残弩-神速",
"role": "SNIPER"
},
{
"name": "迷梦香精"
},
{
"name": "折戟-一夫当关",
"role": "WARRIOR"
},
{
"name": "残弩-战场依存",
"role": "SNIPER"
},
{
"name": "女妖之吻"
},
{
"name": "残弩-百步穿杨",
"role": "SNIPER"
},
{
"name": "折戟-破釜沉舟",
"role": "WARRIOR"
},
{
"name": "微缩舞台模型"
},
{
"name": "钝爪-爆发",
"role": "PIONEER"
},
{
"name": "钝爪-百战",
"role": "PIONEER"
},
{
"name": "钝爪-熟稔",
"role": "PIONEER"
},
{
"name": "断杖-咏唱",
"role": "CASTER"
},
{
"name": "断杖-织法者",
"role": "CASTER"
},
{
"name": "断杖-凝神",
"role": "CASTER"
},
{
"name": "医者-妙手",
"role": "MEDIC"
},
{
"name": "医者-理智固剂",
"role": "MEDIC"
},
{
"name": "皇族金胸针"
},
{
"name": "人偶之家"
},
{
"name": "显圣吊坠"
},
{
"name": "苍白花冠"
},
{
"name": "活玫瑰"
},
{
"name": "皇帝的收藏"
},
{
"name": "制式防暴用具"
},
{
"name": "锈蚀刀片"
},
{
"name": "急救药箱"
},
{
"name": "难闻的止血剂"
},
{
"name": "精神治疗录像带"
},
{
"name": "高闪相机"
},
{
"name": "凯旋号角"
},
{
"name": "舞者手链"
},
{
"name": "设计师量尺"
},
{
"name": "“法术杀手”"
},
{
"name": "演出用香水"
},
{
"name": "生命之水"
},
{
"name": "摩根队长佳酿"
},
{
"name": "荒地龙舌兰"
},
{
"name": "羽兽肝酱"
},
{
"name": "香草沙士汽水"
},
{
"name": "球球果汁"
},
{
"name": "作者的喉舌"
},
{
"name": "皇帝的恩宠"
},
{
"name": "残破合影"
},
{
"name": "奇渊面具"
},
{
"name": "Scout的狙击镜"
},
{
"name": "军团护心镜"
},
{
"name": "异铁小圆盾"
}
]

View File

@@ -6460,12 +6460,13 @@
},
"Roguelike1TraderRandomShopping": {
"action": "ClickSelf",
"templThreshold": 0.7,
"cache": false,
"roi": [
427,
374,
661,
196
480,
240,
750,
280
],
"next": [
"Roguelike1TraderRandomShoppingConfirm",
@@ -6476,6 +6477,56 @@
255
]
},
"Roguelike1TraderShopping": {
"template": "Roguelike1TraderRandomShopping.png",
"templThreshold": 0.7,
"roi": [
480,
240,
750,
280
],
"maskRange": [
1,
255
]
},
"Roguelike1TraderShoppingOcr": {
"algorithm": "OcrDetect",
"text": [],
"roi": [
-120,
-160,
190,
35
],
"ocrReplace": [
]
},
"Roguelike1TraderShoppingConfirm": {
"template": "Roguelike1TraderRandomShoppingConfirm.png",
"action": "ClickSelf",
"cache": false,
"roi": [
872,
425,
221,
136
],
"rearDelay": 1000
},
"Roguelike1TraderShoppingCancel": {
"template": "Roguelike1StageTraderInvestCancel.png",
"action": "ClickSelf",
"cache": false,
"roi": [
350,
350,
500,
250
]
},
"Roguelike1TraderRandomShoppingConfirm": {
"action": "ClickSelf",
"cache": false,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -90,6 +90,8 @@
<ClInclude Include="RoguelikeFormationImageAnalyzer.h" />
<ClInclude Include="RoguelikeRecruitImageAnalyzer.h" />
<ClInclude Include="RoguelikeRecruitTaskPlugin.h" />
<ClInclude Include="RoguelikeShoppingConfiger.h" />
<ClInclude Include="RoguelikeShoppingTaskPlugin.h" />
<ClInclude Include="RoguelikeSkillSelectionImageAnalyzer.h" />
<ClInclude Include="RoguelikeSkillSelectionTaskPlugin.h" />
<ClInclude Include="RoguelikeTask.h" />
@@ -178,6 +180,8 @@
<ClCompile Include="RoguelikeFormationImageAnalyzer.cpp" />
<ClCompile Include="RoguelikeRecruitImageAnalyzer.cpp" />
<ClCompile Include="RoguelikeRecruitTaskPlugin.cpp" />
<ClCompile Include="RoguelikeShoppingConfiger.cpp" />
<ClCompile Include="RoguelikeShoppingTaskPlugin.cpp" />
<ClCompile Include="RoguelikeSkillSelectionImageAnalyzer.cpp" />
<ClCompile Include="RoguelikeSkillSelectionTaskPlugin.cpp" />
<ClCompile Include="RoguelikeTask.cpp" />
@@ -200,6 +204,7 @@
<None Include="..\..\resource\infrast.json" />
<None Include="..\..\resource\roguelike_copilot.json" />
<None Include="..\..\resource\roguelike_recruit.json" />
<None Include="..\..\resource\roguelike_shopping.json" />
<None Include="..\..\resource\tasks.json" />
</ItemGroup>
<PropertyGroup Label="Globals">

View File

@@ -360,6 +360,12 @@
<ClInclude Include="BattleDataConfiger.h">
<Filter>头文件\Resource</Filter>
</ClInclude>
<ClInclude Include="RoguelikeShoppingConfiger.h">
<Filter>头文件\Resource</Filter>
</ClInclude>
<ClInclude Include="RoguelikeShoppingTaskPlugin.h">
<Filter>头文件\Task\Plugin\Roguelike</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Controller.cpp">
@@ -620,6 +626,12 @@
<ClCompile Include="BattleDataConfiger.cpp">
<Filter>源文件\Resource</Filter>
</ClCompile>
<ClCompile Include="RoguelikeShoppingConfiger.cpp">
<Filter>源文件\Resource</Filter>
</ClCompile>
<ClCompile Include="RoguelikeShoppingTaskPlugin.cpp">
<Filter>源文件\Task\Plugin\Roguelike</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\..\resource\config.json">
@@ -637,5 +649,8 @@
<None Include="..\..\resource\roguelike_copilot.json">
<Filter>资源文件</Filter>
</None>
<None Include="..\..\resource\roguelike_shopping.json">
<Filter>资源文件</Filter>
</None>
</ItemGroup>
</Project>

View File

@@ -28,6 +28,7 @@ bool asst::Resource::load(const std::string& dir)
constexpr static auto StageDropsCfgFilename = "stages.json";
constexpr static auto StageDropsTempls = "template/items";
constexpr static auto BattleDataCfgFilename = "battle_data.json";
constexpr static auto RoguelikeShoppingCfgFilename = "roguelike_shopping.json";
bool overload = false;
@@ -168,6 +169,17 @@ bool asst::Resource::load(const std::string& dir)
overload = true;
}
// 加载肉鸽购物需要的数据
if (!m_roguelike_shopping_cfg_unique_ins.load(dir + RoguelikeShoppingCfgFilename)) {
if (!m_loaded) {
m_last_error = std::string(RoguelikeShoppingCfgFilename) + ": " + m_roguelike_shopping_cfg_unique_ins.get_last_error();
return false;
}
}
else {
overload = true;
}
/* 加载OCR库所需要的资源 */
//m_ocr_pack_unique_ins.set_param(opt.ocr_gpu_index, opt.ocr_thread_number);
if (!m_ocr_pack_unique_ins.load(dir + OcrResourceFilename)) {

View File

@@ -18,6 +18,7 @@
#include "RoguelikeCopilotConfiger.h"
#include "StageDropsConfiger.h"
#include "BattleDataConfiger.h"
#include "RoguelikeShoppingConfiger.h"
namespace asst
{
@@ -82,6 +83,10 @@ namespace asst
{
return m_battle_data_cfg_unique_ins;
}
RoguelikeShoppingConfiger& roguelike_shopping() noexcept
{
return m_roguelike_shopping_cfg_unique_ins;
}
const TemplResource& templ() const noexcept
{
@@ -131,6 +136,10 @@ namespace asst
{
return m_battle_data_cfg_unique_ins;
}
const RoguelikeShoppingConfiger& roguelike_shopping() const noexcept
{
return m_roguelike_shopping_cfg_unique_ins;
}
Resource& operator=(const Resource&) = delete;
Resource& operator=(Resource&&) noexcept = delete;
@@ -150,6 +159,7 @@ namespace asst
TilePack m_tile_pack_unique_ins;
StageDropsConfiger m_stage_drops_cfg_unique_ins;
BattleDataConfiger m_battle_data_cfg_unique_ins;
RoguelikeShoppingConfiger m_roguelike_shopping_cfg_unique_ins;
bool m_loaded = false;
};

View File

@@ -0,0 +1,27 @@
#include "RoguelikeShoppingConfiger.h"
#include <meojson/json.hpp>
bool asst::RoguelikeShoppingConfiger::parse(const json::value& json)
{
for (const auto& commodity_json : json.as_array()) {
std::string name = commodity_json.at("name").as_string();
static const std::unordered_map<std::string, BattleRole> RoleMap = {
{ "CASTER", BattleRole::Caster },
{ "MEDIC", BattleRole::Medic },
{ "PIONEER", BattleRole::Pioneer },
{ "SNIPER", BattleRole::Sniper},
{ "SPECIAL", BattleRole::Special},
{ "SUPPORT", BattleRole::Support},
{ "TANK", BattleRole::Tank},
{ "WARRIOR", BattleRole::Warrior},
};
BattleRole role = BattleRole::Unknown;
std::string str_role = commodity_json.get("role", "");
if (!str_role.empty()) {
role = RoleMap.at(str_role);
}
m_goods.emplace_back(RoguelikeGoods{ name, role });
}
return true;
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include "AbstractConfiger.h"
#include <vector>
#include "AsstBattleDef.h"
namespace asst
{
struct RoguelikeGoods
{
std::string name;
BattleRole restriction = BattleRole::Unknown;
};
class RoguelikeShoppingConfiger : public AbstractConfiger
{
public:
virtual ~RoguelikeShoppingConfiger() = default;
const auto& get_goods() const noexcept
{
return m_goods;
}
private:
virtual bool parse(const json::value& json) override;
std::vector<RoguelikeGoods> m_goods;
};
}

View File

@@ -0,0 +1,58 @@
#include "RoguelikeShoppingTaskPlugin.h"
#include "OcrWithFlagTemplImageAnalyzer.h"
#include "Resource.h"
#include "Controller.h"
#include "ProcessTask.h"
bool asst::RoguelikeShoppingTaskPlugin::verify(AsstMsg msg, const json::value& details) const
{
if (msg != AsstMsg::SubTaskStart
|| details.get("subtask", std::string()) != "ProcessTask") {
return false;
}
if (details.at("details").at("task").as_string() == "Roguelike1TraderRandomShopping") {
return true;
}
else {
return false;
}
}
bool asst::RoguelikeShoppingTaskPlugin::_run()
{
OcrWithFlagTemplImageAnalyzer analyzer;
analyzer.set_task_info("Roguelike1TraderShopping", "Roguelike1TraderShoppingOcr");
analyzer.set_image(m_ctrler->get_image());
if (!analyzer.analyze()) {
return false;
}
const auto& result = analyzer.get_result();
const auto& order_goods_list = Resrc.roguelike_shopping().get_goods();
for (const auto& goods : order_goods_list) {
if (goods.restriction != BattleRole::Unknown) {
// TODO
continue;
}
auto find_it = std::find_if(result.cbegin(), result.cend(),
[&](const TextRect& tr) -> bool {
return tr.text == goods.name;
});
if (find_it == result.cend()) {
continue;
}
m_ctrler->click(find_it->rect);
bool confirmed = ProcessTask(*this, { "Roguelike1TraderShoppingConfirm" })
.set_retry_times(5)
.run();
if (!confirmed) {
return false;
}
}
return true;
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include "AbstractTaskPlugin.h"
namespace asst
{
class RoguelikeShoppingTaskPlugin : public AbstractTaskPlugin
{
public:
using AbstractTaskPlugin::AbstractTaskPlugin;
virtual ~RoguelikeShoppingTaskPlugin() = default;
virtual bool verify(AsstMsg msg, const json::value& details) const override;
protected:
virtual bool _run() override;
private:
};
}

View File

@@ -8,6 +8,7 @@
#include "RoguelikeBattleTaskPlugin.h"
#include "RoguelikeControlTaskPlugin.h"
#include "RoguelikeCustomStartTaskPlugin.h"
#include "RoguelikeShoppingTaskPlugin.h"
#include "Logger.hpp"
@@ -20,6 +21,7 @@ asst::RoguelikeTask::RoguelikeTask(const AsstCallback& callback, void* callback_
m_roguelike_task_ptr->regiseter_plugin<RoguelikeFormationTaskPlugin>();
m_roguelike_task_ptr->regiseter_plugin<RoguelikeControlTaskPlugin>();
m_roguelike_task_ptr->regiseter_plugin<RoguelikeShoppingTaskPlugin>();
m_custom_start_task_ptr = m_roguelike_task_ptr->regiseter_plugin<RoguelikeCustomStartTaskPlugin>();
m_battle_task_ptr = m_roguelike_task_ptr->regiseter_plugin<RoguelikeBattleTaskPlugin>();