From 97e2bead13112131e92452127c8973751fc33c61 Mon Sep 17 00:00:00 2001 From: 756yang <72987022+756yang@users.noreply.github.com> Date: Fri, 26 Dec 2025 20:48:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0js=E8=84=9A=E6=9C=AC-?= =?UTF-8?q?=E5=9C=A3=E9=81=97=E7=89=A9=E8=BE=85=E5=8A=A9=20(#2565)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 增加js脚本-圣遗物辅助 * 修复圣遗物辅助的问题 --- repo/js/ArtifactsAssistant/README.md | 41 ++ repo/js/ArtifactsAssistant/assets/0.png | Bin 0 -> 1056 bytes repo/js/ArtifactsAssistant/assets/1.png | Bin 0 -> 768 bytes repo/js/ArtifactsAssistant/assets/10.png | Bin 0 -> 1419 bytes repo/js/ArtifactsAssistant/assets/11.png | Bin 0 -> 791 bytes repo/js/ArtifactsAssistant/assets/12.png | Bin 0 -> 1369 bytes repo/js/ArtifactsAssistant/assets/13.png | Bin 0 -> 1471 bytes repo/js/ArtifactsAssistant/assets/14.png | Bin 0 -> 1233 bytes repo/js/ArtifactsAssistant/assets/15.png | Bin 0 -> 1407 bytes repo/js/ArtifactsAssistant/assets/16.png | Bin 0 -> 1391 bytes repo/js/ArtifactsAssistant/assets/17.png | Bin 0 -> 1190 bytes repo/js/ArtifactsAssistant/assets/18.png | Bin 0 -> 1507 bytes repo/js/ArtifactsAssistant/assets/19.png | Bin 0 -> 1417 bytes repo/js/ArtifactsAssistant/assets/2.png | Bin 0 -> 980 bytes repo/js/ArtifactsAssistant/assets/20.png | Bin 0 -> 1419 bytes repo/js/ArtifactsAssistant/assets/3.png | Bin 0 -> 1274 bytes repo/js/ArtifactsAssistant/assets/4.png | Bin 0 -> 994 bytes repo/js/ArtifactsAssistant/assets/5.png | Bin 0 -> 1173 bytes repo/js/ArtifactsAssistant/assets/6.png | Bin 0 -> 1175 bytes repo/js/ArtifactsAssistant/assets/7.png | Bin 0 -> 994 bytes repo/js/ArtifactsAssistant/assets/8.png | Bin 0 -> 1309 bytes repo/js/ArtifactsAssistant/assets/9.png | Bin 0 -> 1205 bytes repo/js/ArtifactsAssistant/assets/star.png | Bin 0 -> 1064 bytes repo/js/ArtifactsAssistant/main.js | 759 ++++++++++++++++++++ repo/js/ArtifactsAssistant/manifest.json | 21 + repo/js/ArtifactsAssistant/overlay.c | 278 ++++++++ repo/js/ArtifactsAssistant/overlay.exe | Bin 0 -> 45568 bytes repo/js/ArtifactsAssistant/settings.json | 8 + repo/js/ArtifactsAssistant/角色一览.md | 779 +++++++++++++++++++++ 29 files changed, 1886 insertions(+) create mode 100644 repo/js/ArtifactsAssistant/README.md create mode 100644 repo/js/ArtifactsAssistant/assets/0.png create mode 100644 repo/js/ArtifactsAssistant/assets/1.png create mode 100644 repo/js/ArtifactsAssistant/assets/10.png create mode 100644 repo/js/ArtifactsAssistant/assets/11.png create mode 100644 repo/js/ArtifactsAssistant/assets/12.png create mode 100644 repo/js/ArtifactsAssistant/assets/13.png create mode 100644 repo/js/ArtifactsAssistant/assets/14.png create mode 100644 repo/js/ArtifactsAssistant/assets/15.png create mode 100644 repo/js/ArtifactsAssistant/assets/16.png create mode 100644 repo/js/ArtifactsAssistant/assets/17.png create mode 100644 repo/js/ArtifactsAssistant/assets/18.png create mode 100644 repo/js/ArtifactsAssistant/assets/19.png create mode 100644 repo/js/ArtifactsAssistant/assets/2.png create mode 100644 repo/js/ArtifactsAssistant/assets/20.png create mode 100644 repo/js/ArtifactsAssistant/assets/3.png create mode 100644 repo/js/ArtifactsAssistant/assets/4.png create mode 100644 repo/js/ArtifactsAssistant/assets/5.png create mode 100644 repo/js/ArtifactsAssistant/assets/6.png create mode 100644 repo/js/ArtifactsAssistant/assets/7.png create mode 100644 repo/js/ArtifactsAssistant/assets/8.png create mode 100644 repo/js/ArtifactsAssistant/assets/9.png create mode 100644 repo/js/ArtifactsAssistant/assets/star.png create mode 100644 repo/js/ArtifactsAssistant/main.js create mode 100644 repo/js/ArtifactsAssistant/manifest.json create mode 100644 repo/js/ArtifactsAssistant/overlay.c create mode 100644 repo/js/ArtifactsAssistant/overlay.exe create mode 100644 repo/js/ArtifactsAssistant/settings.json create mode 100644 repo/js/ArtifactsAssistant/角色一览.md diff --git a/repo/js/ArtifactsAssistant/README.md b/repo/js/ArtifactsAssistant/README.md new file mode 100644 index 000000000..55e2a639d --- /dev/null +++ b/repo/js/ArtifactsAssistant/README.md @@ -0,0 +1,41 @@ + +# 圣遗物辅助 + +本脚本在后台定时运行,如果你在原神里面查看背包、角色身上的单个圣遗物,那么会在`BetterGI`的遮罩窗口显示文本,以告知这个圣遗物的评价、适用角色等等。 + +请先运行`overlay.exe`,它会不断读取`overlay.txt`并刷新到其窗口上,以解决`BetterGI`的遮罩窗口显示文本难以辨识的问题。 + +你也可以修改脚本自定义配置,`是否在遮罩窗口输出`取消勾选以避免在`BetterGI`的遮罩窗口显示信息。 + +输出信息说明: + +``` txt +==== 完全圣遗物 ==== +黄金剧团:生之花,金,等级+20 +总点数:76.3,主属性:生命值 4780 +副属性1:+0次,生命值+5.3% +副属性2:+0次,防御力+19 +副属性3:+4次,暴击伤害+31.1% +副属性4:+1次,暴击率+7.4% +适配:八重神子、千织、爱可菲、芙宁娜、菲谢尔、阿贝多 +词条点(61.1):*暴击*、*暴伤*、攻击、精通 +---------------- +``` + +- `==== 完全圣遗物 ====`,表示五星初始四个词条而四星初始三词条,可能因计算误判 +- `==== 圣遗物 ====`,表示五星初始三个词条而四星初始两词条,这个不会误判 +- `总点数`,是圣遗物副属性所有点数之和,每个词条随机`7`到`10`点 +- `副属性`後接其已强化次数和属性值,`词条点`後接于角色适用词条的总点数和名称(有则带`*`) +- `这个圣遗物不堪大用啊`,这个圣遗物对目前所有角色都不好用,可合成其他圣遗物或当狗粮喂掉 +- `适配:`,这个圣遗物可为角色的毕业圣遗物,如果属性点不好,可以考虑重塑一下 +- `可用:`,这个圣遗物可为角色的好用圣遗物,可以尝试看看属性点好不好 + + +关于`角色一览.md`的配置: + +1. 你可以自由修改或增加配置项,但必须符合原始语法 +2. 数字序号後必须接空格和角色名称,例如`108. 杜林` +3. 换行规则请务必满足,不要缺少换行符,否则解析会出问题,请确保结尾有两个换行符 +4. 一个搭配项的不同名称以`、`分隔,若角色有两种搭配,则每种搭配以`;`分隔,搭配项依次排列 +5. `圣遗物主词条:`配置`时之沙`、`空之杯`、`理之冠`的主属性,同一部件允许多个主属性则以`/`分隔 +6. 六种默认模板`生命输出`,`攻击输出`,`防御输出`,`生命治疗`,`攻击治疗`,`防御治疗`,最好不要修改 diff --git a/repo/js/ArtifactsAssistant/assets/0.png b/repo/js/ArtifactsAssistant/assets/0.png new file mode 100644 index 0000000000000000000000000000000000000000..97b654b6da401d6f0d7f4f0fff7f6b6951d08059 GIT binary patch literal 1056 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 VTQiouN?ZT{002ovPDHLkV1lsFZ?*sc literal 0 HcmV?d00001 diff --git a/repo/js/ArtifactsAssistant/assets/12.png b/repo/js/ArtifactsAssistant/assets/12.png new file mode 100644 index 0000000000000000000000000000000000000000..7db76794d5072e3c03221457b3424eeb9dc01fc7 GIT binary patch literal 1369 zcmV-f1*ZCmP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1nx;hK~zXfwU%2< z+f^LLd!u(~3!{{lLb-zjfpQaZpuiYRaKuR#h3JySWP9?>=$rAy%hP<(J-EbVOBQvR z!m?FmZo|xh3|JZCercfvdg0QR-nsc*&%a0!8Yc0Rll;&5{m=jWf9H2QhhA2Figsui z33-C&(;GZq zFIi+8rZOdq>OLpX1IAD#DXS~X&$cwz)>L9RGB)vacnoia0)AEH%jeIvmX{U@_5&+TSQ;B6 z7DY|zW)_#0sTBh-sOMftBw}@b?n}k$tc*1Lo{|PoB`VLHZfvNl#_G_6k_L&17OV4e zQ&frQ508vr{r*NzpLT3w>ZYbc({XQYeI4@j)a0@fH8vdhf+CzYr9}mwee%&4pMHGd zTq{|68*J;+w^zRW>YMw2bRi@uX%LxInx2-74jf@zFkv#0!+7wH&1Od*wo%AsY&M&` zB81b1&Y;6lfzC6Ckl^?GVfLP0?e(_X+9yMlG)PpG@JLKFIzFG@<#O!|4y4lhI+aZf zIs-l>eL^^G4#JAfHost^20@^N*<#h{XD6riX0w%&(rBgfRiT=jMCK{1%Gw^g|`tysZF)#zF z3lYK$>8Yxc!aOdAgWDLaTQ3D$7^}6a0KR6!|5ivfgyL9==;Ls@b;$R?9aAKT1QPo&q12a2T zomjl>)^B~d%eE<54x}Y`179L*~x*l!6CKloC*(e7$ycEa# z=~E|>Wk<6z$Q(jQ6z>8-XE4qqClP?V4%jA3F*hcX`~^Z-gKYA)^)Bcl@-a@cHKwIB@BU`6cEWVVnM2><=IML-ZF zB_>EjqI(azerngisSrj*3UM33W-Qjl{hGlz*V8wEvQE|^9QG!PYJ~JbJ{#v2c3tG2 b8yf9z>oh-Wew|Tp00000NkvXXu0mjfAn$uI literal 0 HcmV?d00001 diff --git a/repo/js/ArtifactsAssistant/assets/13.png b/repo/js/ArtifactsAssistant/assets/13.png new file mode 100644 index 0000000000000000000000000000000000000000..90e12649cfb65b14fb2d57ce74fe1cd936f9ee81 GIT binary patch literal 1471 zcmV;w1wi_VP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1yo5yK~zXfwN`6P zTV)t-X-j(wwDb;zUbznjGS~%o!3~Cs(@7+F*~QJMQ(~h3%=~Bcht9;9B^no_iOGKG z52CW@=5&(<&6o_KaxLW!Eu~yap{1o4z^DB_8bMa3#3v{1`@QEo-+9mbyf=1P#gnXU zBQ7pZC}ffn6MViU*Zcxive^PgAWBMP7>3K?u-WWTD757FdpwJaUf=TaGTHWbY}Xpt zk&qx%r>IJbcNP`o{oZQ&=IV9mIUJ5sA=|yHX#c*_Ort?6NoKQI^9%0Laa)_I^X|R2 z(J`BEX^9*X1xI7drQ*K??0_@$I!#6S{&S~lt18Q}?CtCC>gj_U(o$1SK3#q0xf-Kh z%jIzwz1~0|C}bF|CT&+yL54v;Jv(c6Os}l0(BmSAWer@-fr~j@oW8ocO0^L%j3C3H zJ9^~Mxzn{r44E?3!BNa1ab6#Gwdxbe(&uI z7vFiS?#0t^IMqflI6Qj!^D7@*`t){FvuDvuwQEQgi&B&d2$PO!ybobZ^mDHHfuWK4 zg>aa|H*&d@=%a{b4Lgnvq9Q^VL`e_`1RT>dEv=^dhHIdJYS-Wo1ScI+{e#11%Ye=9 zpjtvbhn^D*h5Y^ik)w!Z&4Xah<(jZh(#0Bj&6amBUV7#A3-5pUNsrk=ln6kDLY|dj zlq8F>oSAiwS#9K26zi-(&CsN&_1biDDP&R>@{+|8@Z(ce%BVg?rQq{vtSm3D;39Gq zE32#cbOa545pxE;HapW;T$o>5ef(HuIpQ7MwVArwO*VVoJeAKbsy?tNRHy|U(GB!#dDtztyS-DKg<8cYyV7a}c`-dC1z%|(u#X8?4 z2$^(siY6_UTrdmY0X;mSl*^)el~N%TFyxUf;Scyhirq0aVRxWRqXffqaF`}tjX9(YMF65$E_3i03<=#o)UvjgA7;5W$0WF?=8`3)3FC3WwlKXkB&zkrC8^v z4M0TWP&jkJ?Ln4O?ftRfc2CdDLa^B;TmCQ=7UaPb2q3grgerK+$ut@bS_m*2iFv1` zmF$lqRu2yZgQyT_`k2-3#}r1Eo%y->J94n+?!ES#jlZHCpxcuP5S2;5@Ks8APF6;C zra>xA#y|rSErY|~egESxP0br7!2dpN5g?P{d5Kuu_*?V0SFeLqqQ@)Iu0b+_2CoF^ zuy58m2kIM}?tER}fGP2x!{~M=QB)(0P6$t{&AwrfBS7Eg3;3d>q<9_=ZUdVnwl)Ea Z^%qd=V-6q`-nIY$002ovPDHLkV1mO0yc7Tc literal 0 HcmV?d00001 diff --git a/repo/js/ArtifactsAssistant/assets/14.png b/repo/js/ArtifactsAssistant/assets/14.png new file mode 100644 index 0000000000000000000000000000000000000000..c02b7f4c6faaf5b7ec5854871d53d149ae21d888 GIT binary patch literal 1233 zcmV;?1TOoDP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1ZGJ@K~zXft(IL( zn^hRc`wcBn%2!K)cBQMN+W=vRSO#Mi#>PNI7W6{nF3ggt(Iv)A6J6qk@ydAZgz|!Nzu)1+UryTdKF@hi|L=32=XuN4 zwZ6*Q8ypTtBogLiX9WU}-JUgSO@zZ{i^VyGh50-#Hyn<*J)WiIRqBg_t59p{^x1)q z?CdO+vP^$e*VEZ95D3OClhl`pM3URv-SO#1@Avg|ood%}dAvJA2I`B0L%*L9=n&^* zS7_8dohLr~_=ES(o;j$k$jA^-cOrZ~zpl3WL|aRiNQ6s>7G`D=R}zeB5L+IPi;cKk zE;a2S6lOw4Z}+LsFMN3JowqdmRai`YDZr&xDO+2PC`wDHi5W&Ud3lnI$8mjG zN%553vAhyXx;3xQXtEg16I?c@L|!Zq@L@y>kDAP5CJR|Z;PZG5^|hzFJ62X7O-@ZK z6{SRk#X2=GI7HUO!x$SjhmHJyGTDY03Bh1+ae3wL(8!f*zm7aGQfmtM;eFc)-iQ>w zeP?*c@PInDNgvYxn8gH_+dc1Gpcg5i+!`BRc(Ja=@b}owKL<89HzSb<^)V1rgPwsz zL%EVsRFF>|ATvWCmr0}cVp&nNc0!>r2AL;;3aF_%)OM^1XLM^|aAtOnI-UxTezREB zhYp;1voBAQOD?msMC7E@s(tUCeS2dgNbJUO%cU#VkObs1EjXjH61l!vS6nRZzkcKP z;4qAcOG0Sys41a}#U@K6M8Yac$v8wpT38UZ%cMo3Od+|232dcnsKbEto3{p{ z)dW3cf}P3cNyOB+JZmPi)nuL^W8S$)jv0GRJ7%MHo895{`N%D4!5LLm9yqRV-rCw4 zHJaz<7bLl2jQBPo;PZ3EIWVGy#`nzFN!=eA#h@1~R_Dpq3+K`NWH zA(zRHHR-e!8a$7*sNnV9E@IcH%egzXsV-Ocz19_pgad(%F_YP_QI=q|g0j*OQxK1qX)r|O`#P2WV`dJ~hj8-M&24&$UATWxl-05GaS45w!v zW(Wk%g{64;OrY^>ZH1s4ttD-D*$4(-ZfS%Xtg%hcT>bev)KK3Jj39T&FD@;ILLq8RM>rDk`PT8i95-93 zi5a96iZtov8f8yejOX*Ld2KdF|8KuvzS@shDRra+$2~je9K2`1%6r2j)SAei{uiSg vp`#!b9?m(_Mn0axf_#ZYj3&gGg)G)TRA1cDuFwtt00000NkvXXu0mjffN)H` literal 0 HcmV?d00001 diff --git a/repo/js/ArtifactsAssistant/assets/15.png b/repo/js/ArtifactsAssistant/assets/15.png new file mode 100644 index 0000000000000000000000000000000000000000..3242f8c842e8124fd0d397776d5a852dae11637f GIT binary patch literal 1407 zcmV-_1%UdAP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1r$j{K~zXfwN`6P zn^hS8dZG6#g_af=9k-R+U`(gX;f91Mn?XaOe>B?RE)P%Ru=f4O1kVz$l`MJ-Z zefpiZUVrVv`C>yMpUmZ5Jr>is`+%?MX)1KQUf<%9WnpodwE2al@rkMHKXu&b zycLZL6Tqd<-GD#H%gy2Q_;!bLYQ_vs&|6uw?m$iT@%P@oR9{zH{eH>L;iJ|u76QOYU_nzL?>%S~ntfX01Y%Z5O5=l4} zg1sWeVzaoh7_q<+cEZYFFo>7_dDnQg^+#jBiCW_z6biu)9*>7GIoH;x^+EXWEGBR` zor_D$bPxxbOp+EO4S337a}MTYgIj3mWN6YM2fM~Mfj3yBQYtwd>SDSom5J>U@OfH| z8pliQ$VrEDEfCmD2P7&QvByIyk)*4X=*Xnf`qMSYbA>_%%EEgDy}PHk*EnFY+BP;4 zsFUE$;gX{BFTH@wBtwZoeUiA0P<22TM#j|cW3 z6~rQuR-?(z)E%p=`0aMjpci+40`&H>Y+5%BP_)|Iy0w{9HYfoLXb>`F!gx7wHT5d@zah z3H}#v42SZY-)#E$!}n1%vNN^R8Us6~U8E10jz$ym@u9rg+?7~R_C_!m^2W*tt`ll? z8ZiP0Ao4szqb5V}ch&ABeS*Ebfxyhn&d<&*EG=6hsnnVr5FS!`kaXtRIsAI2PWwp3 zVN@%jK!CWQQ(0bGQdEdFC|h$2i(?a0v8@ydEZzn%dTxG^%jKdf;RDo~93TX#Wy==p zJ>%f9qenFAw9~auLVNo92O}F1RIcjdkD<21m1WBcG;nxyoa`mot7-;AAzb93S{{!# zS)@clA-+*kdQEs-GR6xrCYxK z?&j^DEpgw%es7{sBgh7>W4J?Y-C*JY=Ats7h$7-3AM|(UwT6OW{swx%QmP8|8hro& N002ovPDHLkV1hV3r_cZZ literal 0 HcmV?d00001 diff --git a/repo/js/ArtifactsAssistant/assets/16.png b/repo/js/ArtifactsAssistant/assets/16.png new file mode 100644 index 0000000000000000000000000000000000000000..2bf6087cf0552a126b7999ab499194ddb68ef752 GIT binary patch literal 1391 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 XLIy0ibqP7U00000NkvXXu0mjf*bt|_ literal 0 HcmV?d00001 diff --git a/repo/js/ArtifactsAssistant/assets/2.png b/repo/js/ArtifactsAssistant/assets/2.png new file mode 100644 index 0000000000000000000000000000000000000000..8b7adcb1d03e56865ecff841ce90e65e2ccfe383 GIT binary patch literal 980 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 literal 0 HcmV?d00001 diff --git a/repo/js/ArtifactsAssistant/assets/4.png b/repo/js/ArtifactsAssistant/assets/4.png new file mode 100644 index 0000000000000000000000000000000000000000..bdf0740f858532463563852c6ee18e4decfd5f80 GIT binary patch literal 994 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 T7hYoY00000NkvXXu0mjfG@EKL literal 0 HcmV?d00001 diff --git a/repo/js/ArtifactsAssistant/assets/9.png b/repo/js/ArtifactsAssistant/assets/9.png new file mode 100644 index 0000000000000000000000000000000000000000..d43ddfc7f45b1bd957ecec42c901e7a00b37e393 GIT binary patch literal 1205 zcmV;m1WNmfP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1WHLnK~zXft(IGC zQ*|82*Ph<5+j{TXt?Ss0m0c>6p@C#9qA)WIqC7}6#+b;9J{XPqV3ZePd@#Nd6ZHWS zvWP*D7!sLI?80<1=(-Ew+@))~v94Y3YuB~)+x`z#+qF{dXD8`zzu*6y^ZWm9|HIhZ zcch|xFc}OUpC=ZH1biNg#bPiRi9{l{xfu$DL*ek&R)StvfO2}nX0tUaMQ3|kPq%r8 z(IAsmu_!7OjyRmlH*ecUe;uD&Sj4~d>g}NP#ui%qf3R3oOH;$kCypOKHefW=QWWL! zuKWD~iel+&H0BOdTWeF=GuLuFzD3`YM+x2_3lug>rQ@GUrD*K~bXv{xM+cth-G>$a zKyYZ-^4XW?E`RquUayqP74qups!Eko?sj|aOU~SzA5elfcpmm=sMQOFf=m(owM8bA zxo3CRv1j`Ed|on@8oO!z;_Tquf*rw_UtEgCV(q3@0iQ3GNH*hft8F?K+obROCrtYH zA;9}ifAG#nr`|pJ$_eCx)@Be0_%&K}RizYiEE-!}a-dd-2~})&xbDr)Lq<0BI!!}; z9Wmuof;S8%1BuEAX^4`54niLhc_SJPhQdT9gu`L)x{t_}QmI;{Byv6_cvFOAGKD`P z!%^aN7UT{QA~J`~=JB{h&Zn3+h`+u@YpB(cOChVSU@)NPaXA{5GOJgs6p3WQ=L;m0 zX@?LeS#=ec%gH<=4LYCC;}JRSc3uZ$VbQl6r)gp21zS%p-LufGtT7|iAYpmr)RTSh>cFGMyo3oa!kU*2M_FQ zZ6fzB+8x&|qxV*O@1 z2*#aI$d`yk2%$=)=;`iyyk~b~L%mcgA(=udZPRzJ{b}<2P{PU3|5V@GZ@h*g zxHU0#=JT_*sXMgcZy>E0yGRon2SGwB&CT2OI&J@x2VjM}gI`}hH+YdO&Zj&*m1W)M zANpzJ<4@1L`QEA5-+KSU)1Ta)n8FB#34xiNTNt-al9k(1W^ZypX3d=@)6QndsPSLM zZr!=}2Qh8SfAIz_TBJ*}pt;N)yL$IO#^Z8vM2w97_QUlNG6f1zf;YinXud^VGE{%;_qp=um`!~uT8)S;hO`nT6%!%e00000NkvXXu0mjfd)-F| literal 0 HcmV?d00001 diff --git a/repo/js/ArtifactsAssistant/assets/star.png b/repo/js/ArtifactsAssistant/assets/star.png new file mode 100644 index 0000000000000000000000000000000000000000..60184c4b6ed60fc88eb02eb0a213a1e6794d91a2 GIT binary patch literal 1064 zcmV+@1lRkCP)kd%00001b5ch_0Itp) z=>Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1HDN^K~zXfrBzFB zQ%4k@8DIN4KoUZDEud5aLl#)!B|+E_R%HodSAGCnx~1X=uwc=Os(^$L4+(^LBO%xz zAta!iB0*7GsR@pPVIo1b$EI8-1(oQ+0 zv{LG$ttV}?+rM{S6xowE8a$*TejQfBRd$r68$%zogpr2 z(KSGb&tS3hAuR3CTi2(co4UgGR=Sh8D4{+VzluAfjj(bKRTNJUnH&-zZ+o}o(h$UU zcW+*7dCmouOGEaN(iSykj=qS*N(&?@DYa~o?kVQUO;L9t+tI2lOYa>EvV3R+f7&s9 zukFR6C#7^aQ$O^C)90R0$~`;tI3kd*tS^@&P7S9rJ;hEh1&Vh-KiY*^w|i%Px|$!; zvd&Bp*it2tCeq|)BuNjxnNHoP zKkKt#c-3gS@~}F5=H0~PH^yt7JAS$LcR!HWjYhhcZC`z@j-0LG9#h3xQ{vpQOSQg1 z_BYClU%n{t^5%4PRQ+3?V+&K`t4G%|-s`vxPtRaQ_&Gco-9z-4hSQuqtL_KrTKd`?>#E3Bvl3n7Md zI!}GXaMIp72h*45l*y=Fadp-k%!b+*$ehEA_rXg3ynW6U0j5x? zw)vlll8{^vT)8`09(GY|l0=WZ)sLP=gToPK zBd!QK`2P1IuD&6lSP=?CdeL;5;jOSzZ|n;3>~24tICra28gkakeeY$l@zD)C?iLzIWUkr*i;87v6{UnN$ZzS%%aM=@PZg#hkDSrV%&Rrlb@M19;g inyyk6DH;itQ0_hc+qVxeP*sZn0000 4) throw new Error("副属性解析参数错误"); + for (let i = 0; i < 4; ++i) { + if (!attrs[i]) { + this.subAttr[i] = -1; + this.subValue[i] = 0; + continue; + } + let id = 0; + for (; id < targetKeywords.length; ++id) { + if (attrs[i].includes(targetKeywords[id])) break; + } + if (id >= targetKeywords.length) { + this.subAttr[i] = -1; + this.subValue[i] = 0; + continue; + } + if (id < 3 && !attrs[i].includes("%")) id += targetKeywords.length; + this.subAttr[i] = id; + if (!attrs[i].includes("待激活")) { + const strval = attrs[i].match(/\d*\.?\d+/); + if (!strval) throw new Error("副属性数值解析错误"); + this.subValue[i] = parseFloat(strval[0]); + } + else this.subValue[i] = 0; + } + } + get_mainAttr() {// 由于数值精度, 可能计算不准确 + if (this.main == -1) return null; + let start, end; + if (this.part == 0) {// 生之花 + start = (this.quality == 5 ? 717 : 645); + end = (this.quality == 5 ? 4780 : 4303); + return "生命值 " + Math.round(start + (end - start) / 20.0 * this.level); + } + if (this.part == 1) {// 死之羽 + start = (this.quality == 5 ? 47 : 42); + end = (this.quality == 5 ? 311 : 280); + return "攻击力 " + Math.round(start + (end - start) / 20.0 * this.level); + } + switch (this.main) { + case 0:// 生命百分比 + case 1:// 攻击百分比 + case 9:// 火元素伤害加成 + case 10:// 雷元素伤害加成 + case 11:// 水元素伤害加成 + case 12:// 草元素伤害加成 + case 13:// 风元素伤害加成 + case 14:// 岩元素伤害加成 + case 15:// 冰元素伤害加成 + start = (this.quality == 5 ? 7.0 : 6.3); + end = (this.quality == 5 ? 46.6 : 41.9); + break; + case 2:// 防御百分比 + case 8:// 物理伤害加成 + start = (this.quality == 5 ? 8.7 : 7.9); + end = (this.quality == 5 ? 58.3 : 52.4); + break; + case 3:// 元素精通 + start = (this.quality == 5 ? 28 : 25.2); + end = (this.quality == 5 ? 186.5 : 167.8); + break; + case 4:// 元素充能效率 + start = (this.quality == 5 ? 7.8 : 7.0); + end = (this.quality == 5 ? 51.8 : 46.6); + break; + case 5:// 暴击率 + start = (this.quality == 5 ? 4.7 : 4.2); + end = (this.quality == 5 ? 31.1 : 28.0); + break; + case 6:// 暴击伤害 + start = (this.quality == 5 ? 9.3 : 8.4); + end = (this.quality == 5 ? 62.2 : 55.9); + break; + case 7:// 治疗加成 + start = (this.quality == 5 ? 5.4 : 4.8); + end = (this.quality == 5 ? 35.9 : 32.3); + break; + default: + throw new Error("圣遗物主属性错误"); + } + const value = start + (end - start) / 20.0 * this.level; + if (this.main == 3) return "元素精通 " + Math.round(value); + return targetKeywords[this.main] + " " + value.toFixed(1) + "%"; + } + + make_point() { + // 计算所有副属性的点数 + for (let i = 0; i < 4; ++i) { + let point, id = this.subAttr[i]; + if (id == -1) { + this.subPoints[i] = 0; + continue; + } + switch (id) { + case (targetKeywords.length):// 生命值 + point = 29.8444;// * 2.2533; + break; + case (targetKeywords.length + 1):// 攻击力 + point = 1.9430;// * 2.4300; + break; + case (targetKeywords.length + 2):// 防御力 + point = 2.3316;// * 2.2468; + break; + case 3:// 元素精通 + point = 2.3316; + break; + case 0:// 生命百分比 + case 1:// 攻击百分比 + point = 0.5829; + break; + case 2:// 防御百分比 + point = 0.7286; + break; + case 4:// 元素充能效率 + point = 0.6477; + break; + case 5:// 暴击率 + point = 0.3886; + break; + case 6:// 暴击伤害 + point = 0.7772; + break; + default: + throw new Error("圣遗物副属性错误"); + } + if (this.quality != 5) point *= 0.8;// 若四星圣遗物则都乘以 0.8 + this.subPoints[i] = this.subValue[i] / point; + } + // 计算所有副属性的词条数(计算不可能完全准确因而总词条数可能比实际多一个) + let sum = 0, allcounts = Math.trunc(this.level / 4) + (this.quality - 1); + for (let i = 0; i < 4; ++i) { + let points = this.subPoints[i]; + if (points == 0) { + this.subCounts[i] = 0; + continue; + } + this.subCounts[i] = -1;// 缺省未知词条数 + if (points < 20.5) this.subCounts[i] = (points < 12 ? 1 : 2); + else if (points < 27.9) this.subCounts[i] = 3; + else if (this.quality == 5) { + if (points > 30.1 && points < 34.9) this.subCounts[i] = 4; + else if (points > 40.1 && points < 41.9) this.subCounts[i] = 5; + else if (points > 50.1) this.subCounts[i] = 6; + } + else if (points > 30.1) this.subCounts[i] = 4; + if (this.subCounts[i] != -1) sum += this.subCounts[i]; + else sum |= 128; + } + if (sum > 128) { + sum = allcounts - (sum - 128);// 未确定的词条数 + const id = this.subCounts.indexOf(-1); + if (this.quality == 5) {// 五星圣遗物需猜测词条数 + const nid = this.subCounts.indexOf(-1, id + 1); + if (nid == -1) {// 仅需处理一个未确定词条 + this.subCounts[id] = Math.min(sum, Math.trunc(this.subPoints[id] * 0.1434)); + } + else {// 需处理两个未确定词条 + this.subCounts[nid] = this.subCounts[id] = 3; + if (sum == 7) { + if (this.subPoints[id] >= this.subPoints[nid]) this.subCounts[id] = 4; + else this.subCounts[nid] = 4; + } + } + } + else {// 四星圣遗物基本可确定 + this.subCounts[id] = sum;//(sum < 4 || this.subPoints[id] < 29 ? 3 : 4); + } + } + } + + /* 获取副属性总点数 */ + getAttrPoints() { + //if (this.subPoints.length == 0) this.make_point(); + return this.subPoints[0] + this.subPoints[1] + this.subPoints[2] + this.subPoints[3]; + } + + /* 获取副属性总词条数(对于已强化的圣遗物可能不准确) */ + getAttrCounts() { + //if (this.subCounts.length == 0) this.make_point(); + return this.subCounts[0] + this.subCounts[1] + this.subCounts[2] + this.subCounts[3]; + } + + /* 判断是否为初始完全词条圣遗物(对于已强化的圣遗物可能不准确) */ + isDominant() { + //if (this.subPoints.length == 0) this.make_point(); + return this.getAttrCounts() >= Math.trunc(this.level / 4) + (this.quality - 1); + } + + /* 打印圣遗物信息 */ + print() { + if (!this.isDominant()) logout("==== 圣遗物 ===="); + else logout("==== 完全圣遗物 ===="); + logout(this.name + ":" + targetPartNames[this.part] + "," + + (this.quality == 5 ? "金" : "紫") + ",等级+" + this.level); + logout("总点数:" + this.getAttrPoints().toFixed(1) + "," + "主属性:" + this.get_mainAttr()); + for (let i = 0; i < 4; ++i) { + if (this.subAttr[i] == -1) continue; + const val = this.subValue[i]; + if (val == 0) continue; + let str, id = this.subAttr[i]; + if (id < targetKeywords.length) str = targetKeywords[id]; + else str = targetKeywords[id - targetKeywords.length]; + if (id == 3 || id >= targetKeywords.length) str = str + "+" + Math.round(val); + else str = str + "+" + val.toFixed(1) + "%"; + logout("副属性" + (i + 1) + ":+" + (this.subCounts[i] - 1) + "次," + str); + } + } +}; + +/************************ characters.js ************************/ + +// 词条名称简写 +const abbrevKeywords = [ + "生命", "攻击", "防御", "精通",// 0-3 + "充能", "暴击", "暴伤",// 4-6 + "治疗", "物伤", "火伤",// 7-9 + "雷伤", "水伤", "草伤",// 10-12 + "风伤", "岩伤", "冰伤" // 13-15 +]; + +// 单个角色的套装 +class Actor { + constructor(str) { + if (!str) return;// 支持无参构造 + const actorName = str.match(/^\d+\. *(.*)$/m);// 匹配角色名字 + const weaponRe = /^- 武器:(.*)$/m; + const relicsRe = /^- 圣遗物:(.*)$/m; + const mainAttrRe = /^- 圣遗物主词条:(.*)$/m; + const subAttrRe = /^- 圣遗物副词条:(.*)$/m; + let result, weapon, relics, mainAttr, subAttr, lvl = 0; + if ((/^.*;.*;.*$/m).test(str)) lvl = 2; + else if((/^.*;.*$/m).test(str)) lvl = 1; + /* 武器 */ + result = str.match(weaponRe); + if (!result || !result[1]) weapon = ["", "", ""]; + else { + weapon = result[1].split(";"); + for (let i = weapon.length; i <= lvl; ++i) weapon[i] = weapon[0]; + } + /* 圣遗物 */ + result = str.match(relicsRe); + if (!result || !result[1]) relics = ["", "", ""]; + else { + relics = result[1].split(";"); + for (let i = relics.length; i <= lvl; ++i) relics[i] = relics[0]; + } + /* 圣遗物主词条 */ + result = str.match(mainAttrRe); + if (!result || !result[1]) mainAttr = ["", "", ""]; + else { + mainAttr = result[1].split(";"); + for (let i = mainAttr.length; i <= lvl; ++i) mainAttr[i] = mainAttr[0]; + } + /* 圣遗物副词条 */ + result = str.match(subAttrRe); + if (!result || !result[1]) subAttr = ["", "", ""]; + else { + subAttr = result[1].split(";"); + for (let i = subAttr.length; i <= lvl; ++i) subAttr[i] = subAttr[0]; + } + // 子配置 + let pos = this, objects = [this]; + for (let i = 0; i < lvl; ++i) { + pos = pos.next = new Actor(); + objects[i + 1] = pos; + } + pos.next = null; + // 解析配置 + for (let id = 0; id <= lvl; ++id) { + objects[id].name = actorName[1];// 角色名字 + objects[id].weaponName = weapon[id].split("、");// 武器名称 + objects[id].relicsName = relics[id].split("、");// 圣遗物名称 + objects[id].mainAttr = [(1 << 0), (1 << 1)];// 主属性采取位标志存储 + objects[id].subAttr = [];// 副属性 index + const mainAttrName = mainAttr[id].split("、"); + for (let i = mainAttrName.length; i < 3; ++i) mainAttrName[i] = mainAttrName[0]; + for (let i = 2; i < 5; ++i) { + let val = 0, keywords = mainAttrName[i - 2].split("/"); + for (let j = 0; j < keywords.length; ++j) { + val |= (1 << abbrevKeywords.indexOf(keywords[j])); + } + objects[id].mainAttr[i] = val; + } + const keywords = subAttr[id].split("、"); + for (let i = 0; i < keywords.length; ++i) { + objects[id].subAttr[i] = abbrevKeywords.indexOf(keywords[i]); + } + } + } + + print(index) { + logout((index + ".").padEnd(3) + " " + this.name); + logout(""); + logout("- 武器:" + this.weaponName.join("、")); + logout("- 圣遗物:" + this.relicsName.join("、")); + const mainAttrName = []; + for (let i = 2; i < 5; ++i) { + const attrName = []; + for (let j = 0; j < abbrevKeywords.length; ++j) { + if ((1 << j) & this.mainAttr[i]) attrName.push(abbrevKeywords[j]); + } + mainAttrName.push(attrName.join("/")); + } + logout("- 圣遗物主词条:" + mainAttrName.join("、")); + const subAttrName = []; + for (let i = 0; i < this.subAttr.length; ++i) { + subAttrName.push(abbrevKeywords[this.subAttr[i]]); + } + logout("- 圣遗物副词条:" + subAttrName.join("、")); + logout(""); + if (this.next) this.next.print(index); + } + + /* 圣遗物是否适合当前角色, 返回适合的配置(Actor类型) */ + getSuitable(relics) { + do { + // 套装名称必须匹配 + if (this.relicsName[0] && !this.relicsName.includes(relics.name)) break; + // 主属性必须匹配 + if (!((1 << relics.main) & this.mainAttr[relics.part])) break; + // 计算是否包含有效词条 + const hasAttr = []; + for (let i = 0; i < this.subAttr.length; ++i) { + if (relics.part >= 2 && this.subAttr[i] == relics.main) continue; + hasAttr.push(relics.subAttr.indexOf(this.subAttr[i]) != -1); + } + // 若初始完全词条且含前两类 + const dominant = relics.isDominant(); + const hasFirst = (hasAttr[0] === void 0 || hasAttr[0]); + const hasSecond = (hasAttr[1] === void 0 || hasAttr[1]); + if (dominant && hasFirst && hasSecond) return this; + // 若有效词条类型多于三种(不占用主词条)或四种(占用主词条) + if (hasAttr.length > 3) { + const hasThird = (hasAttr[2] === void 0 || hasAttr[2]); + const hasFourth = (hasAttr[3] === void 0 || hasAttr[3]); + if (!dominant) {// 非初始完全词条 + if (!hasFirst || !hasSecond) break;// 前两类必须都有 + if (hasThird && hasFourth) return this;// 前四类都有 + if (!hasThird && !hasFourth) break;// 前四类缺少两类 + for (let i = 4; i < hasAttr.length; ++i) { + if (hasAttr[i]) return this;// 四有效 + } + } + else {// 初始完全词条 + if (!hasFirst && !hasSecond) break;// 前两类必须有一类 + if (hasThird && hasFourth) return this;// 前四类有三类 + if (!hasThird && !hasFourth) break;// 前四类缺少三类 + for (let i = 4; i < hasAttr.length; ++i) { + if (hasAttr[i]) return this;// 三有效 + } + } + } + } while(false); + if (!this.next) return null; + else return this.next.getSuitable(relics); + } + + /* 圣遗物是否可用于当前角色, 返回适合的配置(Actor类型) */ + getAffable(relics) { + do { + // 套装名称必须匹配 + if (this.relicsName[0] && !this.relicsName.includes(relics.name)) break; + // 主属性必须匹配 + if (!((1 << relics.main) & this.mainAttr[relics.part])) break; + // 计算是否包含有效词条 + const hasAttr = []; + for (let i = 0; i < this.subAttr.length; ++i) { + if (relics.part >= 2 && this.subAttr[i] == relics.main) continue; + hasAttr.push(relics.subAttr.indexOf(this.subAttr[i]) != -1); + } + // 若含前两类词条 + const hasFirst = (hasAttr[0] === void 0 || hasAttr[0]); + const hasSecond = (hasAttr[1] === void 0 || hasAttr[1]); + if (hasFirst && hasSecond) return this; + // 若有效词条类型多于三种(不占用主词条)或四种(占用主词条) + if (hasAttr.length > 3) { + const hasThird = (hasAttr[2] === void 0 || hasAttr[2]); + const hasFourth = (hasAttr[3] === void 0 || hasAttr[3]); + if (!hasFirst && !hasSecond) break;// 前两类必须有一类 + if (hasThird && hasFourth) return this;// 前四类有三类 + if (!hasThird && !hasFourth) break;// 前四类缺少三类 + for (let i = 4; i < hasAttr.length; ++i) { + if (hasAttr[i]) return this;// 三有效 + } + } + } while(false); + if (!this.next) return null; + else return this.next.getAffable(relics); + } + + /* 获取圣遗物于当前角色的适用分数 */ + getScore(relics) { + let ret = this.relicsName.indexOf(relics.name); + if (ret != -1) { + if (ret == 0) ret = 2;// 专属套装加两分 + else if (ret > 1) ret = 0;// 非专属套装不加分 + } + const indexAttr = []; + for (let i = 0; i < this.subAttr.length; ++i) {// 要排除与主属性相同的副词条 + if (relics.part >= 2 && this.subAttr[i] == relics.main) continue; + indexAttr.push(relics.subAttr.indexOf(this.subAttr[i])); + } + for (let i = 0; i < indexAttr.length; ++i) { + const id = indexAttr[i]; + if (id == -1) continue; + if (i < 2) ret += relics.subPoints[id]; + else if (i < 4) ret += relics.subPoints[id] * 0.8; + else ret += relics.subPoints[id] * 0.56; + if (relics.subAttr[id] < 3) {// 计算数值生命值、攻击力、防御力 + const nid = relics.subAttr.indexOf(this.subAttr[i] + targetKeywords.length); + if (nid == -1) continue; + // 统一将点数除以 2.37 以转为百分比属性点 + if (i < 2) ret += relics.subPoints[nid] * (1.0 * 27 / 64); + else if (i < 4) ret += relics.subPoints[nid] * (0.8 * 27 / 64); + else ret += relics.subPoints[nid] * (0.56 * 27 / 64); + } + } + this.score = ret; + return ret; + } +}; + +// 所有角色的套装 +class Characters { + constructor(str) { + this.actors = []; + const general = str.match(/1\. .*\n\n(?:- .*\n)+\n/g);// 默认模板 + let pos = this.actors[0] = new Actor(general[0]); + for (let i = 1; i < general.length; ++i) { + pos = pos.next = new Actor(general[i]); + } + const specials = str.match(/\d+\..*\n\n(?:- .*\n)+\n/g);// 特定角色 + for (let i = general.length; i < specials.length; ++i) { + this.actors.push(new Actor(specials[i])); + } + //enableLog = false; + //this.print();// 调试信息 + //logout("", "characters.txt"); + //enableLog = settings.enableLog; + } + + print() { + for (let i = 0; i < this.actors.length; ++i) this.actors[i].print(i + 1); + } + + /* 评价圣遗物 */ + evaluate(relics) { + let text, objects = [];// 首先查找毕业配置 + for (let i = 1; i < this.actors.length; ++i) {// 先跳过默认模板 + const obj = this.actors[i].getSuitable(relics); + if (obj != null) { + obj.getScore(relics); + objects.push(obj); + } + } + objects.sort((x, y) => y.score - x.score);// 评分降序排列 + let obj = this.actors[0].getSuitable(relics); + if (obj != null) { + obj.getScore(relics); + objects.push(obj);// 确保默认模板排在最後 + } + if (objects.length == 0) {// 尝试查找可用配置 + for (let i = 1; i < this.actors.length; ++i) {// 先跳过默认模板 + const obj = this.actors[i].getAffable(relics); + if (obj != null) { + obj.getScore(relics); + objects.push(obj); + } + } + objects.sort((x, y) => y.score - x.score);// 评分降序排列 + let obj = this.actors[0].getAffable(relics); + if (obj != null) { + obj.getScore(relics); + objects.push(obj);// 确保默认模板排在最後 + } + if (objects.length == 0) {// 没有角色需要此圣遗物 + logout("**这个圣遗物不堪大用啊**"); + return; + } + else text = "可用:"; + } + else text = "适配:"; + /* 打印前六名适配角色 */ + text = text + objects[0].name; + for (let i = 1; i < 6 && i < objects.length; ++i) { + text = text + "、" + objects[i].name; + } + logout(text); + /* 打印首个适配角色所需副词条和评分 */ + obj = objects[0]; + text = "词条点(" + obj.score.toFixed(1) + "):"; + for (let i = 0; i < obj.subAttr.length; ++i) { + let midstr = ""; + if (relics.subAttr.indexOf(obj.subAttr[i]) != -1) midstr = "*"; + text = text + midstr + abbrevKeywords[obj.subAttr[i]] + midstr + "、"; + } + logout(text.slice(0, -1)); + } +}; + +/************************ genshin.js ************************/ + +// 辅助函数:检查圣遗物品质(使用模板匹配) +function checkQuality(image, templateObj, x, y, w, h) { + const crop = image.DeriveCrop(x, y, w, h); + const matchResult = crop.Find(templateObj); + const ret = !matchResult.IsEmpty(); + matchResult.Dispose(); + crop.Dispose(); + return ret; +} + +// 辅助函数:检查圣遗物等级(使用模板匹配,因为OCR识别不准确) +function checkLevel(image, templateObjs, x, y, w, h) { + const crop = image.DeriveCrop(x, y, w, h); + let ret = 0; + let res = crop.Find(templateObjs[ret]); + if (res.IsEmpty()) {// 尝试两遍 + ret = 20; + let i = 0; + while (true) { + res.Dispose(); + res = crop.Find(templateObjs[ret]); + if (!res.IsEmpty()) break; + if (--ret < 0) { + if (++i >= 2) break; + ret = 20; + } + } + } + res.Dispose(); + crop.Dispose(); + return ret; +} + +// 辅助函数:读取指定区域的文本内容(使用OCR识别) +function readTextRegion(image, KeywordObj) { + const textResult = image.Find(KeywordObj); + const ret = textResult.Text; + textResult.Dispose(); + return ret; +} + +function autoZoom(x, y, w, h) { + /* 注意, BetterGI 截图强制转为 1080P, 这里不用缩放 */ + const ratio = 1;//genshin.scaleTo1080PRatio; + return [x * ratio, y * ratio, w * ratio, h * ratio]; +} + +function readImageAutoZoom(path, width, height) { + const ratio = 1;//genshin.scaleTo1080PRatio; + return file.ReadImageMatWithResizeSync(path, width * ratio, height * ratio); +} + +function readTemplate() { + const template = []; + for (let i = 0; i <= 20; ++i) { + template[i] = readImageAutoZoom("assets/" + i.toFixed(0) + ".png", 47, 21); + } + template[21] = readImageAutoZoom("assets/star.png", 28, 26); + return template; +} + +function freeTemplate(template) { + for (let i = 0; i <= 21; ++i) template[i].Dispose(); +} + +// 入口函数 +(async function () { + const characters = new Characters(file.readTextSync("角色一览.md")); + const template = readTemplate(); + const templateQualityObj = RecognitionObject.TemplateMatch(template[21]); + const templateLevelObj = []; + for (let i = 0; i <= 20; ++i) { + let tempObj = RecognitionObject.TemplateMatch(template[i]); + tempObj.Threshold = 0.91;// 至少 0.91 + //tempObj.InitTemplate();// 这个不需要 + templateLevelObj[i] = tempObj; + } + + const backpackPartNameObj = RecognitionObject.Ocr(...autoZoom(1320, 180, 90, 40)); + const backpackMainAttrObj = RecognitionObject.Ocr(...autoZoom(1320, 268, 180, 32)); + const backpackSuitNameObj = RecognitionObject.Ocr(...autoZoom(1320, 630, 240, 35)); + const backpackSubAttrObj1 = RecognitionObject.Ocr(...autoZoom(1352, 470, 368, 40)); + const backpackSubAttrObj2 = RecognitionObject.Ocr(...autoZoom(1352, 510, 368, 40)); + const backpackSubAttrObj3 = RecognitionObject.Ocr(...autoZoom(1352, 550, 368, 40)); + const backpackSubAttrObj4 = RecognitionObject.Ocr(...autoZoom(1352, 590, 368, 40)); + // 祝圣之霜定义的圣遗物, 坐标轴需下移 38px + const ebackpackSuitNameObj = RecognitionObject.Ocr(...autoZoom(1320, 630 + 38, 240, 35)); + const ebackpackSubAttrObj1 = RecognitionObject.Ocr(...autoZoom(1352, 470 + 38, 368, 40)); + const ebackpackSubAttrObj2 = RecognitionObject.Ocr(...autoZoom(1352, 510 + 38, 368, 40)); + const ebackpackSubAttrObj3 = RecognitionObject.Ocr(...autoZoom(1352, 550 + 38, 368, 40)); + const ebackpackSubAttrObj4 = RecognitionObject.Ocr(...autoZoom(1352, 590 + 38, 368, 40)); + + const characterSuitNameObj = RecognitionObject.Ocr(...autoZoom(1458, 486, 242, 32)); + const characterPartNameObj = RecognitionObject.Ocr(...autoZoom(1458, 172, 90, 30)); + const characterMainAttrObj = RecognitionObject.Ocr(...autoZoom(1466, 214, 214, 38)); + const characterSubAttrObj1 = RecognitionObject.Ocr(...autoZoom(1480, 352, 368, 27)); + const characterSubAttrObj2 = RecognitionObject.Ocr(...autoZoom(1480, 385, 368, 27)); + const characterSubAttrObj3 = RecognitionObject.Ocr(...autoZoom(1480, 419, 368, 27)); + const characterSubAttrObj4 = RecognitionObject.Ocr(...autoZoom(1480, 453, 368, 27)); + + while (true) { + // 每次分析耗时约 100ms, 等待约 200ms + await sleep(200); + // 捕获游戏区域图像 + const gameImage = captureGameRegion(); + if (gameImage.IsEmpty()) { + log.error("无法捕获游戏画面"); + break; + } + try { + // 尝试背包界面匹配主词条 + let mainResult = gameImage.Find(backpackMainAttrObj); + const relics = new Relics(); + if (!mainResult.IsEmpty()) { + relics.set_main(mainResult.Text); + if (relics.main != -1) { + // 背包界面属性识别 + let name, part, quality, level, attr1, attr2, attr3, attr4; + part = readTextRegion(gameImage, backpackPartNameObj); + if (checkQuality(gameImage, templateQualityObj, ...autoZoom(1468, 356, 32, 32))) + quality = 5; + else quality = 4; + level = checkLevel(gameImage, templateLevelObj, ...autoZoom(1338, 429, 55, 27)); + if (level != -1) { + name = readTextRegion(gameImage, backpackSuitNameObj); + attr1 = readTextRegion(gameImage, backpackSubAttrObj1); + attr2 = readTextRegion(gameImage, backpackSubAttrObj2); + attr3 = readTextRegion(gameImage, backpackSubAttrObj3); + attr4 = readTextRegion(gameImage, backpackSubAttrObj4); + } + else { + level = checkLevel(gameImage, templateLevelObj, ...autoZoom(1338, 429 + 38, 55, 27)); + name = readTextRegion(gameImage, ebackpackSuitNameObj); + attr1 = readTextRegion(gameImage, ebackpackSubAttrObj1); + attr2 = readTextRegion(gameImage, ebackpackSubAttrObj2); + attr3 = readTextRegion(gameImage, ebackpackSubAttrObj3); + attr4 = readTextRegion(gameImage, ebackpackSubAttrObj4); + } + relics.set_name(name); + relics.set_part(part); + relics.set_quality(quality); + relics.set_level(level); + relics.set_subAttr(attr1, attr2, attr3, attr4); + } + } else { + mainResult.Dispose(); + // 尝试角色界面匹配主词条 + mainResult = gameImage.Find(characterMainAttrObj); + if (!mainResult.IsEmpty()) { + relics.set_main(mainResult.Text); + if (relics.main != -1) { + // 角色界面属性识别 + relics.set_level(checkLevel(gameImage, templateLevelObj, ...autoZoom(1465, 310, 56, 28))); + relics.set_quality(checkQuality(gameImage, templateQualityObj, ...autoZoom(1596, 265, 32, 32)) ? 5 : 4); + relics.set_part(readTextRegion(gameImage, characterPartNameObj)); + relics.set_name(readTextRegion(gameImage, characterSuitNameObj)); + relics.set_subAttr( + readTextRegion(gameImage, characterSubAttrObj1), + readTextRegion(gameImage, characterSubAttrObj2), + readTextRegion(gameImage, characterSubAttrObj3), + readTextRegion(gameImage, characterSubAttrObj4) + ); + } + } + } + mainResult.Dispose(); + /* 分析结果 */ + if (relics.main != -1) { + relics.make_point();// 计算副属性点数 + relics.print();// 打印圣遗物信息 + characters.evaluate(relics);// 评价圣遗物 + logout("----------------", "overlay.txt"); + } + } catch (error) { + log.error(`处理失败: ${error.message}`); + } + finally { + gameImage.Dispose(); + } + } + freeTemplate(template); +})(); diff --git a/repo/js/ArtifactsAssistant/manifest.json b/repo/js/ArtifactsAssistant/manifest.json new file mode 100644 index 000000000..d0a67a6f9 --- /dev/null +++ b/repo/js/ArtifactsAssistant/manifest.json @@ -0,0 +1,21 @@ +{ + "manifest_version": 1, + "name": "圣遗物辅助", + "version": "1.0", + "bgi_version": "0.54.0", + "description": "自动分析圣遗物价值", + "authors": [ + { + "name": "756yang", + "link": "https://github.com/756yang" + } + ], + "settings_ui": "settings.json", + "main": "main.js", + "saved_files": [ + "assets/*.png", + "角色一览.md", + "README.md", + "overlay.exe" + ] +} \ No newline at end of file diff --git a/repo/js/ArtifactsAssistant/overlay.c b/repo/js/ArtifactsAssistant/overlay.c new file mode 100644 index 000000000..c4614ceb9 --- /dev/null +++ b/repo/js/ArtifactsAssistant/overlay.c @@ -0,0 +1,278 @@ +#include +#include +#include +#include +#include +#include + +// 编译命令:gcc overlay.c -fexec-charset=UTF-8 -mcmodel=small -static -O3 -DNDEBUG -s -flto=auto -Wl,--gc-sections,--as-needed -o overlay.exe -lgdi32 + +BOOL RunAsAdmin() { + wchar_t szPath[MAX_PATH]; + if (GetModuleFileNameW(NULL, szPath, ARRAYSIZE(szPath))) { + SHELLEXECUTEINFOW sei = { sizeof(SHELLEXECUTEINFOW) }; + sei.lpVerb = L"runas"; // 关键:请求提升权限 + sei.lpFile = szPath; + sei.hwnd = NULL; + sei.nShow = SW_NORMAL; + if (ShellExecuteExW(&sei)) { + ExitProcess(0); // 成功启动新实例后退出当前进程 + return TRUE; + } + } + return FALSE; +} + +// 检查当前是否管理员权限 +BOOL IsUserAdmin() { + BOOL isAdmin = FALSE; + PSID pAdminGroup = NULL; + // 创建管理员组的SID + SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; + if (AllocateAndInitializeSid(&NtAuthority, 2, + SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, &pAdminGroup)) { + // 检查令牌是否包含管理员组 + if (!CheckTokenMembership(NULL, pAdminGroup, &isAdmin)) isAdmin = FALSE; + FreeSid(pAdminGroup); + } + return isAdmin; +} + +BOOL PerformPrivilegedOperation() { + if (!IsUserAdmin()) { // 先检查当前权限 + if (RunAsAdmin()) { + return TRUE; // 已触发UAC提示,等待重启 + } else { + // 处理用户拒绝或错误 + MessageBoxW(NULL, L"需要管理员权限才能继续", L"权限错误", MB_ICONERROR); + return FALSE; + } + } + return TRUE; +} + + +char *utf16_to_utf8(const wchar_t *input) { + char *Buffer; + int BuffSize = 0, Result = 0; + BuffSize = WideCharToMultiByte(CP_UTF8, 0, input, -1, NULL, 0, NULL, NULL); + Buffer = (char*) malloc(sizeof(char) * BuffSize); + if(Buffer) { + Result = WideCharToMultiByte(CP_UTF8, 0, input, -1, Buffer, BuffSize, NULL, NULL); + if((Result > 0) && (Result <= BuffSize)) return Buffer; + free(Buffer); + } + return NULL; +} + +wchar_t *utf8_to_utf16(const char *input) { + wchar_t *Buffer; + int BuffSize = 0, Result = 0; + BuffSize = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0); + Buffer = (wchar_t*) malloc(sizeof(wchar_t) * BuffSize); + if(Buffer) { + Result = MultiByteToWideChar(CP_UTF8, 0, input, -1, Buffer, BuffSize); + if((Result > 0) && (Result <= BuffSize)) return Buffer; + free(Buffer); + } + return NULL; +} + +int utf8_printf(const char *format, ...) { + DWORD NUM; + int ret = -1; + HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); + va_list args; + va_start(args, format); + if(hOut == NULL || hOut == INVALID_HANDLE_VALUE || !GetConsoleMode(hOut, &NUM)) { + ret = vprintf(format, args); + va_end(args); + return ret; + } + char *buffer = (char*)malloc(16384); + if(buffer == NULL) return ret; + va_list args_copy; + va_copy(args_copy, args); + ret = vsnprintf(buffer, 16384, format, args); + va_end(args); + if(ret >= 16384) { + free(buffer); + buffer = (char*)malloc(++ret); + ret = vsnprintf(buffer, ret, format, args_copy); + } + va_end(args_copy); + if(ret < 0) { + free(buffer); + return ret; + } + wchar_t *buffer_utf16 = utf8_to_utf16(buffer); + free(buffer); + if(buffer_utf16 == NULL) return -1; + BOOL VAL = WriteConsoleW(hOut, buffer_utf16, (DWORD)wcslen(buffer_utf16), &NUM, NULL); + free(buffer_utf16); + if(!VAL) return -1; + return NUM; +} + +// 设置控制台字体 +BOOL SetConsoleFont(HANDLE hOutput, COORD fontSize, const wchar_t* fontName) { + CONSOLE_FONT_INFOEX cfi; + ZeroMemory(&cfi, sizeof(cfi)); + cfi.cbSize = sizeof(cfi); + cfi.dwFontSize = fontSize; + wcscpy_s(cfi.FaceName, LF_FACESIZE, fontName); + + // 设置字体样式 + cfi.FontWeight = FW_NORMAL; + cfi.FontFamily = FF_DONTCARE; + + return SetCurrentConsoleFontEx(hOutput, FALSE, &cfi); +} + +#define INTERVAL_MS 50 +#define DELIMITER "----------------" + +// 全局变量用于控制程序运行状态 +volatile BOOL g_bRunning = TRUE; +HANDLE g_hExitEvent = NULL; + +// 控制台事件处理函数 +BOOL WINAPI ConsoleHandler(DWORD dwCtrlType) { + switch (dwCtrlType) { + case CTRL_CLOSE_EVENT: + case CTRL_BREAK_EVENT: + case CTRL_SHUTDOWN_EVENT: + g_bRunning = FALSE; + if (g_hExitEvent) { + SetEvent(g_hExitEvent); + } + // 给主线程一点时间清理资源 + Sleep(50); + return TRUE; + default: + return FALSE; + } +} + +// 获取当前 exe 所在目录的路径 +char* get_exe_dir() { + static char path[MAX_PATH]; + GetModuleFileName(NULL, path, MAX_PATH); + // 去除文件名,只保留目录部分 + char* last_slash = strrchr(path, '\\'); + if (last_slash) { + *(last_slash + 1) = '\0'; + } + return path; +} + +// 读取整个文件内容,调用者需负责释放返回的字符串 +char* read_file(const char* filepath) { + FILE* file = fopen(filepath, "rb"); + if (!file) { + return NULL; + } + fseek(file, 0, SEEK_END); + long size = ftell(file); + fseek(file, 0, SEEK_SET); + char* content = (char*)malloc(size + 1); + if (content) { + fread(content, 1, size, file); + content[size] = '\0'; + } + fclose(file); + return content; +} + +// 检查字符串是否以指定的分隔符结尾 +int ends_with(const char* str, const char* suffix) { + if (!str || !suffix) return 0; + size_t len_str = strlen(str); + size_t len_suffix = strlen(suffix); + if (len_suffix > len_str) return 0; + return strncmp(str + len_str - len_suffix, suffix, len_suffix) == 0; +} + +int main() { + if(!PerformPrivilegedOperation()) return 1;// 以管理员模式启动 + if(!SetProcessDPIAware()) return 1;// 设置DPI感知 + // 设置窗口位置和大小 (x, y, width, height) + // 设置字体为宋体, 高度 25px + COORD fontSize = {0, 20}; + HDC hdc = GetDC(NULL); + if (!hdc) return 1; + fontSize.Y = fontSize.Y * 96.0 / GetDeviceCaps(hdc, LOGPIXELSY); + int posX = 1320 * GetDeviceCaps(hdc, DESKTOPHORZRES) / 1920;// 桌面水平分辨率 + int posY = 680 * GetDeviceCaps(hdc, DESKTOPVERTRES) / 1080;// 桌面垂直分辨率 + ReleaseDC(NULL, hdc); + DWORD console_mode; + HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); + if (hOut == NULL || hOut == INVALID_HANDLE_VALUE) return 1; + // 设置控制台字体大小 + if(!SetConsoleFont(hOut, fontSize, L"SimHei")) SetConsoleFont(hOut, fontSize, L"SimSun"); + if (!GetConsoleMode(hOut, &console_mode)) return 1; + // 设置控制台启用虚拟终端模式 + SetConsoleMode(hOut, console_mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING); + // 获取控制台窗口句柄 + HWND hwnd = GetConsoleWindow(); + SetWindowPos(hwnd, HWND_TOPMOST, posX, posY, 600, 300, SWP_SHOWWINDOW); + + // 创建退出事件对象 + g_hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!g_hExitEvent) { + return 2; + } + + // 注册控制台事件处理程序 + if (!SetConsoleCtrlHandler(ConsoleHandler, TRUE)) { + CloseHandle(g_hExitEvent); + return 3; + } + + // 1. 获取 overlay.txt 的绝对路径 + char filepath[MAX_PATH]; + snprintf(filepath, sizeof(filepath), "%soverlay.txt", get_exe_dir()); + + char* last_content = NULL; // 保存上一次以分隔符结尾的内容 + char* current_content = NULL; + + while (g_bRunning) { + // 2. 读取文件 + current_content = read_file(filepath); + if (current_content != NULL) { + // 3. 检查是否以分隔符结尾 + if (ends_with(current_content, DELIMITER)) { + // 4. 与上一次内容比较 + if (last_content == NULL || strcmp(current_content, last_content) != 0) { + // 5. 若不同,则输出 + char* last_break = strrchr(current_content, '\n'); + if (last_break) *last_break = '\0'; + utf8_printf("\033[2J\033[H%s\n", current_content);// 清屏并输出 + if (last_break) *last_break = '\n'; + // 更新 last_content + if (last_content) { + free(last_content); + } + last_content = current_content; + } else { + free(current_content); + } + } else { + free(current_content); + } + } + // 6. 睡眠 50ms,但可被退出事件唤醒 + WaitForSingleObject(g_hExitEvent, INTERVAL_MS); + } + + // 清理资源 + if (last_content) { + free(last_content); + } + if (g_hExitEvent) { + CloseHandle(g_hExitEvent); + } + + return 0; +} diff --git a/repo/js/ArtifactsAssistant/overlay.exe b/repo/js/ArtifactsAssistant/overlay.exe new file mode 100644 index 0000000000000000000000000000000000000000..10c7145e7454e396d4674a0366b12de657070c79 GIT binary patch literal 45568 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