From de59bbf87f9ae797ece9528b103002c03f72e7f9 Mon Sep 17 00:00:00 2001 From: MistEO Date: Sun, 20 Mar 2022 01:25:33 +0800 Subject: [PATCH] =?UTF-8?q?feat.=E5=AE=8C=E6=88=90=E6=9C=80=E5=9F=BA?= =?UTF-8?q?=E6=9C=AC=E7=9A=84=E6=8A=84=E4=BD=9C=E4=B8=9A=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E3=80=82=E9=87=8D=E6=9E=84=E4=BA=86=E4=B8=80=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/战斗流程协议.md | 9 +- resource/battle/test.json | 57 ++ resource/tasks.json | 42 +- resource/template/BattleKillsFlag.png | Bin 0 -> 4347 bytes src/MeoAssistant/AbstractImageAnalyzer.cpp | 4 +- src/MeoAssistant/AbstractImageAnalyzer.h | 4 +- src/MeoAssistant/AsstBattleDef.h | 36 +- src/MeoAssistant/AsstInfrastDef.h | 2 +- src/MeoAssistant/AutoRecruitTask.cpp | 2 +- src/MeoAssistant/BattleConfiger.cpp | 10 +- src/MeoAssistant/BattleConfiger.h | 12 +- src/MeoAssistant/BattleImageAnalyzer.cpp | 128 ++- src/MeoAssistant/BattleImageAnalyzer.h | 57 +- .../BattlePerspectiveImageAnalyzer.cpp | 90 -- .../BattlePerspectiveImageAnalyzer.h | 26 - src/MeoAssistant/BattleProcessTask.cpp | 190 ++++ src/MeoAssistant/BattleProcessTask.h | 38 + src/MeoAssistant/Controller.cpp | 22 +- src/MeoAssistant/CreditShopImageAnalyzer.cpp | 2 +- src/MeoAssistant/CreditShoppingTask.cpp | 2 +- src/MeoAssistant/DebugTask.cpp | 8 +- src/MeoAssistant/InfrastClueImageAnalyzer.cpp | 2 +- .../InfrastClueVacancyImageAnalyzer.cpp | 2 +- .../InfrastFacilityImageAnalyzer.cpp | 3 +- src/MeoAssistant/InfrastOfficeTask.cpp | 2 +- src/MeoAssistant/InfrastOperImageAnalyzer.cpp | 7 +- src/MeoAssistant/InfrastOperImageAnalyzer.h | 4 +- src/MeoAssistant/InfrastPowerTask.cpp | 2 +- src/MeoAssistant/InfrastProductionTask.cpp | 14 +- src/MeoAssistant/InfrastProductionTask.h | 2 +- src/MeoAssistant/InfrastReceptionTask.cpp | 1 - .../InfrastSmileyImageAnalyzer.cpp | 3 +- src/MeoAssistant/MatchImageAnalyzer.cpp | 5 + src/MeoAssistant/MatchImageAnalyzer.h | 1 + src/MeoAssistant/MeoAssistant.vcxproj | 4 +- src/MeoAssistant/MeoAssistant.vcxproj.filters | 12 +- src/MeoAssistant/MultiMatchImageAnalyzer.cpp | 5 + src/MeoAssistant/MultiMatchImageAnalyzer.h | 1 + src/MeoAssistant/OcrImageAnalyzer.cpp | 5 + src/MeoAssistant/OcrImageAnalyzer.h | 1 + src/MeoAssistant/ProcessTask.cpp | 4 + src/MeoAssistant/RecruitImageAnalyzer.cpp | 6 +- src/MeoAssistant/Resource.cpp | 11 + src/MeoAssistant/Resource.h | 10 + .../RoguelikeBattleTaskPlugin.cpp | 823 +++++++++--------- src/MeoAssistant/RoguelikeBattleTaskPlugin.h | 3 +- .../RoguelikeFormationImageAnalyzer.cpp | 6 +- .../RoguelikeFormationImageAnalyzer.h | 6 +- .../RoguelikeRecruitTaskPlugin.cpp | 2 +- .../RoguelikeSkillSelectionImageAnalyzer.cpp | 2 +- src/MeoAssistant/RoguelikeTask.cpp | 114 +-- tools/TestCaller/main.cpp | 36 +- 52 files changed, 1103 insertions(+), 737 deletions(-) create mode 100644 resource/battle/test.json create mode 100644 resource/template/BattleKillsFlag.png delete mode 100644 src/MeoAssistant/BattlePerspectiveImageAnalyzer.cpp delete mode 100644 src/MeoAssistant/BattlePerspectiveImageAnalyzer.h create mode 100644 src/MeoAssistant/BattleProcessTask.cpp create mode 100644 src/MeoAssistant/BattleProcessTask.h diff --git a/docs/战斗流程协议.md b/docs/战斗流程协议.md index c07e086de5..7ff2cf9d4f 100644 --- a/docs/战斗流程协议.md +++ b/docs/战斗流程协议.md @@ -78,6 +78,13 @@ { "type": 100 } - ] + ], + "minimum_required": "v4.0", // 最低要求 maa 版本号,必选。保留字段 + "desc": { // 描述,可选,保留字段。 + // 后期完成了作业分享平台后,可能直接展示该字段给其他用户看 + "title": "低练度高成功率作业", + "details": "对练度要求很低balabala……", + "requirements": "棘刺精二、任意群奶、……" + }, } ``` diff --git a/resource/battle/test.json b/resource/battle/test.json new file mode 100644 index 0000000000..c7e968d0c3 --- /dev/null +++ b/resource/battle/test.json @@ -0,0 +1,57 @@ +{ + "minimum_required": "v4.0", + "desc": { + "title": "Hello World", + "details": "第一份测试作业", + "requirements": "" + }, + "stage_name": "切尔诺伯格", + "opers": [ + { + "name": "能天使" + }, + { + "name": "嵯峨" + }, + { + "name": "橙闪" + }, + { + "name": "临光" + } + ], + "actions": [ + { + "name": "嵯峨", + "location": [ + 8, + 5 + ], + "direction": 2 + }, + { + "name": "能天使", + "location": [ + 9, + 5 + ], + "direction": 2 + }, + { + "name": "橙闪", + "location": [ + 7, + 4 + ], + "direction": 2 + }, + { + "name": "临光", + "location": [ + 8, + 4 + ], + "direction": 2 + } + ] +} diff --git a/resource/tasks.json b/resource/tasks.json index 17a8582530..612cf47f4a 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -3265,6 +3265,44 @@ 60 ] }, + "BattlePause": { + "algorithm": "JustReturn", + "action": "ClickRect", + "specificRect": [ + 1170, + 20, + 60, + 60 + ] + }, + "BattleCancelSelection": { + "algorithm": "JustReturn", + "action": "ClickSelf", + "specificRect": [ + 150, + 0, + 1000, + 60 + ] + }, + "BattleKillsFlag": { + "roi": [ + 150, + 0, + 600, + 60 + ], + "rectMove": [ + 50, + 0, + 150, + 60 + ], + "maskRange": [ + 1, + 255 + ] + }, "BattleUseOper": { "algorithm": "JustReturn", "preDelay": 500, @@ -3293,9 +3331,9 @@ "BattleOperClickRange": { "algorithm": "JustReturn", "rectMove": [ - -59, + -45, 6, - 98, + 75, 120 ] }, diff --git a/resource/template/BattleKillsFlag.png b/resource/template/BattleKillsFlag.png new file mode 100644 index 0000000000000000000000000000000000000000..51d7d5ba62b1a9b2554abc636e3bd568df6a1f2d GIT binary patch literal 4347 zcmVyb;mz5zwQ0rrYGq=?Y89I3fRUtW-$iBl0tw`0tuy<5Yi+hCuyK3A#F$?36wVU zu%w}okTf}@O->ftG|+@4WC0Es1HlW67bF`C%a$zL(vzOv_SS32gjVW^@lg~3@QsV+ zpd+8#emip9xn0NR@7AVS+E`|9$>FDO<<{ zB&ife-&MCMn~vMvhMb{5eBOP> z`3=L=j+@eso6`4O)}{5G=)#vx-P)MePD9Ia*O=<^oh*wb(li)8f4ZhfA|7(vh8}Kx z#zz0$QsJ2I9-;t#wM?m>l)AM~g_jr7H>&VTh1tp{8gN9wQ`fqzTQ)*Q zg#2<>3%6~V$9+5JaB1f#|XY{x7h2CKg+t*`gcS4^-bTi~vhZ*kL-LGF5UE?dTveDA$GIVD>p z@0q-KD9MvUjo1O4w5Q5S~p8j%*>w1eM(EP{d*&%!c3YnJ8 z=_{6Ue(N~94kmbR+Ypg|q>z*b(zJQ}nl#-V74Cbbi@SErA<}}&x(@N+dR)3_l>c12ldHQ&2^4&DTPOFv*hzO=g(ub}n7erSwBkYt0Q_o&XSWX1 zHuy6yuY;9J}0Pzfcjp}2m* zFkRUSl*M7Ox+jGO6i^nlHhEmrbBMSRQH=z5yw(K@uA6s&DDY=NW&8XS**4*VhLal0 z2x$<_pg+?FNGXW|kNJrzm6FLo$szR0M@(kf4riadlrwV^>>YL4luu$xP1Xrm*;uR> zcX8O@seehD%J7s#XepY?aLtq{i)nno)iV})P= zs)qNb5n&1qLSs6rhIf$y8*;ILPzgpon~|#E(V<4Z+*ahWRc-uYAV*^?z^EHN=1Zzd za;y=|z>YUe6Fu{S)k|2MtT5`EG{?qBnh|;5gxtdAO%=b6E_q$oZn5}v&cCab`@iYA6?aQQAK zhr?(flwhb@07}4sJ2&=le_sbpPKYT45eBBz6ax?{AYnuVN>d69KDp=sH?JD3&82_{ zh-7U|qyAeQxn>j^7*c^z&yghjWOEzlrhJl??ODdE7HKo&;*L@BzR42<%}A*+>KUmJ z1WK^1p~TAUB?p)Z+YzA>O!@|2>>b20G+KeLO&%Z45to_|wvUiBBZSaYm0*9_ z;b(n0ECCa~!IE^9wQUo;b|}TG`2@BRA?g-HfY5>qJI06`@c5o4Dv_iq7P8?$4D*3M zyv6ry7wK43@(0P^WHTOEeC>@M_7Cntc{Rur(tuco&z#c6%C-W(-k0TH`#R~2dsIS$ zmYC1KukK^@f{8lfz$^I%K=b!21|eSa>iYf$KE1P*AMeiMnwtHd&6k$$W9^)AR(y97 zn8dPUP%moIa_E}Bl+{f|hy{G;#|MceGelmQAQ(kPVTf0rBr4}IOp}Sgq&4Q#>3S%y zgjcEcYN>#(Co7K~NJg4-0uX zZj#}OL3g@Ls~aGWg0#@D@cWmx^4hW_XLsaT(pP3vK1G@kDKvX3HlKcF3Fo}s%IUcR zYqApv6yJHHla~)9c=}+PPz%ylL^+ZaeS`OAi>z&*;EmBFPz0DRR6ltC^q)Ve6 zk}xCCP*Elu#v0gNN$|tf+W`2R4GY;{k#xpA;)X_P2(`cj{%YxI8)9pj%W6%5lP3d8C5D)9LEo*W6;~ z53(Rt#+I6xoI))@R4-U9F&~ZKq0{@2)SyvOtJF$ERY~5{P+|Q*0}tzRR9SMsw$0_J=1D0os44Bq*Yy&uMl8h@^+dje0e1c88Mlel_ zFgzSWM{uDi3~|%V{CuzlnNVEbaS&qxUen5UoJSv4QDLip@AHWnk_>47L*|fB$lnf5}@i@s0ajvN)mRPcAbtlvrYtjgCY#SZRa7|C1%TE|(^R5)P{QeE1V|f4g1_S|) zo8ab+ZG7sGN251_Jyv0GOz{K%0CQZhUB$^cldcvAI}ZB~l^Gk2s2C<=MZwruNP!v^ zaD^hS!Es^Pe22D74BNJdg^J1XBEB%uhGfeg#k^c6R@$OBJ;Lu^Z{Xe?u^JxCNbZ^K znAa*$ztGKg5smMqMQdVlD1-)$PDDHgmV|5>=Cne4x5@CRV&5J`8SoWMPD1E_6$di{ zI}&Iq$+{647uvgA;##n0XPL_eJi(0O^=BDi+cr@Y zalr?#;N$B)LbEE6A0Nj|B#9>+e)Xe&qwlrXu?%>7(5G##%SD%5!lB{4RJ7#skKah( z`IL$UR2Y(QV!X29MIL+PVUj6};h{X`60~<(m{y8-tci2ZJ(oRiz0THGH*(fRAECeG z@aUtD;8#lc{_NA*R6FLSscqXD&<{NDpw?RJyT5jmKC`=1fAqA)dfllf>TA}_*L_;3x%^k+YOu3p)IJ}|Ubzy89L`kS}hsI}Jm>0kX+U$mk}UwLYezIyEm`s&k{=$D`V zt)3Vk)i+;%rM~jCUj5dN&3bp=R(;o3KdZIY`hR}cK>F(B!Wog4O zj;ZG{b6{pG6!HMPJz8RaWU|nd?Cal#bR9b9^~+(CoNkAhKm;oip3gQlnUb* zhQP8dM)nR<93P{jtA}($6Bk^1Df{2kK|^B;ndTNMl``mnZ0B6M<}W7M(9GbTJ^0ls zhL8k$_LU~Q!{zQ&o2tU^fB!{%?D|h~^$j<2=EY|bQsXVVHow5VU;Qe!3)x%-uUtf{ zn#>8S&*0k6e}Rww?HBpLB^QuPI#jC_lnVL&x9{fmTff7OS2rRJlP%9b$4AdzMO#Y? zPe1ztPd)J)&RDaC(a}*N!EwXqT|?;Jd+yO%YkkI<@6&+p5$JBv=P!wCKMeJOt(){o z7J5|tFng)>`Wy-0>xy1HA}z59m{y(Ib0yX|1*X;EFDt1^w#F&uFc+ zzG}@v4d@5Ib+^`9>x(bGxc05Vc69wK(*G}nrfRILQ`@Wm`YO6R8d=_xMJkJ3eVd3P zMLdxr<^neCetR#&dxvU=AK>)&U&`l3@+1-hRK(DZSEt{_;t3oe<|Y9!ESoeiIay?E ze1i4sp9er`#XEgPIxY%XrinmsVs9_KC!UDqy2R~(u7(6L!{Wu~en(SVJC*^jJo7YC z3tH!$KqV}I1t%^)m9(2A=EP8jKuDjyO@G3Pr)g@=^86p3B7dmJnHQWzb7MOjo_vDQ z17+R_B~{-iX4^IVkD_B<>A$N1P=itxgoHEhELTZr5@2VbSOM+8niVFkLa=*hK%N>$ zJ1_)Z08)Z5K-v&bgDyZ+g?Wp>iNUTu@XB!d3NTU)eCwqm#UR45Z6c)z!|-_O0mrGt zQ_c5%48vgQ{6+ZMpvi_C7Vl?CvczO$V7Z_SXpd_;g`%?5X0#eoRSFI4_Z@;r;#eUu zJ3s@5XCVTUc(UfV$%WuJu%JDpub_FVu!t>vdkFmMJBH4mWq=R@r4(=O+=*p7oN)T7 ztUKu-G8@#~JC!IQpdo2MZYHiNZ<_N@lQ|vK1fu%J8`Q>FkQ)hTO2 #include +#include + #include "AsstTypes.h" namespace asst @@ -16,14 +18,14 @@ namespace asst NotUse = 3, // 不自动使用 OnceUsed }; - struct BattleOper // 干员 + struct BattleDeployOper // 干员 { std::string name; int skill = 1; // 技能序号,取值范围 [1, 3] BattleSkillUsage skill_usage = BattleSkillUsage::Possibly; }; - enum class DeployDirection + enum class BattleDeployDirection { Right = 0, Down = 1, @@ -47,15 +49,39 @@ namespace asst BattleActionType type = BattleActionType::Deploy; std::string group_name; // 目标名,若 type >= SwitchSpeed, group_name 为空 Point location; - DeployDirection direction = DeployDirection::Right; + BattleDeployDirection direction = BattleDeployDirection::Right; int pre_delay = 0; int rear_delay = 0; int time_out = INT_MAX; }; - struct BattleActions + struct BattleActionsGroup { - std::unordered_map> opers_groups; + std::unordered_map> opers_groups; std::vector actions; }; + + enum class BattleRole + { + Unknown, + Caster, + Medic, + Pioneer, + Sniper, + Special, + Support, + Tank, + Warrior, + Drone + }; + + struct BattleRealTimeOper + { + int cost = 0; + BattleRole role = BattleRole::Unknown; + bool available = false; + Rect rect; + cv::Mat avatar; + std::string name; + }; } diff --git a/src/MeoAssistant/AsstInfrastDef.h b/src/MeoAssistant/AsstInfrastDef.h index b5dbf0ba47..d9dc871c90 100644 --- a/src/MeoAssistant/AsstInfrastDef.h +++ b/src/MeoAssistant/AsstInfrastDef.h @@ -68,7 +68,7 @@ namespace asst { namespace infrast { - struct Oper + struct BattleRealTimeOper { ::std::string face_hash; // 有些干员的技能是完全一样的,做个hash区分一下不同干员 ::std::string name_hash; // 预留 diff --git a/src/MeoAssistant/AutoRecruitTask.cpp b/src/MeoAssistant/AutoRecruitTask.cpp index 0f75064b1b..283dffbeba 100644 --- a/src/MeoAssistant/AutoRecruitTask.cpp +++ b/src/MeoAssistant/AutoRecruitTask.cpp @@ -80,7 +80,7 @@ bool asst::AutoRecruitTask::_run() bool asst::AutoRecruitTask::analyze_start_buttons() { OcrImageAnalyzer start_analyzer; - start_analyzer.set_task_info(Task.get("StartRecruit")); + start_analyzer.set_task_info("StartRecruit"); auto image = m_ctrler->get_image(); start_analyzer.set_image(image); diff --git a/src/MeoAssistant/BattleConfiger.cpp b/src/MeoAssistant/BattleConfiger.cpp index 2f1f67167e..ad464282a9 100644 --- a/src/MeoAssistant/BattleConfiger.cpp +++ b/src/MeoAssistant/BattleConfiger.cpp @@ -8,14 +8,14 @@ bool asst::BattleConfiger::parse(const json::value& json) { std::string stage_name = json.at("stage_name").as_string(); - BattleActions battle_actions; + BattleActionsGroup battle_actions; if (json.contains("opers_groups")) { for (const auto& group_info : json.at("opers_groups").as_array()) { std::string group_name = group_info.at("name").as_string(); - std::vector oper_vec; + std::vector oper_vec; for (const auto& oper_info : group_info.at("opers").as_array()) { - BattleOper oper; + BattleDeployOper oper; oper.name = oper_info.at("name").as_string(); oper.skill = oper_info.get("skill", 1); oper.skill_usage = static_cast(oper_info.get("skill_usage", 0)); @@ -27,7 +27,7 @@ bool asst::BattleConfiger::parse(const json::value& json) if (json.contains("opers")) { for (const auto& oper_info : json.at("opers").as_array()) { - BattleOper oper; + BattleDeployOper oper; oper.name = oper_info.at("name").as_string(); oper.skill = oper_info.get("skill", 1); oper.skill_usage = static_cast(oper_info.get("skill_usage", 0)); @@ -48,7 +48,7 @@ bool asst::BattleConfiger::parse(const json::value& json) action.location.x = action_info.get("location", 0, 0); action.location.y = action_info.get("location", 1, 0); - action.direction = static_cast(action_info.get("direction", 0)); + action.direction = static_cast(action_info.get("direction", 0)); action.pre_delay = action_info.get("pre_delay", 0); action.rear_delay = action_info.get("rear_delay", 0); action.time_out = action_info.get("timeout", INT_MAX); diff --git a/src/MeoAssistant/BattleConfiger.h b/src/MeoAssistant/BattleConfiger.h index db74ee27e1..ee5d95a0aa 100644 --- a/src/MeoAssistant/BattleConfiger.h +++ b/src/MeoAssistant/BattleConfiger.h @@ -8,8 +8,18 @@ namespace asst { public: virtual ~BattleConfiger() = default; + + bool contains_actions(const std::string& stage_name) const noexcept + { + return m_battle_actions.find(stage_name) != m_battle_actions.cend(); + } + + auto get_actions(const std::string& stage_name) const noexcept + { + return m_battle_actions.at(stage_name); + } protected: virtual bool parse(const json::value& json) override; - std::unordered_map m_battle_actions; + std::unordered_map m_battle_actions; }; } diff --git a/src/MeoAssistant/BattleImageAnalyzer.cpp b/src/MeoAssistant/BattleImageAnalyzer.cpp index 83d30ae495..2421e439e3 100644 --- a/src/MeoAssistant/BattleImageAnalyzer.cpp +++ b/src/MeoAssistant/BattleImageAnalyzer.cpp @@ -4,24 +4,48 @@ #include "MultiMatchImageAnalyzer.h" #include "MatchImageAnalyzer.h" +#include "OcrImageAnalyzer.h" #include "HashImageAnalyzer.h" #include "Logger.hpp" #include "TaskData.h" -bool asst::BattleImageAnalyzer::analyze() +bool asst::BattleImageAnalyzer::set_target(int target) { - // 生命值和家门,只要识别到了任一个,就可以说明当前是在战斗场景 - bool ret = hp_analyze(); - ret |= home_analyze(); - - if (ret) { - opers_analyze(); - skill_analyze(); - } - return ret; + m_target = target; + return true; } -const std::vector& asst::BattleImageAnalyzer::get_opers() const noexcept +bool asst::BattleImageAnalyzer::analyze() +{ + // HP 作为 flag,无论如何都识别。表明当前画面是在战斗场景的 + bool ret = hp_analyze(); + + if (m_target & Target::Home) { + ret |= home_analyze(); + } + + if (!ret) { + return false; + } + + // 可能没有干员(全上场了),所以干员识别结果不影响返回值 + if (m_target & Target::Oper) { + opers_analyze(); + } + + // 可能没有可使用的技能,所以技能识别结果不影响返回值 + if (m_target & Target::Skill) { + skill_analyze(); + } + + if (m_target & Target::Kills) { + ret &= kills_analyze(); + } + + return true; +} + +const std::vector& asst::BattleImageAnalyzer::get_opers() const noexcept { return m_opers; } @@ -41,12 +65,17 @@ int asst::BattleImageAnalyzer::get_hp() const noexcept return m_hp; } +int asst::BattleImageAnalyzer::get_kills() const noexcept +{ + return m_kills; +} + bool asst::BattleImageAnalyzer::opers_analyze() { LogTraceFunction; MultiMatchImageAnalyzer flags_analyzer(m_image); - flags_analyzer.set_task_info(Task.get("BattleOpersFlag")); + flags_analyzer.set_task_info("BattleOpersFlag"); if (!flags_analyzer.analyze()) { return false; } @@ -58,8 +87,9 @@ bool asst::BattleImageAnalyzer::opers_analyze() const auto avlb_move = Task.get("BattleOperAvailable")->rect_move; for (const MatchRect& flag_mrect : flags_analyzer.get_result()) { - Oper oper; + BattleRealTimeOper oper; oper.rect = flag_mrect.rect.move(click_move); + oper.avatar = m_image(utils::make_rect(oper.rect)); Rect available_rect = flag_mrect.rect.move(avlb_move); oper.available = oper_available_analyze(available_rect); @@ -85,26 +115,26 @@ bool asst::BattleImageAnalyzer::opers_analyze() return true; } -asst::BattleImageAnalyzer::Role asst::BattleImageAnalyzer::oper_role_analyze(const Rect& roi) +asst::BattleRole asst::BattleImageAnalyzer::oper_role_analyze(const Rect& roi) { - static const std::unordered_map RolesName = { - { Role::Caster, "Caster" }, - { Role::Medic, "Medic" }, - { Role::Pioneer, "Pioneer" }, - { Role::Sniper, "Sniper" }, - { Role::Special, "Special" }, - { Role::Support, "Support" }, - { Role::Tank, "Tank" }, - { Role::Warrior, "Warrior" }, - { Role::Drone, "Drone" } + static const std::unordered_map RolesName = { + { BattleRole::Caster, "Caster" }, + { BattleRole::Medic, "Medic" }, + { BattleRole::Pioneer, "Pioneer" }, + { BattleRole::Sniper, "Sniper" }, + { BattleRole::Special, "Special" }, + { BattleRole::Support, "Support" }, + { BattleRole::Tank, "Tank" }, + { BattleRole::Warrior, "Warrior" }, + { BattleRole::Drone, "Drone" } }; MatchImageAnalyzer role_analyzer(m_image); - Role result = Role::Unknown; + BattleRole result = BattleRole::Unknown; double max_score = 0; for (auto&& [role, role_name] : RolesName) { - role_analyzer.set_task_info(Task.get("BattleOperRole" + role_name)); + role_analyzer.set_task_info("BattleOperRole" + role_name); role_analyzer.set_roi(roi); if (!role_analyzer.analyze()) { continue; @@ -329,3 +359,49 @@ bool asst::BattleImageAnalyzer::hp_analyze() m_hp = hp; return true; } + +bool asst::BattleImageAnalyzer::kills_analyze() +{ + const auto task_ptr = Task.get("BattleKillsFlag"); + MatchImageAnalyzer flag_analzyer(m_image); + flag_analzyer.set_task_info(task_ptr); + if (!flag_analzyer.analyze()) { + return false; + } + + auto kills_roi = flag_analzyer.get_result().rect.move(task_ptr->rect_move); + OcrImageAnalyzer kills_analyzer(m_image); + kills_analyzer.set_roi(kills_roi); + if (!kills_analyzer.analyze()) { + return false; + } + kills_analyzer.sort_result_by_score(); + + // 这里的结果应该是 "击杀数/总的敌人数",例如 "0/41" + std::string kills_res = kills_analyzer.get_result().front().text; + int pos = kills_res.find('/'); + if (pos == std::string::npos) { + return false; + } + + // 例子中的"0" + std::string kills_count = kills_res.substr(0, pos); + if (kills_count.empty() || + !std::all_of(kills_count.cbegin(), kills_count.cend(), + [](char c) -> bool {return std::isdigit(c);})) { + return false; + } + int cur_kills = std::stoi(kills_count); + m_kills = std::max(m_kills, cur_kills); + return true; +} + +bool asst::BattleImageAnalyzer::cost_analyze() +{ + return false; +} + +bool asst::BattleImageAnalyzer::vacancies_analyze() +{ + return false; +} diff --git a/src/MeoAssistant/BattleImageAnalyzer.h b/src/MeoAssistant/BattleImageAnalyzer.h index c669792f2a..4de90424d2 100644 --- a/src/MeoAssistant/BattleImageAnalyzer.h +++ b/src/MeoAssistant/BattleImageAnalyzer.h @@ -1,57 +1,60 @@ #pragma once #include "AbstractImageAnalyzer.h" +#include "AsstBattleDef.h" + namespace asst { class BattleImageAnalyzer : public AbstractImageAnalyzer { public: - enum class Role + enum Target // 需要识别的目标 { - Unknown, - Caster, - Medic, - Pioneer, - Sniper, - Special, - Support, - Tank, - Warrior, - Drone - }; - struct Oper - { - int cost = 0; - Role role = Role::Unknown; - bool available = false; - Rect rect; + HP, // 剩余生命值 + Home, // 蓝色的家门 + Oper, // 下方的干员信息 + Skill, // cd 转好了可以使用的技能 + Kills, // 击杀数 + Cost, // 费用 + Vacancies, // 剩余可部署干员数 + // 肉鸽模式需要用到的识别 + Roguelike = Home | HP | Oper | Skill }; public: using AbstractImageAnalyzer::AbstractImageAnalyzer; virtual ~BattleImageAnalyzer() = default; + bool set_target(int target); virtual bool analyze() override; - virtual const std::vector& get_opers() const noexcept; + virtual const std::vector& get_opers() const noexcept; virtual const std::vector& get_homes() const noexcept; const std::vector& get_ready_skills() const noexcept; int get_hp() const noexcept; - protected: + int get_kills() const noexcept; + protected: bool opers_analyze(); // 识别干员 - Role oper_role_analyze(const Rect& roi); + BattleRole oper_role_analyze(const Rect& roi); int oper_cost_analyze(const Rect& roi); bool oper_available_analyze(const Rect& roi); bool home_analyze(); // 识别蓝色的家门 bool skill_analyze(); // 识别技能是否可用 bool hp_analyze(); // 识别剩余生命值 + bool kills_analyze(); // 识别击杀数 + bool cost_analyze(); // 识别费用 + bool vacancies_analyze();// 识别剩余可部署人数 - std::vector m_opers; // 下方干员信息 - std::vector m_homes; // 蓝色的家门位置 - std::vector m_ready_skills; // 可以释放的技能(Rect实际是干员的位置) - int m_hp = 0; // 剩余生命值 + int m_target = 0; // 待识别的目标 + + /* 识别结果缓存 */ + std::vector m_opers; // 下方干员信息 + std::vector m_homes; // 蓝色的家门位置 + std::vector m_ready_skills; // 可以释放的技能(Rect实际是干员的位置) + int m_hp = 0; // 剩余生命值 + int m_kills = 0; // 击杀数 protected: // 该分析器不支持外部设置ROI @@ -59,9 +62,5 @@ namespace asst { AbstractImageAnalyzer::set_roi(roi); } - virtual void set_image(const cv::Mat image, const Rect& roi) - { - AbstractImageAnalyzer::set_image(image, roi); - } }; } diff --git a/src/MeoAssistant/BattlePerspectiveImageAnalyzer.cpp b/src/MeoAssistant/BattlePerspectiveImageAnalyzer.cpp deleted file mode 100644 index 5dd8d7c190..0000000000 --- a/src/MeoAssistant/BattlePerspectiveImageAnalyzer.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "BattlePerspectiveImageAnalyzer.h" - -#include "Logger.hpp" - -bool asst::BattlePerspectiveImageAnalyzer::analyze() -{ - home_analyze(); - return placed_analyze(); -} - -void asst::BattlePerspectiveImageAnalyzer::set_src_homes(std::vector src_homes) -{ - m_src_homes = std::move(src_homes); -} - -asst::Point asst::BattlePerspectiveImageAnalyzer::get_nearest_point() const noexcept -{ - return m_nearest_point; -} - -const std::vector& asst::BattlePerspectiveImageAnalyzer::get_homes() const noexcept -{ - return m_homes.empty() ? m_src_homes : m_homes; -} - -bool asst::BattlePerspectiveImageAnalyzer::placed_analyze() -{ - // 颜色转换 - cv::Mat hsv; - cv::cvtColor(m_image, hsv, cv::COLOR_BGR2HSV); - cv::Mat bin; - cv::inRange(hsv, cv::Scalar(55, 90, 70), cv::Scalar(80, 150, 150), bin); - - // 形态学降噪 - cv::Mat morph_dst = bin; - cv::Mat morph_open_kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(9, 9)); - cv::morphologyEx(morph_dst, morph_dst, cv::MORPH_OPEN, morph_open_kernel); - //cv::Mat morph_close_kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); - //cv::morphologyEx(morph_dst, morph_dst, cv::MORPH_CLOSE, morph_close_kernel); - - // 计算可放干员格子的连通域,圈出每个单独的格子 - cv::Mat out, stats, centroids; - int number = cv::connectedComponentsWithStats(morph_dst, out, stats, centroids); - if (number < 2) { - return false; - } - std::vector placed_centers; - for (int i = 1; i != number; ++i) { // 第 0 个是整张图,所以从 1 开始 - int area = stats.at(i, cv::CC_STAT_AREA); - if (area < 300) { - continue; - } - int x = stats.at(i, cv::CC_STAT_LEFT); - int y = stats.at(i, cv::CC_STAT_TOP); - int w = stats.at(i, cv::CC_STAT_WIDTH); - int h = stats.at(i, cv::CC_STAT_HEIGHT); - m_available_placed.emplace_back(Rect(x, y, w, h)); - - int center_x = static_cast(centroids.at(i, 0)); - int center_y = static_cast(centroids.at(i, 1)); - placed_centers.emplace_back(Point(center_x, center_y)); - -#ifdef ASST_DEBUG - cv::circle(m_image_draw, cv::Point(center_x, center_y), 3, cv::Scalar(0, 0, 255), -1); - cv::rectangle(m_image_draw, cv::Rect(x, y, w, h), cv::Scalar(255, 0, 0), 3); -#endif - } - if (m_available_placed.empty()) { - return false; - } - - const auto& all_homes = get_homes(); - if (all_homes.empty()) { - return false; - } - Rect home = all_homes.front(); - - auto nearest_iter = std::min_element(placed_centers.cbegin(), placed_centers.cend(), - [&home](const Point& lhs, const Point& rhs) -> bool { - double lhs_dist = std::pow((home.x - lhs.x), 2) + std::pow((home.y - lhs.y), 2); - double rhs_dist = std::pow((home.x - rhs.x), 2) + std::pow((home.y - rhs.y), 2); - return lhs_dist < rhs_dist; - }); - if (nearest_iter == placed_centers.cend()) { - return false; - } - m_nearest_point = *nearest_iter; - - return true; -} diff --git a/src/MeoAssistant/BattlePerspectiveImageAnalyzer.h b/src/MeoAssistant/BattlePerspectiveImageAnalyzer.h deleted file mode 100644 index f582303717..0000000000 --- a/src/MeoAssistant/BattlePerspectiveImageAnalyzer.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once -#include "BattleImageAnalyzer.h" - -namespace asst -{ - // 战斗透视图片,一般是点击干员后的画面 - class BattlePerspectiveImageAnalyzer : public BattleImageAnalyzer - { - public: - using BattleImageAnalyzer::BattleImageAnalyzer; - virtual ~BattlePerspectiveImageAnalyzer() = default; - - virtual bool analyze() override; - virtual const std::vector& get_homes() const noexcept override; - - // 设置非透视状态下蓝色家门的位置 - void set_src_homes(std::vector src_homes); - Point get_nearest_point() const noexcept; - protected: - bool placed_analyze(); // 识别可放置干员的位置 - - std::vector m_src_homes; - std::vector m_available_placed; - Point m_nearest_point; - }; -} diff --git a/src/MeoAssistant/BattleProcessTask.cpp b/src/MeoAssistant/BattleProcessTask.cpp new file mode 100644 index 0000000000..1155d864a1 --- /dev/null +++ b/src/MeoAssistant/BattleProcessTask.cpp @@ -0,0 +1,190 @@ +#include "BattleProcessTask.h" + +#include "Controller.h" +#include "Resource.h" +#include "TaskData.h" +#include "Logger.hpp" + +#include "ProcessTask.h" + +#include "OcrImageAnalyzer.h" +#include "BattleImageAnalyzer.h" + +void asst::BattleProcessTask::set_stage_name(std::string name) +{ + m_stage_name = std::move(name); +} + +bool asst::BattleProcessTask::_run() +{ + bool ret = get_stage_info(); + + if (!ret) { + return false; + } + + while (!analyze_opers_preview()) { + ; + } + + for (const BattleAction& action : m_actions.actions) { + do_action(action); + } + + return true; +} + +bool asst::BattleProcessTask::get_stage_info() +{ + const auto& tile = Resrc.tile(); + + m_side_tile_info = tile.calc(m_stage_name, true); + m_normal_tile_info = tile.calc(m_stage_name, false); + + if (m_side_tile_info.empty() || m_normal_tile_info.empty()) { + return false; + } + + const auto& battle = Resrc.battle(); + bool contains = battle.contains_actions(m_stage_name); + if (!contains) { + return false; + } + + m_actions = battle.get_actions(m_stage_name); + + return true; +} + +bool asst::BattleProcessTask::analyze_opers_preview() +{ + BattleImageAnalyzer analyzer(m_ctrler->get_image()); + analyzer.set_target(BattleImageAnalyzer::Target::Oper); + if (!analyzer.analyze()) { + return false; + } + // TODO: 干员头像出来之后,还要过 2 秒左右才可以点击,这里可能还要加个延时 + + battle_pause(); + auto opers = analyzer.get_opers(); + + for (size_t i = 0; i != opers.size(); ++i) { + const auto& cur_oper = analyzer.get_opers(); + size_t offset = opers.size() > cur_oper.size() ? opers.size() - cur_oper.size() : 0; + m_ctrler->click(cur_oper.at(i - offset).rect); + + sleep(Task.get("BattleUseOper")->pre_delay); + + auto image = m_ctrler->get_image(); + + OcrImageAnalyzer name_analyzer(image); + name_analyzer.set_task_info("BattleOperName"); + name_analyzer.set_replace( + std::dynamic_pointer_cast( + Task.get("Roguelike1RecruitData")) + ->replace_map); + + std::string oper_name = "Unknown"; + if (name_analyzer.analyze()) { + name_analyzer.sort_result_by_score(); + oper_name = name_analyzer.get_result().front().text; + } + opers.at(i).name = oper_name; + + m_cur_opers_info.emplace(std::move(oper_name), std::move(opers.at(i))); + + // 干员特别多的时候,任意干员被点开,都会导致下方的干员图标被裁剪和移动。所以这里需要重新识别一下 + analyzer.set_image(image); + analyzer.analyze(); + } + battle_pause(); + cancel_selection(); + + return true; +} + +bool asst::BattleProcessTask::do_action(const BattleAction& action) +{ + if (!wait_condition(action)) { + return false; + } + const auto use_oper_task_ptr = Task.get("BattleUseOper"); + const auto swipe_oper_task_ptr = Task.get("BattleSwipeOper"); + + // TODO,临时调试方案。正式版本这里需要对 group_name -> oper_name 做一个转换 + auto iter = m_cur_opers_info.find(action.group_name); + if (iter == m_cur_opers_info.cend()) { + Log.error("battle opers group", action.group_name, "not found"); + return false; + } + + // 点击干员 + Rect oper_rect = iter->second.rect; + m_ctrler->click(oper_rect); + sleep(use_oper_task_ptr->pre_delay); + + // 拖动到场上 + Point placed_point = m_side_tile_info[action.location].pos; + Rect placed_rect{ placed_point.x ,placed_point.y, 1, 1 }; + m_ctrler->swipe(oper_rect, placed_rect); + + sleep(use_oper_task_ptr->rear_delay); + + if (action.direction != BattleDeployDirection::No) { + static const std::unordered_map DirectionMapping = { + { BattleDeployDirection::Right, Point(1, 0)}, + { BattleDeployDirection::Down, Point(0, 1)}, + { BattleDeployDirection::Left, Point(-1, 0)}, + { BattleDeployDirection::Up, Point(0, -1)}, + { BattleDeployDirection::No, Point(0, 0)}, + }; + + // 计算往哪边拖动(干员朝向) + Point direction = DirectionMapping.at(action.direction); + + // 将方向转换为实际的 swipe end 坐标点 + Point end_point = placed_point; + constexpr int coeff = 500; + end_point.x += direction.x * coeff; + end_point.y += direction.y * coeff; + + end_point.x = std::max(0, end_point.x); + end_point.x = std::min(end_point.x, WindowWidthDefault); + end_point.y = std::max(0, end_point.y); + end_point.y = std::min(end_point.y, WindowHeightDefault); + + m_ctrler->swipe(placed_point, end_point, swipe_oper_task_ptr->rear_delay); + } + + return true; +} + +bool asst::BattleProcessTask::wait_condition(const BattleAction& action) +{ + constexpr int analyze_target = BattleImageAnalyzer::Target::Kills | BattleImageAnalyzer::Target::Vacancies | BattleImageAnalyzer::Target::Cost; + + while (true) { + auto image = m_ctrler->get_image(); + BattleImageAnalyzer analyzer(image); + analyzer.set_target(analyze_target); + + if (!analyzer.analyze()) { + return true; + } + if (action.kills_condition <= analyzer.get_kills()) { + return true; + } + } + + return false; +} + +bool asst::BattleProcessTask::battle_pause() +{ + return ProcessTask(*this, { "BattlePause" }).run(); +} + +bool asst::BattleProcessTask::cancel_selection() +{ + return ProcessTask(*this, { "BattleCancelSelection" }).run(); +} diff --git a/src/MeoAssistant/BattleProcessTask.h b/src/MeoAssistant/BattleProcessTask.h new file mode 100644 index 0000000000..356fd033e3 --- /dev/null +++ b/src/MeoAssistant/BattleProcessTask.h @@ -0,0 +1,38 @@ +#pragma once +#include "AbstractTask.h" + +#include "AsstTypes.h" +#include "TilePack.h" +#include "AsstBattleDef.h" +#include "BattleImageAnalyzer.h" + +namespace asst +{ + class BattleProcessTask : public AbstractTask + { + public: + using AbstractTask::AbstractTask; + virtual ~BattleProcessTask() = default; + + void set_stage_name(std::string name); + + protected: + virtual bool _run() override; + + bool get_stage_info(); + bool battle_pause(); + bool cancel_selection(); // 取消选择干员 + bool analyze_opers_preview(); + + bool do_action(const BattleAction& action); + bool wait_condition(const BattleAction& action); + + std::string m_stage_name; + + std::unordered_map m_side_tile_info; + std::unordered_map m_normal_tile_info; + BattleActionsGroup m_actions; + + std::unordered_map m_cur_opers_info; + }; +} diff --git a/src/MeoAssistant/Controller.cpp b/src/MeoAssistant/Controller.cpp index 82a58a3781..dfa52f2b64 100644 --- a/src/MeoAssistant/Controller.cpp +++ b/src/MeoAssistant/Controller.cpp @@ -101,7 +101,7 @@ asst::Controller::~Controller() close(m_pipe_out[PIPE_READ]); close(m_pipe_out[PIPE_WRITE]); #endif -} + } //asst::Rect asst::Controller::shaped_correct(const Rect & rect) const //{ @@ -638,10 +638,10 @@ bool asst::Controller::connect(const std::string & adb_path, const std::string & auto adb_ret = Resrc.cfg().get_adb_cfg(config); if (!adb_ret) { - json::value info = get_info_json() | + json::value info = get_info_json() | json::object{ { "what", "ConnectFailed" }, - { "why", "ConfigNotFound" }}; + { "why", "ConfigNotFound" } }; m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg); return false; } @@ -667,7 +667,7 @@ bool asst::Controller::connect(const std::string & adb_path, const std::string & auto connect_ret = call_command(cmd_replace(adb_cfg.connect)); // 端口即使错误,命令仍然会返回0,TODO 对connect_result进行判断 if (!connect_ret) { - json::value info = get_info_json() | + json::value info = get_info_json() | json::object{ { "what", "ConnectFailed" }, { "why", "Connection command failed to exec" } @@ -681,11 +681,11 @@ bool asst::Controller::connect(const std::string & adb_path, const std::string & { auto uuid_ret = call_command(cmd_replace(adb_cfg.uuid)); if (!uuid_ret) { - json::value info = get_info_json() | + json::value info = get_info_json() | json::object{ { "what", "ConnectFailed" }, { "why", "Uuid command failed to exec" } - }; + }; m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg); return false; } @@ -701,7 +701,7 @@ bool asst::Controller::connect(const std::string & adb_path, const std::string & json::object{ { "what", "UuidGetted" }, { "why", "" } - }; + }; info["details"]["uuid"] = m_uuid; m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg); } @@ -736,7 +736,7 @@ bool asst::Controller::connect(const std::string & adb_path, const std::string & json::object{ { "what", "ConnectFailed" }, { "why", "Display command failed to exec" } - }; + }; m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg); return false; } @@ -763,10 +763,10 @@ bool asst::Controller::connect(const std::string & adb_path, const std::string & { "why", "" } }; - info["details"] |= json::object { + info["details"] |= json::object{ { "width", m_width }, { "height", m_height } - }; + }; m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg); } @@ -795,7 +795,7 @@ bool asst::Controller::connect(const std::string & adb_path, const std::string & json::object{ { "what", "Connected" }, { "why", "" } - }; + }; m_callback(AsstMsg::ConnectionInfo, info, m_callback_arg); } diff --git a/src/MeoAssistant/CreditShopImageAnalyzer.cpp b/src/MeoAssistant/CreditShopImageAnalyzer.cpp index 4286a0f5da..4d161d5fbc 100644 --- a/src/MeoAssistant/CreditShopImageAnalyzer.cpp +++ b/src/MeoAssistant/CreditShopImageAnalyzer.cpp @@ -93,7 +93,7 @@ bool asst::CreditShopImageAnalyzer::sold_out_analyze() { // 识别是否售罄 MatchImageAnalyzer sold_out_analyzer(m_image); - sold_out_analyzer.set_task_info(Task.get("CreditShop-SoldOut")); + sold_out_analyzer.set_task_info("CreditShop-SoldOut"); for (const Rect& commodity : m_need_to_buy) { sold_out_analyzer.set_roi(commodity); diff --git a/src/MeoAssistant/CreditShoppingTask.cpp b/src/MeoAssistant/CreditShoppingTask.cpp index 804e0e0292..13f53e0e05 100644 --- a/src/MeoAssistant/CreditShoppingTask.cpp +++ b/src/MeoAssistant/CreditShoppingTask.cpp @@ -80,7 +80,7 @@ bool asst::CreditShoppingTask::_run() OcrImageAnalyzer prompt_analyzer(prompt_image); - prompt_analyzer.set_task_info(Task.get("CreditShop-NoMoney")); + prompt_analyzer.set_task_info("CreditShop-NoMoney"); if (prompt_analyzer.analyze()) { click_return_button(); return true; diff --git a/src/MeoAssistant/DebugTask.cpp b/src/MeoAssistant/DebugTask.cpp index 9af1a5ba3f..1b4d31536f 100644 --- a/src/MeoAssistant/DebugTask.cpp +++ b/src/MeoAssistant/DebugTask.cpp @@ -1,10 +1,14 @@ #include "DebugTask.h" -#include "RoguelikeSkillSelectionTaskPlugin.h" +//#include "RoguelikeSkillSelectionTaskPlugin.h" + +#include "BattleProcessTask.h" asst::DebugTask::DebugTask(AsstCallback callback, void* callback_arg) : PackageTask(callback, callback_arg, TaskType) { - auto task_ptr = std::make_shared(callback, callback_arg, TaskType); + //auto task_ptr = std::make_shared(callback, callback_arg, TaskType); + auto task_ptr = std::make_shared(callback, callback_arg, TaskType); + task_ptr->set_stage_name("切尔诺伯格"); m_subtasks.emplace_back(task_ptr); } diff --git a/src/MeoAssistant/InfrastClueImageAnalyzer.cpp b/src/MeoAssistant/InfrastClueImageAnalyzer.cpp index cc1a938976..cbf0025ea3 100644 --- a/src/MeoAssistant/InfrastClueImageAnalyzer.cpp +++ b/src/MeoAssistant/InfrastClueImageAnalyzer.cpp @@ -16,7 +16,7 @@ bool asst::InfrastClueImageAnalyzer::analyze() bool asst::InfrastClueImageAnalyzer::clue_detect() { MultiMatchImageAnalyzer clue_analyzer(m_image); - clue_analyzer.set_task_info(Task.get("InfrastClue")); + clue_analyzer.set_task_info("InfrastClue"); clue_analyzer.set_roi(m_roi); // 该任务以外部设置的roi为准 if (!clue_analyzer.analyze()) { diff --git a/src/MeoAssistant/InfrastClueVacancyImageAnalyzer.cpp b/src/MeoAssistant/InfrastClueVacancyImageAnalyzer.cpp index 717948099a..f3a96e182d 100644 --- a/src/MeoAssistant/InfrastClueVacancyImageAnalyzer.cpp +++ b/src/MeoAssistant/InfrastClueVacancyImageAnalyzer.cpp @@ -12,7 +12,7 @@ bool asst::InfrastClueVacancyImageAnalyzer::analyze() MatchImageAnalyzer analyzer(m_image); for (const std::string& suffix : m_to_be_analyzed) { - analyzer.set_task_info(Task.get(clue_vacancy + suffix)); + analyzer.set_task_info(clue_vacancy + suffix); if (!analyzer.analyze()) { Log.trace("no", clue_vacancy, suffix); continue; diff --git a/src/MeoAssistant/InfrastFacilityImageAnalyzer.cpp b/src/MeoAssistant/InfrastFacilityImageAnalyzer.cpp index c255bc0d4a..e477d7fea0 100644 --- a/src/MeoAssistant/InfrastFacilityImageAnalyzer.cpp +++ b/src/MeoAssistant/InfrastFacilityImageAnalyzer.cpp @@ -23,9 +23,8 @@ bool asst::InfrastFacilityImageAnalyzer::analyze() MultiMatchImageAnalyzer mm_analyzer(m_image); - auto task_analyze = [&](const std::string& task_name) -> bool { - mm_analyzer.set_task_info(Task.get(task_name)); + mm_analyzer.set_task_info(task_name); return mm_analyzer.analyze(); }; diff --git a/src/MeoAssistant/InfrastOfficeTask.cpp b/src/MeoAssistant/InfrastOfficeTask.cpp index 5b6fef9bf0..3b4652f6c0 100644 --- a/src/MeoAssistant/InfrastOfficeTask.cpp +++ b/src/MeoAssistant/InfrastOfficeTask.cpp @@ -24,7 +24,7 @@ bool asst::InfrastOfficeTask::_run() auto find_iter = std::find_if( m_all_available_opers.begin(), m_all_available_opers.end(), - [&](const infrast::Oper& info) -> bool { + [&](const infrast::BattleRealTimeOper& info) -> bool { return info.selected; }); diff --git a/src/MeoAssistant/InfrastOperImageAnalyzer.cpp b/src/MeoAssistant/InfrastOperImageAnalyzer.cpp index 6b43449fb5..00e3d2e1f4 100644 --- a/src/MeoAssistant/InfrastOperImageAnalyzer.cpp +++ b/src/MeoAssistant/InfrastOperImageAnalyzer.cpp @@ -46,7 +46,7 @@ void asst::InfrastOperImageAnalyzer::sort_by_loc() std::sort( m_result.begin(), m_result.end(), - [](const infrast::Oper& lhs, const infrast::Oper& rhs) -> bool { + [](const infrast::BattleRealTimeOper& lhs, const infrast::BattleRealTimeOper& rhs) -> bool { if (std::abs(lhs.rect.x - rhs.rect.x) < 5) { // x差距较小则理解为是同一排的,按y排序 return lhs.rect.y < rhs.rect.y; } @@ -62,7 +62,7 @@ void asst::InfrastOperImageAnalyzer::sort_by_mood() std::sort( m_result.begin(), m_result.end(), - [](const infrast::Oper& lhs, const infrast::Oper& rhs) -> bool { + [](const infrast::BattleRealTimeOper& lhs, const infrast::BattleRealTimeOper& rhs) -> bool { // 先按心情排序,心情低的放前面 if (std::fabs(lhs.mood_ratio - rhs.mood_ratio) > DoubleDiff) { return lhs.mood_ratio < rhs.mood_ratio; @@ -92,7 +92,6 @@ void asst::InfrastOperImageAnalyzer::oper_detect() InfrastSmileyImageAnalyzer smiley_analyzer(m_image); - for (auto&& roi : all_roi) { smiley_analyzer.set_roi(roi); if (!smiley_analyzer.analyze()) { @@ -120,7 +119,7 @@ void asst::InfrastOperImageAnalyzer::oper_detect() cv::rectangle(m_image_draw, utils::make_rect(smiley_rect), cv::Scalar(0, 0, 255), 2); #endif // ASST_DEBUG - infrast::Oper oper; + infrast::BattleRealTimeOper oper; oper.smiley = smiley; m_result.emplace_back(std::move(oper)); } diff --git a/src/MeoAssistant/InfrastOperImageAnalyzer.h b/src/MeoAssistant/InfrastOperImageAnalyzer.h index a1c5bb1677..dbc8982a15 100644 --- a/src/MeoAssistant/InfrastOperImageAnalyzer.h +++ b/src/MeoAssistant/InfrastOperImageAnalyzer.h @@ -30,7 +30,7 @@ namespace asst void sort_by_loc(); void sort_by_mood(); - auto get_result() const noexcept -> const std::vector& + auto get_result() const noexcept -> const std::vector& { return m_result; } @@ -69,7 +69,7 @@ namespace asst void doing_analyze(); std::string m_facility; - std::vector m_result; + std::vector m_result; int m_to_be_calced = All; int m_num_of_opers_with_skills = 0; }; diff --git a/src/MeoAssistant/InfrastPowerTask.cpp b/src/MeoAssistant/InfrastPowerTask.cpp index fbcc9ba619..6e0a6fada1 100644 --- a/src/MeoAssistant/InfrastPowerTask.cpp +++ b/src/MeoAssistant/InfrastPowerTask.cpp @@ -36,7 +36,7 @@ bool asst::InfrastPowerTask::_run() auto find_iter = std::find_if( m_all_available_opers.begin(), m_all_available_opers.end(), - [&](const infrast::Oper& info) -> bool { + [&](const infrast::BattleRealTimeOper& info) -> bool { return info.selected; }); bool need_shift = true; diff --git a/src/MeoAssistant/InfrastProductionTask.cpp b/src/MeoAssistant/InfrastProductionTask.cpp index 09d58f8828..0e9efcbc06 100644 --- a/src/MeoAssistant/InfrastProductionTask.cpp +++ b/src/MeoAssistant/InfrastProductionTask.cpp @@ -48,7 +48,7 @@ bool asst::InfrastProductionTask::shift_facility_list() add_analyzer.set_task_info(add_task_ptr); MultiMatchImageAnalyzer locked_analyzer; - locked_analyzer.set_task_info(Task.get("InfrastOperLocked" + facility_name())); + locked_analyzer.set_task_info("InfrastOperLocked" + facility_name()); for (; m_cur_facility_index < m_facility_list_tabs.size(); ++m_cur_facility_index) { Rect tab = m_facility_list_tabs.at(m_cur_facility_index); @@ -86,7 +86,7 @@ bool asst::InfrastProductionTask::shift_facility_list() std::string cur_product = all_products.at(0); double max_score = 0; for (const std::string& product : all_products) { - product_analyzer.set_task_info(Task.get("InfrastFlag" + product)); + product_analyzer.set_task_info("InfrastFlag" + product); if (product_analyzer.analyze()) { double score = product_analyzer.get_result().score; if (score > max_score) { @@ -207,7 +207,7 @@ size_t asst::InfrastProductionTask::opers_detect() } auto find_iter = std::find_if( m_all_available_opers.cbegin(), m_all_available_opers.cend(), - [&](const infrast::Oper& oper) -> bool { + [&](const infrast::BattleRealTimeOper& oper) -> bool { // 有可能是同一个干员,比一下hash int dist = HashImageAnalyzer::hamming(cur_oper.face_hash, oper.face_hash); Log.debug("opers_detect hash dist |", dist); @@ -492,7 +492,7 @@ bool asst::InfrastProductionTask::opers_choose() Log.trace("before mood filter, opers size:", cur_all_opers.size()); // 小于心情阈值的干员则不可用 auto remove_iter = std::remove_if(cur_all_opers.begin(), cur_all_opers.end(), - [&](const infrast::Oper& rhs) -> bool { + [&](const infrast::BattleRealTimeOper& rhs) -> bool { return rhs.mood_ratio < m_mood_threshold; }); cur_all_opers.erase(remove_iter, cur_all_opers.end()); @@ -502,7 +502,7 @@ bool asst::InfrastProductionTask::opers_choose() Log.trace("to find", opt_iter->skills.begin()->names.front()); auto find_iter = std::find_if( cur_all_opers.cbegin(), cur_all_opers.cend(), - [&](const infrast::Oper& lhs) -> bool { + [&](const infrast::BattleRealTimeOper& lhs) -> bool { if (lhs.skills != opt_iter->skills) { return false; } @@ -544,7 +544,7 @@ bool asst::InfrastProductionTask::opers_choose() { auto avlb_iter = std::find_if( m_all_available_opers.cbegin(), m_all_available_opers.cend(), - [&](const infrast::Oper& lhs) -> bool { + [&](const infrast::BattleRealTimeOper& lhs) -> bool { int dist = HashImageAnalyzer::hamming(lhs.face_hash, find_iter->face_hash); Log.debug("opers_choose | face hash dist", dist); if (dist < face_hash_thres) { @@ -626,7 +626,7 @@ bool asst::InfrastProductionTask::facility_list_detect() const auto image = m_ctrler->get_image(); MultiMatchImageAnalyzer mm_analyzer(image); - mm_analyzer.set_task_info(Task.get("InfrastFacilityListTab" + facility_name())); + mm_analyzer.set_task_info("InfrastFacilityListTab" + facility_name()); if (!mm_analyzer.analyze()) { return false; diff --git a/src/MeoAssistant/InfrastProductionTask.h b/src/MeoAssistant/InfrastProductionTask.h index c9ade75a35..a465824d4f 100644 --- a/src/MeoAssistant/InfrastProductionTask.h +++ b/src/MeoAssistant/InfrastProductionTask.h @@ -32,7 +32,7 @@ namespace asst std::string m_product; std::string m_uses_of_drones; int m_cur_num_of_lokced_opers = 0; - std::vector m_all_available_opers; + std::vector m_all_available_opers; std::vector m_optimal_combs; std::vector m_facility_list_tabs; size_t max_num_of_opers_per_page = 0; diff --git a/src/MeoAssistant/InfrastReceptionTask.cpp b/src/MeoAssistant/InfrastReceptionTask.cpp index 78b4ffbbc1..c3837d07a5 100644 --- a/src/MeoAssistant/InfrastReceptionTask.cpp +++ b/src/MeoAssistant/InfrastReceptionTask.cpp @@ -146,7 +146,6 @@ bool asst::InfrastReceptionTask::shift() const auto image = m_ctrler->get_image(); MatchImageAnalyzer add_analyzer(image); - const auto raw_task_ptr = Task.get("InfrastAddOperator" + facility_name() + m_work_mode_name); switch (raw_task_ptr->algorithm) { case AlgorithmType::JustReturn: diff --git a/src/MeoAssistant/InfrastSmileyImageAnalyzer.cpp b/src/MeoAssistant/InfrastSmileyImageAnalyzer.cpp index 655017fada..4a15e873ef 100644 --- a/src/MeoAssistant/InfrastSmileyImageAnalyzer.cpp +++ b/src/MeoAssistant/InfrastSmileyImageAnalyzer.cpp @@ -16,10 +16,9 @@ bool asst::InfrastSmileyImageAnalyzer::analyze() MultiMatchImageAnalyzer mm_analyzer(m_image); - decltype(m_result) temp_result; for (const auto& [type, task_name] : smiley_map) { - mm_analyzer.set_task_info(Task.get(task_name)); + mm_analyzer.set_task_info(task_name); mm_analyzer.set_roi(m_roi); if (!mm_analyzer.analyze()) { continue; diff --git a/src/MeoAssistant/MatchImageAnalyzer.cpp b/src/MeoAssistant/MatchImageAnalyzer.cpp index 58655a071d..00917c1ebf 100644 --- a/src/MeoAssistant/MatchImageAnalyzer.cpp +++ b/src/MeoAssistant/MatchImageAnalyzer.cpp @@ -52,6 +52,11 @@ void asst::MatchImageAnalyzer::set_task_info(std::shared_ptr task_ptr) set_task_info(*std::dynamic_pointer_cast(task_ptr)); } +void asst::MatchImageAnalyzer::set_task_info(const std::string& task_name) +{ + set_task_info(Task.get(task_name)); +} + void asst::MatchImageAnalyzer::set_region_of_appeared(Rect region) noexcept { m_region_of_appeared = std::move(region); diff --git a/src/MeoAssistant/MatchImageAnalyzer.h b/src/MeoAssistant/MatchImageAnalyzer.h index 037814cc56..f057d1bb56 100644 --- a/src/MeoAssistant/MatchImageAnalyzer.h +++ b/src/MeoAssistant/MatchImageAnalyzer.h @@ -18,6 +18,7 @@ namespace asst void set_templ_name(std::string templ_name) noexcept; void set_threshold(double templ_thres) noexcept; void set_task_info(std::shared_ptr task_ptr); + void set_task_info(const std::string& task_name); void set_region_of_appeared(Rect region) noexcept; const MatchRect& get_result() const noexcept; diff --git a/src/MeoAssistant/MeoAssistant.vcxproj b/src/MeoAssistant/MeoAssistant.vcxproj index 0c966fc723..a697beb526 100644 --- a/src/MeoAssistant/MeoAssistant.vcxproj +++ b/src/MeoAssistant/MeoAssistant.vcxproj @@ -27,7 +27,7 @@ - + @@ -97,7 +97,7 @@ - + diff --git a/src/MeoAssistant/MeoAssistant.vcxproj.filters b/src/MeoAssistant/MeoAssistant.vcxproj.filters index 9cb23ba359..d8ffd000c2 100644 --- a/src/MeoAssistant/MeoAssistant.vcxproj.filters +++ b/src/MeoAssistant/MeoAssistant.vcxproj.filters @@ -219,9 +219,6 @@ 头文件\ImageAnalyzer\General - - 头文件\ImageAnalyzer\General - 头文件\Task\Plugin @@ -309,6 +306,9 @@ 头文件\Resource + + 头文件\Task\Sub + @@ -455,9 +455,6 @@ 源文件\ImageAnalyzer\Final - - 源文件\ImageAnalyzer\Final - 源文件\ImageAnalyzer\Final @@ -515,6 +512,9 @@ 源文件\Resource + + 源文件\Task\Sub + diff --git a/src/MeoAssistant/MultiMatchImageAnalyzer.cpp b/src/MeoAssistant/MultiMatchImageAnalyzer.cpp index 859e6a92a3..eb8ec2933b 100644 --- a/src/MeoAssistant/MultiMatchImageAnalyzer.cpp +++ b/src/MeoAssistant/MultiMatchImageAnalyzer.cpp @@ -73,6 +73,11 @@ void asst::MultiMatchImageAnalyzer::set_task_info(std::shared_ptr task set_task_info(*std::dynamic_pointer_cast(task_ptr)); } +void asst::MultiMatchImageAnalyzer::set_task_info(const std::string& task_name) +{ + set_task_info(Task.get(task_name)); +} + const std::vector& asst::MultiMatchImageAnalyzer::get_result() const noexcept { return m_result; diff --git a/src/MeoAssistant/MultiMatchImageAnalyzer.h b/src/MeoAssistant/MultiMatchImageAnalyzer.h index 874bb11426..2919a0afe9 100644 --- a/src/MeoAssistant/MultiMatchImageAnalyzer.h +++ b/src/MeoAssistant/MultiMatchImageAnalyzer.h @@ -20,6 +20,7 @@ namespace asst void set_threshold(double templ_thres) noexcept; void set_task_info(std::shared_ptr task_ptr); + void set_task_info(const std::string& task_name); const std::vector& get_result() const noexcept; diff --git a/src/MeoAssistant/OcrImageAnalyzer.cpp b/src/MeoAssistant/OcrImageAnalyzer.cpp index 4b6435f822..619870e168 100644 --- a/src/MeoAssistant/OcrImageAnalyzer.cpp +++ b/src/MeoAssistant/OcrImageAnalyzer.cpp @@ -111,6 +111,11 @@ void asst::OcrImageAnalyzer::set_task_info(std::shared_ptr task_ptr) set_task_info(*std::dynamic_pointer_cast(task_ptr)); } +void asst::OcrImageAnalyzer::set_task_info(const std::string& task_name) +{ + set_task_info(Task.get(task_name)); +} + void asst::OcrImageAnalyzer::set_region_of_appeared(Rect region) noexcept { m_region_of_appeared = std::move(region); diff --git a/src/MeoAssistant/OcrImageAnalyzer.h b/src/MeoAssistant/OcrImageAnalyzer.h index 981b30668d..0885686fd1 100644 --- a/src/MeoAssistant/OcrImageAnalyzer.h +++ b/src/MeoAssistant/OcrImageAnalyzer.h @@ -25,6 +25,7 @@ namespace asst void set_required(std::vector required, bool full_match = false) noexcept; void set_replace(std::unordered_map replace) noexcept; void set_task_info(std::shared_ptr task_ptr); + void set_task_info(const std::string& task_name); void set_region_of_appeared(Rect region) noexcept; void set_pred(const TextRectProc& pred); diff --git a/src/MeoAssistant/ProcessTask.cpp b/src/MeoAssistant/ProcessTask.cpp index 13f4922316..ee9d7dbe9f 100644 --- a/src/MeoAssistant/ProcessTask.cpp +++ b/src/MeoAssistant/ProcessTask.cpp @@ -202,6 +202,10 @@ bool ProcessTask::_run() callback(AsstMsg::SubTaskCompleted, info); + if (cur_task_ptr->next.empty()) { + need_stop = true; + } + if (need_stop) { return true; } diff --git a/src/MeoAssistant/RecruitImageAnalyzer.cpp b/src/MeoAssistant/RecruitImageAnalyzer.cpp index 48db41d4c6..f7ae84e5f5 100644 --- a/src/MeoAssistant/RecruitImageAnalyzer.cpp +++ b/src/MeoAssistant/RecruitImageAnalyzer.cpp @@ -58,7 +58,6 @@ bool asst::RecruitImageAnalyzer::time_analyze() MatchImageAnalyzer time_analyzer(m_image); time_analyzer.set_task_info(time_task_ptr); - if (time_analyzer.analyze()) { Rect rect = time_analyzer.get_result().rect; const auto& res_move = time_task_ptr->rect_move; @@ -77,8 +76,7 @@ bool asst::RecruitImageAnalyzer::time_analyze() bool asst::RecruitImageAnalyzer::confirm_analyze() { MatchImageAnalyzer confirm_analyzer(m_image); - confirm_analyzer.set_task_info(Task.get("RecruitConfirm")); - + confirm_analyzer.set_task_info("RecruitConfirm"); if (confirm_analyzer.analyze()) { m_confirm_rect = confirm_analyzer.get_result().rect; @@ -92,7 +90,7 @@ bool asst::RecruitImageAnalyzer::refresh_analyze() { MatchImageAnalyzer refresh_analyzer(m_image); - refresh_analyzer.set_task_info(Task.get("RecruitRefresh")); + refresh_analyzer.set_task_info("RecruitRefresh"); if (refresh_analyzer.analyze()) { m_refresh_rect = refresh_analyzer.get_result().rect; diff --git a/src/MeoAssistant/Resource.cpp b/src/MeoAssistant/Resource.cpp index 0efbad017e..0ded74d019 100644 --- a/src/MeoAssistant/Resource.cpp +++ b/src/MeoAssistant/Resource.cpp @@ -19,6 +19,7 @@ bool asst::Resource::load(const std::string& dir) constexpr static const char* RecruitCfgFilename = "recruit.json"; constexpr static const char* ItemCfgFilename = "item_index.json"; constexpr static const char* InfrastCfgFilename = "infrast.json"; + constexpr static const char* BattleCfgDirname = "battle"; constexpr static const char* OcrResourceFilename = "PaddleOCR"; constexpr static const char* PenguinResourceFilename = "penguin-stats-recognize"; constexpr static const char* TilesCalcResourceFilename = "Arknights-Tile-Pos"; @@ -66,6 +67,16 @@ bool asst::Resource::load(const std::string& dir) overload = true; } + for (const auto& entry : std::filesystem::directory_iterator(dir + BattleCfgDirname)) { + if (entry.path().extension() != ".json") { + continue; + } + if (!m_battle_cfg_unique_ins.load(entry.path().u8string())) { + m_last_error = entry.path().u8string() + " Load field"; + return false; + } + } + if (!m_infrast_cfg_unique_ins.load(dir + InfrastCfgFilename)) { if (!m_loaded) { m_last_error = std::string(InfrastCfgFilename) + ": " + m_infrast_cfg_unique_ins.get_last_error(); diff --git a/src/MeoAssistant/Resource.h b/src/MeoAssistant/Resource.h index 983627082a..02a59788ff 100644 --- a/src/MeoAssistant/Resource.h +++ b/src/MeoAssistant/Resource.h @@ -14,6 +14,7 @@ #include "TaskData.h" #include "TemplResource.h" #include "TilePack.h" +#include "BattleConfiger.h" namespace asst { @@ -50,6 +51,10 @@ namespace asst { return m_infrast_cfg_unique_ins; } + BattleConfiger& battle() noexcept + { + return m_battle_cfg_unique_ins; + } OcrPack& ocr() noexcept { return m_ocr_pack_unique_ins; @@ -83,6 +88,10 @@ namespace asst { return m_infrast_cfg_unique_ins; } + const BattleConfiger& battle() const noexcept + { + return m_battle_cfg_unique_ins; + } const OcrPack& ocr() const noexcept { return m_ocr_pack_unique_ins; @@ -105,6 +114,7 @@ namespace asst TemplResource m_templ_resource_unique_ins; GeneralConfiger m_general_cfg_unique_ins; RecruitConfiger m_recruit_cfg_unique_ins; + BattleConfiger m_battle_cfg_unique_ins; ItemConfiger m_item_cfg_unique_ins; InfrastConfiger m_infrast_cfg_unique_ins; OcrPack m_ocr_pack_unique_ins; diff --git a/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp b/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp index 1ce22ce314..82193df58f 100644 --- a/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp @@ -1,7 +1,6 @@ #include "RoguelikeBattleTaskPlugin.h" #include "BattleImageAnalyzer.h" -#include "BattlePerspectiveImageAnalyzer.h" #include "Controller.h" #include "TaskData.h" #include "ProcessTask.h" @@ -11,336 +10,338 @@ bool asst::RoguelikeBattleTaskPlugin::verify(AsstMsg msg, const json::value& details) const { - if (msg != AsstMsg::SubTaskCompleted - || details.get("subtask", std::string()) != "ProcessTask") { - return false; - } + if (msg != AsstMsg::SubTaskCompleted + || details.get("subtask", std::string()) != "ProcessTask") { + return false; + } - if (details.at("details").at("task").as_string() == "Roguelike1StartAction") { - return true; - } - else { - return false; - } + if (details.at("details").at("task").as_string() == "Roguelike1StartAction") { + return true; + } + else { + return false; + } } void asst::RoguelikeBattleTaskPlugin::set_skill_usage(SkillUsageMap usage_map) { - m_skill_usage = std::move(usage_map); + m_skill_usage = std::move(usage_map); } void asst::RoguelikeBattleTaskPlugin::set_stage_name(std::string stage) { - m_stage_name = std::move(stage); + m_stage_name = std::move(stage); } bool asst::RoguelikeBattleTaskPlugin::_run() { - bool getted_info = get_stage_info(); + bool getted_info = get_stage_info(); - speed_up(); + speed_up(); - if (!getted_info) { - return true; - } + if (!getted_info) { + return true; + } - while (!need_exit()) { - // 不在战斗场景,且已使用过了干员,说明已经打完了,就结束循环 - if (!auto_battle() && m_opers_used) { - break; - } - } + while (!need_exit()) { + // 不在战斗场景,且已使用过了干员,说明已经打完了,就结束循环 + if (!auto_battle() && m_opers_used) { + break; + } + } - clear(); + clear(); - return true; + return true; } bool asst::RoguelikeBattleTaskPlugin::get_stage_info() { - LogTraceFunction; + LogTraceFunction; - const auto& tile = Resrc.tile(); - bool calced = false; + const auto& tile = Resrc.tile(); + bool calced = false; - if (m_stage_name.empty()) { - const auto stage_name_task_ptr = Task.get("BattleStageName"); - sleep(stage_name_task_ptr->pre_delay); + if (m_stage_name.empty()) { + const auto stage_name_task_ptr = Task.get("BattleStageName"); + sleep(stage_name_task_ptr->pre_delay); - constexpr int StageNameRetryTimes = 50; - for (int i = 0; i != StageNameRetryTimes; ++i) { - cv::Mat image = m_ctrler->get_image(); - OcrImageAnalyzer name_analyzer(image); + constexpr int StageNameRetryTimes = 50; + for (int i = 0; i != StageNameRetryTimes; ++i) { + cv::Mat image = m_ctrler->get_image(); + OcrImageAnalyzer name_analyzer(image); - name_analyzer.set_task_info(stage_name_task_ptr); - if (!name_analyzer.analyze()) { - continue; - } + name_analyzer.set_task_info(stage_name_task_ptr); + if (!name_analyzer.analyze()) { + continue; + } - for (const auto& tr : name_analyzer.get_result()) { - auto side_info = tile.calc(tr.text, true); - if (side_info.empty()) { - continue; - } - m_side_tile_info = std::move(side_info); - m_normal_tile_info = tile.calc(tr.text, false); - m_stage_name = tr.text; - calced = true; - break; - } - if (calced) { - break; - } - } - } - else { - m_side_tile_info = tile.calc(m_stage_name, true); - calced = true; - } + for (const auto& tr : name_analyzer.get_result()) { + auto side_info = tile.calc(tr.text, true); + if (side_info.empty()) { + continue; + } + m_side_tile_info = std::move(side_info); + m_normal_tile_info = tile.calc(tr.text, false); + m_stage_name = tr.text; + calced = true; + break; + } + if (calced) { + break; + } + } + } + else { + m_side_tile_info = tile.calc(m_stage_name, true); + m_normal_tile_info = tile.calc(m_stage_name, false); + calced = true; + } - if (calced) { + if (calced) { #ifdef ASST_DEBUG - auto normal_tiles = tile.calc(m_stage_name, false); - cv::Mat draw = m_ctrler->get_image(); - for (const auto& [point, info] : normal_tiles) { - using TileKey = TilePack::TileKey; - static const std::unordered_map TileKeyMapping = { - { TileKey::Invalid, "invalid" }, - { TileKey::Forbidden, "forbidden" }, - { TileKey::Wall, "wall" }, - { TileKey::Road, "road" }, - { TileKey::Home, "end" }, - { TileKey::EnemyHome, "start" }, - { TileKey::Floor, "floor" }, - { TileKey::Hole, "hole" }, - { TileKey::Telin, "telin" }, - { TileKey::Telout, "telout" } - }; + auto normal_tiles = tile.calc(m_stage_name, false); + cv::Mat draw = m_ctrler->get_image(); + for (const auto& [point, info] : normal_tiles) { + using TileKey = TilePack::TileKey; + static const std::unordered_map TileKeyMapping = { + { TileKey::Invalid, "invalid" }, + { TileKey::Forbidden, "forbidden" }, + { TileKey::Wall, "wall" }, + { TileKey::Road, "road" }, + { TileKey::Home, "end" }, + { TileKey::EnemyHome, "start" }, + { TileKey::Floor, "floor" }, + { TileKey::Hole, "hole" }, + { TileKey::Telin, "telin" }, + { TileKey::Telout, "telout" } + }; - cv::putText(draw, TileKeyMapping.at(info.key), cv::Point(info.pos.x, info.pos.y), 1, 1, cv::Scalar(0, 0, 255)); - } + cv::putText(draw, TileKeyMapping.at(info.key), cv::Point(info.pos.x, info.pos.y), 1, 1, cv::Scalar(0, 0, 255)); + } #endif - auto cb_info = basic_info_with_what("StageInfo"); - auto& details = cb_info["details"]; - details["name"] = m_stage_name; - details["size"] = m_side_tile_info.size(); - callback(AsstMsg::SubTaskExtraInfo, cb_info); - } - else { - callback(AsstMsg::SubTaskExtraInfo, basic_info_with_what("StageInfoError")); - } + auto cb_info = basic_info_with_what("StageInfo"); + auto& details = cb_info["details"]; + details["name"] = m_stage_name; + details["size"] = m_side_tile_info.size(); + callback(AsstMsg::SubTaskExtraInfo, cb_info); + } + else { + callback(AsstMsg::SubTaskExtraInfo, basic_info_with_what("StageInfoError")); + } - return calced; + return calced; } bool asst::RoguelikeBattleTaskPlugin::auto_battle() { - LogTraceFunction; + LogTraceFunction; - using Oper = asst::BattleImageAnalyzer::Oper; + using BattleRealTimeOper = asst::BattleRealTimeOper; - BattleImageAnalyzer battle_analyzer(m_ctrler->get_image()); + BattleImageAnalyzer battle_analyzer(m_ctrler->get_image()); + battle_analyzer.set_target(BattleImageAnalyzer::Target::Roguelike); - if (!battle_analyzer.analyze()) { - return false; - } + if (!battle_analyzer.analyze()) { + return false; + } - //if (int hp = battle_analyzer.get_hp(); - // hp != 0) { - // bool used_skills = false; - // if (hp < m_pre_hp) { // 说明漏怪了,漏怪就开技能( - // for (const Rect& rect : battle_analyzer.get_ready_skills()) { - // used_skills = true; - // if (!use_skill(rect)) { - // break; - // } - // } - // } - // m_pre_hp = hp; - // if (used_skills) { - // return true; - // } - //} + //if (int hp = battle_analyzer.get_hp(); + // hp != 0) { + // bool used_skills = false; + // if (hp < m_pre_hp) { // 说明漏怪了,漏怪就开技能( + // for (const Rect& rect : battle_analyzer.get_ready_skills()) { + // used_skills = true; + // if (!use_skill(rect)) { + // break; + // } + // } + // } + // m_pre_hp = hp; + // if (used_skills) { + // return true; + // } + //} - for (const Rect& rect : battle_analyzer.get_ready_skills()) { - // 找出这个可以使用的技能是哪个干员的(根据之前放干员的位置) - std::string name = "NotFound"; - for (const auto& [loc, oper_name] : m_used_tiles) { - auto point = m_normal_tile_info[loc].pos; - if (rect.include(point)) { - name = oper_name; - break; - } - } + for (const Rect& rect : battle_analyzer.get_ready_skills()) { + // 找出这个可以使用的技能是哪个干员的(根据之前放干员的位置) + std::string name = "NotFound"; + for (const auto& [loc, oper_name] : m_used_tiles) { + auto point = m_normal_tile_info[loc].pos; + if (rect.include(point)) { + name = oper_name; + break; + } + } - auto& usage = m_skill_usage[name]; - Log.info("Oper", name, ", skill usage", static_cast(usage)); - switch (usage) { - case BattleSkillUsage::Once: - use_skill(rect); - usage = BattleSkillUsage::OnceUsed; - return true; - break; - case BattleSkillUsage::Possibly: - use_skill(rect); - return true; - break; - } - } + auto& usage = m_skill_usage[name]; + Log.info("Oper", name, ", skill usage", static_cast(usage)); + switch (usage) { + case BattleSkillUsage::Once: + use_skill(rect); + usage = BattleSkillUsage::OnceUsed; + return true; + break; + case BattleSkillUsage::Possibly: + use_skill(rect); + return true; + break; + } + } - const auto& opers = battle_analyzer.get_opers(); - if (opers.empty()) { - return true; - } + const auto& opers = battle_analyzer.get_opers(); + if (opers.empty()) { + return true; + } - static const std::array RoleOrder = { - Role::Pioneer, - Role::Sniper, - Role::Warrior, - Role::Support, - Role::Medic, - Role::Caster, - Role::Special, - Role::Tank, - Role::Drone - }; - const auto use_oper_task_ptr = Task.get("BattleUseOper"); - const auto swipe_oper_task_ptr = Task.get("BattleSwipeOper"); + static const std::array RoleOrder = { + BattleRole::Pioneer, + BattleRole::Sniper, + BattleRole::Warrior, + BattleRole::Support, + BattleRole::Medic, + BattleRole::Caster, + BattleRole::Special, + BattleRole::Tank, + BattleRole::Drone + }; + const auto use_oper_task_ptr = Task.get("BattleUseOper"); + const auto swipe_oper_task_ptr = Task.get("BattleSwipeOper"); - // 点击当前最合适的干员 - Oper opt_oper; - bool oper_found = false; - for (auto role : RoleOrder) { - for (const auto& oper : opers) { - if (!oper.available) { - continue; - } - if (oper.role == role) { - opt_oper = oper; - oper_found = true; - break; - } - } - if (oper_found) { - break; - } - } - if (!oper_found) { - return true; - } - m_ctrler->click(opt_oper.rect); - sleep(use_oper_task_ptr->pre_delay); + // 点击当前最合适的干员 + BattleRealTimeOper opt_oper; + bool oper_found = false; + for (auto role : RoleOrder) { + for (const auto& oper : opers) { + if (!oper.available) { + continue; + } + if (oper.role == role) { + opt_oper = oper; + oper_found = true; + break; + } + } + if (oper_found) { + break; + } + } + if (!oper_found) { + return true; + } + m_ctrler->click(opt_oper.rect); + sleep(use_oper_task_ptr->pre_delay); - OcrImageAnalyzer oper_name_analyzer(m_ctrler->get_image()); - oper_name_analyzer.set_task_info(Task.get("BattleOperName")); - oper_name_analyzer.set_replace( - std::dynamic_pointer_cast( - Task.get("Roguelike1RecruitData")) - ->replace_map); + OcrImageAnalyzer oper_name_analyzer(m_ctrler->get_image()); + oper_name_analyzer.set_task_info("BattleOperName"); + oper_name_analyzer.set_replace( + std::dynamic_pointer_cast( + Task.get("Roguelike1RecruitData")) + ->replace_map); - std::string oper_name = "Unknown"; - if (oper_name_analyzer.analyze()) { - oper_name_analyzer.sort_result_by_score(); - oper_name = oper_name_analyzer.get_result().front().text; - } + std::string oper_name = "Unknown"; + if (oper_name_analyzer.analyze()) { + oper_name_analyzer.sort_result_by_score(); + oper_name = oper_name_analyzer.get_result().front().text; + } - // 将干员拖动到场上 - Loc loc = Loc::All; - switch (opt_oper.role) { - case Role::Medic: - case Role::Support: - case Role::Sniper: - case Role::Caster: - loc = Loc::Ranged; - break; - case Role::Pioneer: - case Role::Warrior: - case Role::Tank: - loc = Loc::Melee; - break; - case Role::Special: - case Role::Drone: - default: - // 特种和无人机,有的只能放地面,有的又只能放高台,不好判断 - // 笨办法,都试试,总有一次能成的 - //{ - // static Loc static_loc = Loc::Melee; - // loc = static_loc; - // if (static_loc == Loc::Melee) { - // static_loc = Loc::Ranged; - // } - // else { - // static_loc = Loc::Melee; - // } - //} - loc = Loc::Melee; - break; - } + // 将干员拖动到场上 + Loc loc = Loc::All; + switch (opt_oper.role) { + case BattleRole::Medic: + case BattleRole::Support: + case BattleRole::Sniper: + case BattleRole::Caster: + loc = Loc::Ranged; + break; + case BattleRole::Pioneer: + case BattleRole::Warrior: + case BattleRole::Tank: + loc = Loc::Melee; + break; + case BattleRole::Special: + case BattleRole::Drone: + default: + // 特种和无人机,有的只能放地面,有的又只能放高台,不好判断 + // 笨办法,都试试,总有一次能成的 + //{ + // static Loc static_loc = Loc::Melee; + // loc = static_loc; + // if (static_loc == Loc::Melee) { + // static_loc = Loc::Ranged; + // } + // else { + // static_loc = Loc::Melee; + // } + //} + loc = Loc::Melee; + break; + } - Point placed_loc = get_placed(loc); - Point placed_point = m_side_tile_info.at(placed_loc).pos; + Point placed_loc = get_placed(loc); + Point placed_point = m_side_tile_info.at(placed_loc).pos; #ifdef ASST_DEBUG - auto image = m_ctrler->get_image(); - cv::circle(image, cv::Point(placed_point.x, placed_point.y), 10, cv::Scalar(0, 0, 255), -1); + auto image = m_ctrler->get_image(); + cv::circle(image, cv::Point(placed_point.x, placed_point.y), 10, cv::Scalar(0, 0, 255), -1); #endif - Rect placed_rect(placed_point.x, placed_point.y, 1, 1); - m_ctrler->swipe(opt_oper.rect, placed_rect, swipe_oper_task_ptr->pre_delay); - sleep(use_oper_task_ptr->rear_delay); + Rect placed_rect(placed_point.x, placed_point.y, 1, 1); + m_ctrler->swipe(opt_oper.rect, placed_rect, swipe_oper_task_ptr->pre_delay); + sleep(use_oper_task_ptr->rear_delay); - // 计算往哪边拖动(干员朝向) - Point direction = calc_direction(placed_loc, opt_oper.role); + // 计算往哪边拖动(干员朝向) + Point direction = calc_direction(placed_loc, opt_oper.role); - // 将方向转换为实际的 swipe end 坐标点 - Point end_point = placed_point; - constexpr int coeff = 500; - end_point.x += direction.x * coeff; - end_point.y += direction.y * coeff; + // 将方向转换为实际的 swipe end 坐标点 + Point end_point = placed_point; + constexpr int coeff = 500; + end_point.x += direction.x * coeff; + end_point.y += direction.y * coeff; - end_point.x = std::max(0, end_point.x); - end_point.x = std::min(end_point.x, WindowWidthDefault); - end_point.y = std::max(0, end_point.y); - end_point.y = std::min(end_point.y, WindowHeightDefault); + end_point.x = std::max(0, end_point.x); + end_point.x = std::min(end_point.x, WindowWidthDefault); + end_point.y = std::max(0, end_point.y); + end_point.y = std::min(end_point.y, WindowHeightDefault); - m_ctrler->swipe(placed_point, end_point, swipe_oper_task_ptr->rear_delay); + m_ctrler->swipe(placed_point, end_point, swipe_oper_task_ptr->rear_delay); - m_used_tiles.emplace(placed_loc, oper_name); - m_opers_used = true; - ++m_cur_home_index; + m_used_tiles.emplace(placed_loc, oper_name); + m_opers_used = true; + ++m_cur_home_index; - return true; + return true; } bool asst::RoguelikeBattleTaskPlugin::speed_up() { - ProcessTask task(*this, { "BattleSpeedUp" }); - return task.run(); + ProcessTask task(*this, { "BattleSpeedUp" }); + return task.run(); } bool asst::RoguelikeBattleTaskPlugin::use_skill(const asst::Rect& rect) { - m_ctrler->click(rect); + m_ctrler->click(rect); - ProcessTask task(*this, { "BattleUseSkillBegin" }); - task.set_retry_times(0); - return task.run(); + ProcessTask task(*this, { "BattleUseSkillBegin" }); + task.set_retry_times(0); + return task.run(); } void asst::RoguelikeBattleTaskPlugin::clear() { - m_opers_used = false; - m_pre_hp = 0; - m_homes.clear(); - m_cur_home_index = 0; - m_stage_name.clear(); - m_side_tile_info.clear(); - m_used_tiles.clear(); + m_opers_used = false; + m_pre_hp = 0; + m_homes.clear(); + m_cur_home_index = 0; + m_stage_name.clear(); + m_side_tile_info.clear(); + m_used_tiles.clear(); - for (auto& [_, usage] : m_skill_usage) { - if (usage == BattleSkillUsage::OnceUsed) { - usage = BattleSkillUsage::Once; - } - } + for (auto& [_, usage] : m_skill_usage) { + if (usage == BattleSkillUsage::OnceUsed) { + usage = BattleSkillUsage::Once; + } + } } //asst::Rect asst::RoguelikeBattleTaskPlugin::get_placed_by_cv() @@ -358,177 +359,177 @@ void asst::RoguelikeBattleTaskPlugin::clear() asst::Point asst::RoguelikeBattleTaskPlugin::get_placed(Loc buildable_type) { - LogTraceFunction; + LogTraceFunction; - if (m_homes.empty()) { - for (const auto& [loc, side] : m_side_tile_info) { - if (side.key == TilePack::TileKey::Home) { - m_homes.emplace_back(loc); - } - } - if (m_homes.empty()) { - Log.error("Unknown home pos"); - } - } - if (m_cur_home_index >= m_homes.size()) { - m_cur_home_index = 0; - } + if (m_homes.empty()) { + for (const auto& [loc, side] : m_side_tile_info) { + if (side.key == TilePack::TileKey::Home) { + m_homes.emplace_back(loc); + } + } + if (m_homes.empty()) { + Log.error("Unknown home pos"); + } + } + if (m_cur_home_index >= m_homes.size()) { + m_cur_home_index = 0; + } - Point nearest; - int min_dist = INT_MAX; + Point nearest; + int min_dist = INT_MAX; - Point home(5, 5); // 默认值,一般是地图的中间 - if (m_cur_home_index < m_homes.size()) { - home = m_homes.at(m_cur_home_index); - } + Point home(5, 5); // 默认值,一般是地图的中间 + if (m_cur_home_index < m_homes.size()) { + home = m_homes.at(m_cur_home_index); + } - for (const auto& [loc, tile] : m_side_tile_info) { - if (tile.buildable == buildable_type - || tile.buildable == Loc::All) { - if (m_used_tiles.find(loc) != m_used_tiles.cend()) { - continue; - } - int dx = std::abs(home.x - loc.x); - int dy = std::abs(home.y - loc.y); - int dist = dx * dx + dy * dy; - if (dist <= min_dist) { - min_dist = dist; - nearest = loc; - } - } - } - Log.info(__FUNCTION__, nearest.to_string()); + for (const auto& [loc, tile] : m_side_tile_info) { + if (tile.buildable == buildable_type + || tile.buildable == Loc::All) { + if (m_used_tiles.find(loc) != m_used_tiles.cend()) { + continue; + } + int dx = std::abs(home.x - loc.x); + int dy = std::abs(home.y - loc.y); + int dist = dx * dx + dy * dy; + if (dist <= min_dist) { + min_dist = dist; + nearest = loc; + } + } + } + Log.info(__FUNCTION__, nearest.to_string()); - return nearest; + return nearest; } -asst::Point asst::RoguelikeBattleTaskPlugin::calc_direction(Point loc, Role role) +asst::Point asst::RoguelikeBattleTaskPlugin::calc_direction(Point loc, BattleRole role) { - LogTraceFunction; + LogTraceFunction; - // 根据家门的方向计算一下大概的朝向 - if (m_cur_home_index >= m_homes.size()) { - m_cur_home_index = 0; - } - Point home_loc(5, 5); - if (m_cur_home_index < m_homes.size()) { - home_loc = m_homes.at(m_cur_home_index); - } - Point home_point = m_side_tile_info.at(home_loc).pos; - Rect home_rect(home_point.x, home_point.y, 1, 1); + // 根据家门的方向计算一下大概的朝向 + if (m_cur_home_index >= m_homes.size()) { + m_cur_home_index = 0; + } + Point home_loc(5, 5); + if (m_cur_home_index < m_homes.size()) { + home_loc = m_homes.at(m_cur_home_index); + } + Point home_point = m_side_tile_info.at(home_loc).pos; + Rect home_rect(home_point.x, home_point.y, 1, 1); - int dx = 0; - if (loc.x > home_loc.x) dx = 1; - else if (loc.x < home_loc.x) dx = -1; - else dx = 0; + int dx = 0; + if (loc.x > home_loc.x) dx = 1; + else if (loc.x < home_loc.x) dx = -1; + else dx = 0; - int dy = 0; - if (loc.y > home_loc.y) dy = 1; - else if (loc.y < home_loc.y) dy = -1; - else dy = 0; + int dy = 0; + if (loc.y > home_loc.y) dy = 1; + else if (loc.y < home_loc.y) dy = -1; + else dy = 0; - Point base_direction(0, 0); - switch (role) { - case Role::Medic: - { - if (std::abs(dx) < std::abs(dy)) { - base_direction.y = -dy; - } - else { - base_direction.x = -dx; - } - } - break; - case Role::Support: - case Role::Pioneer: - case Role::Warrior: - case Role::Sniper: - case Role::Special: - case Role::Tank: - case Role::Caster: - case Role::Drone: - default: - { - if (std::abs(dx) < std::abs(dy)) { - base_direction.y = dy; - } - else { - base_direction.x = dx; - } - } - break; - } + Point base_direction(0, 0); + switch (role) { + case BattleRole::Medic: + { + if (std::abs(dx) < std::abs(dy)) { + base_direction.y = -dy; + } + else { + base_direction.x = -dx; + } + } + break; + case BattleRole::Support: + case BattleRole::Pioneer: + case BattleRole::Warrior: + case BattleRole::Sniper: + case BattleRole::Special: + case BattleRole::Tank: + case BattleRole::Caster: + case BattleRole::Drone: + default: + { + if (std::abs(dx) < std::abs(dy)) { + base_direction.y = dy; + } + else { + base_direction.x = dx; + } + } + break; + } - using TileKey = TilePack::TileKey; + using TileKey = TilePack::TileKey; - // 战斗干员朝向的权重 - static const std::unordered_map TileKeyFightWeights = { - { TileKey::Invalid, 0 }, - { TileKey::Forbidden, 0 }, - { TileKey::Wall, 500 }, - { TileKey::Road, 1000 }, - { TileKey::Home, 1000 }, - { TileKey::EnemyHome, 1000 }, - { TileKey::Floor, 1000 }, - { TileKey::Hole, 0 }, - { TileKey::Telin, 0 }, - { TileKey::Telout, 0 } - }; + // 战斗干员朝向的权重 + static const std::unordered_map TileKeyFightWeights = { + { TileKey::Invalid, 0 }, + { TileKey::Forbidden, 0 }, + { TileKey::Wall, 500 }, + { TileKey::Road, 1000 }, + { TileKey::Home, 1000 }, + { TileKey::EnemyHome, 1000 }, + { TileKey::Floor, 1000 }, + { TileKey::Hole, 0 }, + { TileKey::Telin, 0 }, + { TileKey::Telout, 0 } + }; - static const std::unordered_map DirectionStartingPoint = { - { Point(1, 0), Point(0, -1) }, // 朝右 - { Point(0, 1), Point(-1, 0) }, // 朝下 - { Point(-1, 0), Point(-2, -1) }, // 朝左 - { Point(0, -1), Point(-1, -2) }, // 朝上 - }; + static const std::unordered_map DirectionStartingPoint = { + { Point(1, 0), Point(0, -1) }, // 朝右 + { Point(0, 1), Point(-1, 0) }, // 朝下 + { Point(-1, 0), Point(-2, -1) }, // 朝左 + { Point(0, -1), Point(-1, -2) }, // 朝上 + }; - int max_score = 0; - Point opt_direction; + int max_score = 0; + Point opt_direction; - // 计算每个方向上的得分 - for (const auto& [direction, point_move] : DirectionStartingPoint) { - Point start_point = loc; - start_point.x += point_move.x; - start_point.y += point_move.y; - int score = 0; + // 计算每个方向上的得分 + for (const auto& [direction, point_move] : DirectionStartingPoint) { + Point start_point = loc; + start_point.x += point_move.x; + start_point.y += point_move.y; + int score = 0; - constexpr int AttackRangeSize = 3; - // 这个方向上 3x3 的格子,计算总的得分 - for (int i = 0; i != AttackRangeSize; ++i) { - for (int j = 0; j != AttackRangeSize; ++j) { - Point cur_point = start_point; - cur_point.x += i; - cur_point.y += j; + constexpr int AttackRangeSize = 3; + // 这个方向上 3x3 的格子,计算总的得分 + for (int i = 0; i != AttackRangeSize; ++i) { + for (int j = 0; j != AttackRangeSize; ++j) { + Point cur_point = start_point; + cur_point.x += i; + cur_point.y += j; - switch (role) { - // 医疗干员根据哪个方向上人多决定朝向哪 - case Role::Medic: - if (m_used_tiles.find(cur_point) != m_used_tiles.cend()) { - score += 1000; - } - break; - // 其他干员(战斗干员)根据哪个方向上权重高决定朝向哪 - default: - if (auto iter = m_side_tile_info.find(cur_point); - iter == m_side_tile_info.cend()) { - continue; - } - else { - score += TileKeyFightWeights.at(iter->second.key); - } - } - } - } + switch (role) { + // 医疗干员根据哪个方向上人多决定朝向哪 + case BattleRole::Medic: + if (m_used_tiles.find(cur_point) != m_used_tiles.cend()) { + score += 1000; + } + break; + // 其他干员(战斗干员)根据哪个方向上权重高决定朝向哪 + default: + if (auto iter = m_side_tile_info.find(cur_point); + iter == m_side_tile_info.cend()) { + continue; + } + else { + score += TileKeyFightWeights.at(iter->second.key); + } + } + } + } - if (direction == base_direction) { - score += 50; - } + if (direction == base_direction) { + score += 50; + } - if (score > max_score) { - max_score = score; - opt_direction = direction; - } - } + if (score > max_score) { + max_score = score; + opt_direction = direction; + } + } - return opt_direction; -} \ No newline at end of file + return opt_direction; +} diff --git a/src/MeoAssistant/RoguelikeBattleTaskPlugin.h b/src/MeoAssistant/RoguelikeBattleTaskPlugin.h index 1827e10e51..fda6a12da3 100644 --- a/src/MeoAssistant/RoguelikeBattleTaskPlugin.h +++ b/src/MeoAssistant/RoguelikeBattleTaskPlugin.h @@ -11,7 +11,6 @@ namespace asst class RoguelikeBattleTaskPlugin : public AbstractTaskPlugin { using Loc = asst::TilePack::BuildableType; - using Role = asst::BattleImageAnalyzer::Role; public: using SkillUsageMap = std::unordered_map; public: @@ -38,7 +37,7 @@ namespace asst // 计算摆放干员的朝向 // 返回滑动的方向 - Point calc_direction(Point loc, Role role); + Point calc_direction(Point loc, BattleRole role); bool m_opers_used = false; int m_pre_hp = 0; diff --git a/src/MeoAssistant/RoguelikeFormationImageAnalyzer.cpp b/src/MeoAssistant/RoguelikeFormationImageAnalyzer.cpp index 2680d1beeb..40d5f9e81b 100644 --- a/src/MeoAssistant/RoguelikeFormationImageAnalyzer.cpp +++ b/src/MeoAssistant/RoguelikeFormationImageAnalyzer.cpp @@ -8,7 +8,7 @@ bool asst::RoguelikeFormationImageAnalyzer::analyze() { MultiMatchImageAnalyzer opers_analyzer(m_image); - opers_analyzer.set_task_info(Task.get("Roguelike1FormationOper")); + opers_analyzer.set_task_info("Roguelike1FormationOper"); if (!opers_analyzer.analyze()) { return false; @@ -16,7 +16,7 @@ bool asst::RoguelikeFormationImageAnalyzer::analyze() opers_analyzer.sort_result(); const auto& all_opers = opers_analyzer.get_result(); for (const MatchRect& oper_mr : all_opers) { - Oper oper; + FormationOper oper; oper.rect = oper_mr.rect; oper.selected = selected_analyze(oper_mr.rect); @@ -35,7 +35,7 @@ bool asst::RoguelikeFormationImageAnalyzer::analyze() return !m_result.empty(); } -const std::vector& +const std::vector& asst::RoguelikeFormationImageAnalyzer::get_result() const noexcept { return m_result; diff --git a/src/MeoAssistant/RoguelikeFormationImageAnalyzer.h b/src/MeoAssistant/RoguelikeFormationImageAnalyzer.h index 011acc1760..3275bbcc89 100644 --- a/src/MeoAssistant/RoguelikeFormationImageAnalyzer.h +++ b/src/MeoAssistant/RoguelikeFormationImageAnalyzer.h @@ -6,7 +6,7 @@ namespace asst class RoguelikeFormationImageAnalyzer final : public AbstractImageAnalyzer { public: - struct Oper + struct FormationOper { Rect rect; bool selected = false; @@ -18,7 +18,7 @@ namespace asst virtual bool analyze() override; - const std::vector& get_result() const noexcept; + const std::vector& get_result() const noexcept; protected: // 该分析器不支持外部设置ROI virtual void set_roi(const Rect& roi) noexcept override @@ -32,6 +32,6 @@ namespace asst bool selected_analyze(const Rect& roi); - std::vector m_result; + std::vector m_result; }; } diff --git a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp index a144c969fd..228b3a3f92 100644 --- a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp @@ -27,7 +27,7 @@ bool asst::RoguelikeRecruitTaskPlugin::verify(AsstMsg msg, const json::value& de bool asst::RoguelikeRecruitTaskPlugin::_run() { OcrImageAnalyzer analyzer(m_ctrler->get_image()); - analyzer.set_task_info(Task.get("Roguelike1RecruitData")); + analyzer.set_task_info("Roguelike1RecruitData"); analyzer.set_required(m_opers); if (!analyzer.analyze()) { diff --git a/src/MeoAssistant/RoguelikeSkillSelectionImageAnalyzer.cpp b/src/MeoAssistant/RoguelikeSkillSelectionImageAnalyzer.cpp index 31c7b95edf..009c1f43bf 100644 --- a/src/MeoAssistant/RoguelikeSkillSelectionImageAnalyzer.cpp +++ b/src/MeoAssistant/RoguelikeSkillSelectionImageAnalyzer.cpp @@ -9,7 +9,7 @@ bool asst::RoguelikeSkillSelectionImageAnalyzer::analyze() { MultiMatchImageAnalyzer flag_analyzer(m_image); - flag_analyzer.set_task_info(Task.get("Roguelike1SkillSelectionFlag")); + flag_analyzer.set_task_info("Roguelike1SkillSelectionFlag"); if (!flag_analyzer.analyze()) { return false; diff --git a/src/MeoAssistant/RoguelikeTask.cpp b/src/MeoAssistant/RoguelikeTask.cpp index 0abdff7621..d88779f4e2 100644 --- a/src/MeoAssistant/RoguelikeTask.cpp +++ b/src/MeoAssistant/RoguelikeTask.cpp @@ -10,78 +10,78 @@ #include "Logger.hpp" asst::RoguelikeTask::RoguelikeTask(AsstCallback callback, void* callback_arg) - : PackageTask(callback, callback_arg, TaskType), - m_roguelike_task_ptr(std::make_shared(callback, callback_arg, TaskType)) + : PackageTask(callback, callback_arg, TaskType), + m_roguelike_task_ptr(std::make_shared(callback, callback_arg, TaskType)) { - m_roguelike_task_ptr->set_tasks({ "Roguelike1Begin" }) - .set_retry_times(50); + m_roguelike_task_ptr->set_tasks({ "Roguelike1Begin" }) + .set_retry_times(50); - m_roguelike_task_ptr->regiseter_plugin(); + m_roguelike_task_ptr->regiseter_plugin(); - m_battle_task_ptr = m_roguelike_task_ptr->regiseter_plugin(); + m_battle_task_ptr = m_roguelike_task_ptr->regiseter_plugin(); - m_recruit_task_ptr = m_roguelike_task_ptr->regiseter_plugin(); - m_recruit_task_ptr->set_retry_times(2); + m_recruit_task_ptr = m_roguelike_task_ptr->regiseter_plugin(); + m_recruit_task_ptr->set_retry_times(2); - m_skill_task_ptr = m_roguelike_task_ptr->regiseter_plugin(); - m_skill_task_ptr->set_retry_times(0); + m_skill_task_ptr = m_roguelike_task_ptr->regiseter_plugin(); + m_skill_task_ptr->set_retry_times(0); - // 这个任务如果卡住会放弃当前的肉鸽并重新开始,所以多添加一点。先这样凑合用 - for (int i = 0; i != 10000; ++i) { - m_subtasks.emplace_back(m_roguelike_task_ptr); - } + // 这个任务如果卡住会放弃当前的肉鸽并重新开始,所以多添加一点。先这样凑合用 + for (int i = 0; i != 10000; ++i) { + m_subtasks.emplace_back(m_roguelike_task_ptr); + } } bool asst::RoguelikeTask::set_params(const json::value& params) { - // 0 - 尽可能一直往后打 - // 1 - 第一层投资完源石锭就退出 - // 2 - 投资过后再退出,没有投资就继续往后打 + // 0 - 尽可能一直往后打 + // 1 - 第一层投资完源石锭就退出 + // 2 - 投资过后再退出,没有投资就继续往后打 - if (!params.contains("opers") || !params.at("opers").is_array()) { - return false; - } + if (!params.contains("opers") || !params.at("opers").is_array()) { + return false; + } - std::vector opers_vec; - RoguelikeSkillSelectionTaskPlugin::SkillMap skill_map; - RoguelikeBattleTaskPlugin::SkillUsageMap usage_map; + std::vector opers_vec; + RoguelikeSkillSelectionTaskPlugin::SkillMap skill_map; + RoguelikeBattleTaskPlugin::SkillUsageMap usage_map; - for (auto& oper : params.at("opers").as_array()) { - if (!oper.contains("name") || !oper.at("name").is_string()) { - return false; - } - int skill = oper.get("skill", 1); - if (skill < 1 || 3 < skill) { - return false; - } - std::string name = oper.at("name").as_string(); - opers_vec.emplace_back(name); - skill_map.emplace(name, skill); + for (auto& oper : params.at("opers").as_array()) { + if (!oper.contains("name") || !oper.at("name").is_string()) { + return false; + } + int skill = oper.get("skill", 1); + if (skill < 1 || 3 < skill) { + return false; + } + std::string name = oper.at("name").as_string(); + opers_vec.emplace_back(name); + skill_map.emplace(name, skill); - auto usage = static_cast(oper.get("skill_usage", 0)); - usage_map.emplace(name, usage); - } - skill_map.emplace("Unknown", 3); + auto usage = static_cast(oper.get("skill_usage", 0)); + usage_map.emplace(name, usage); + } + skill_map.emplace("Unknown", 3); - int mode = params.get("mode", 0); - switch (mode) { - case 0: - break; - case 1: - m_roguelike_task_ptr->set_times_limit("Roguelike1StageTraderLeave", 0); - break; - case 2: - m_roguelike_task_ptr->set_times_limit("Roguelike1StageTraderInvestCancel", 0); - break; - default: - Log.error(__FUNCTION__, "| Unknown mode", mode); - return false; - } + int mode = params.get("mode", 0); + switch (mode) { + case 0: + break; + case 1: + m_roguelike_task_ptr->set_times_limit("Roguelike1StageTraderLeave", 0); + break; + case 2: + m_roguelike_task_ptr->set_times_limit("Roguelike1StageTraderInvestCancel", 0); + break; + default: + Log.error(__FUNCTION__, "| Unknown mode", mode); + return false; + } - m_recruit_task_ptr->set_opers(std::move(opers_vec)); - m_skill_task_ptr->set_skill_map(std::move(skill_map)); + m_recruit_task_ptr->set_opers(std::move(opers_vec)); + m_skill_task_ptr->set_skill_map(std::move(skill_map)); - m_battle_task_ptr->set_skill_usage(std::move(usage_map)); + m_battle_task_ptr->set_skill_usage(std::move(usage_map)); - return true; -} \ No newline at end of file + return true; +} diff --git a/tools/TestCaller/main.cpp b/tools/TestCaller/main.cpp index aaa26e1831..9b1c77ca16 100644 --- a/tools/TestCaller/main.cpp +++ b/tools/TestCaller/main.cpp @@ -72,25 +72,25 @@ int main(int argc, char** argv) //)"); // AsstAppendTask(ptr, "Award", R"({})"); // - AsstAppendTask(ptr, "Roguelike", R"( - { - "opers": [ - { - "name": "山", - "skill": 2, - "skill_usage": 1 - }, - { - "name": "梓兰" - }, - { - "name": "芙蓉" - } - ] - } - )"); + //AsstAppendTask(ptr, "Roguelike", R"( + //{ + // "opers": [ + // { + // "name": "山", + // "skill": 2, + // "skill_usage": 1 + // }, + // { + // "name": "梓兰" + // }, + // { + // "name": "芙蓉" + // } + // ] + //} + //)"); - //AsstAppendTask(ptr, "Debug", R"({})"); + AsstAppendTask(ptr, "Debug", R"({})"); AsstStart(ptr);