diff --git "a/NIKKE/NIKKE\346\227\245\345\270\270.js" "b/NIKKE/NIKKE\346\227\245\345\270\270.js"
index bf8a062..087a12f 100644
--- "a/NIKKE/NIKKE\346\227\245\345\270\270.js"
+++ "b/NIKKE/NIKKE\346\227\245\345\270\270.js"
@@ -1,11 +1,13 @@
var {
启动NIKKE, 等待NIKKE加载, 退出NIKKE,
- mostSimilar, 返回首页, 关闭限时礼包
+ mostSimilar, 返回首页, 关闭限时礼包,
+ detectNikkes
} = require('./NIKKEutils.js');
var { 模拟室 } = require('./模拟室.js');
var {
ocrUntilFound, clickRect, findImageByFeature,
- requestScreenCaptureAuto, getDisplaySize
+ requestScreenCaptureAuto, getDisplaySize,
+ findContoursRect
} = require('./utils.js');
let width, height;
let NIKKEstorage = storages.create("NIKKEconfig");
@@ -40,7 +42,8 @@ function 日常() {
竞技场: 竞技场,
爬塔: 爬塔,
咨询: 咨询,
- 模拟室: () => 模拟室(true)
+ 模拟室: () => 模拟室(true),
+ 每日任务: 每日任务
};
let alreadyRetry = 0;
const maxRetry = NIKKEstorage.get('maxRetry', 1);
@@ -97,7 +100,7 @@ function 商店() {
clickRect(ocrUntilFound(res => res.find(e => e.text == '购买'), 30, 1000));
let affordable = true;
ocrUntilFound(res => {
- if (res.text.includes('不足')) {
+ if (res.find(e => e.text.match(/不足.?$/) != null)) {
affordable = false;
return true;
}
@@ -786,4 +789,136 @@ function 单次咨询(advise) {
}
toast('回到咨询首页');
return true;
-}
\ No newline at end of file
+}
+
+function listEquip() {
+ let [equip, leftBound, lowerBound] = ocrUntilFound(res => {
+ let e = res.find(e => e.text == 'EQUIP');
+ let le = res.find(e => e.text.match(/(装备|技能|魔方)/) != null);
+ let lo = res.find(e => e.text.match(/(快捷|全部)/) != null);
+ if (!e || !le || !lo)
+ return null;
+ return [e.bounds.bottom, le.bounds.right, lo.bounds.top];
+ }, 30, 300);
+ let ret = [];
+ let equipHeight = lowerBound - equip;
+ for (let i = 0; i < 10; ++i) {
+ ret = findContoursRect(captureScreen(), {
+ thresh: 160,
+ region: [leftBound, equip, width - leftBound, equipHeight]
+ }).filter(rect => {
+ if (rect.height() < equipHeight / 4 || rect.height() > equipHeight / 2)
+ return false;
+ if (rect.width() < equipHeight / 4 || rect.width() > equipHeight / 2)
+ return false;
+ return true;
+ });
+ if (ret.length == 4)
+ break;
+ }
+ return ret;
+}
+
+function 强化装备() {
+ let dailyMission = NIKKEstorage.get('dailyMission', {});
+ let targetEquip = dailyMission.equipEnhanceSlot || 0;
+ let targetNikke = dailyMission.equipEnhanceNikke || '';
+ if (targetNikke == '') {
+ toastLog('未指定强化装备妮姬');
+ return;
+ }
+ let targetNikkeReg = new RegExp(targetNikke);
+ let target = null;
+ clickRect(ocrUntilFound(res => res.find(e => e.text == '妮姬'), 40, 1000));
+ let upperBound = ocrUntilFound(res => {
+ let upper = res.find(e => e.text == 'ALL');
+ if (!upper)
+ return null;
+ return upper.bounds.bottom;
+ }, 30, 600);
+ // 找到指定妮姬
+ for (let retry = 0; target == null && retry < 3; ++retry) {
+ if (retry > 0)
+ for (let i = 0; i < 7; ++i)
+ swipe(width / 2, (upperBound + height) / 2, width / 2, height, 300);
+ sleep(1000);
+ let lastNikke = null;
+ for (let page = 0; page < 10; ++page) {
+ let nikkes = detectNikkes(captureScreen(), [0, upperBound]);
+ if (nikkes[nikkes.length - 1].name == lastNikke)
+ break;
+ lastNikke = nikkes[nikkes.length - 1].name;
+ let bottomY = nikkes[nikkes.length - 1].bounds.bottom;
+ let t = mostSimilar(targetNikke, nikkes.map(x => x.name));
+ if (t.similarity > 0.5) {
+ target = nikkes.find(e => e.name == t.result);
+ break;
+ }
+ t = nikkes.find(x => targetNikkeReg.test(x.name));
+ if (t != null) {
+ target = t;
+ break;
+ }
+ swipe(width / 2, bottomY, width / 2, upperBound, 1000);
+ swipe(100, bottomY, width / 2, bottomY, 500);
+ sleep(500);
+ }
+ }
+ if (target == null) {
+ console.error(`没有找到名为“${targetNikke}”的妮姬`);
+ clickRect(ocrUntilFound(res => res.find(e => e.text == '大厅'), 30, 1000));
+ return;
+ }
+ clickRect(target, 0.01);
+ ocrUntilFound(res => res.text.match(/(STATUS|体力|攻击|返回)/), 30, 1000);
+ // 点击指定装备
+ clickRect({ bounds: listEquip()[targetEquip] });
+ ocrUntilFound(res => res.find(e => e.text.match(/^(升级|穿戴|交换|改造)/) == null), 20, 1000);
+ // 检查是否可以升级
+ let enhanceBtn = ocrUntilFound(res => res.find(e => e.text.match(/^升级$/) != null), 3, 1000);
+ if (enhanceBtn == null) {
+ toastLog('指定装备不可升级');
+ back();
+ 返回首页();
+ return;
+ }
+ // 检查升级材料
+ clickRect(enhanceBtn);
+ let [enhanceConfirm, equipUpperBound] = ocrUntilFound(res => {
+ if (!res.text.includes('自动'))
+ return null;
+ let confirm = res.find(e => e.text == '升级');
+ let upper = res.find(e => e.text.match(/(择升|级别|等级)/) != null);
+ if (!confirm || !upper)
+ return null;
+ return [confirm, upper.bounds.bottom];
+ }, 30, 1000);
+ let enhanceStuff = findContoursRect(captureScreen(), {
+ thresh: 170,
+ region: [0, equipUpperBound, width, enhanceConfirm.bounds.top - equipUpperBound]
+ }).filter(x => {
+ if (x.width() < 100)
+ return false;
+ if (Math.abs(x.width() - x.height()) > 20)
+ return false;
+ return true;
+ });
+ if (enhanceStuff.length == 0) {
+ toastLog('没有强化材料');
+ } else {
+ clickRect({ bounds: enhanceStuff[0] });
+ clickRect(enhanceConfirm);
+ sleep(1000);
+ while (colors.blue(captureScreen().pixel(
+ enhanceConfirm.bounds.left,
+ enhanceConfirm.bounds.top
+ )) > 220)
+ sleep(300);
+ }
+ back();
+ 返回首页();
+}
+
+function 每日任务() {
+ 强化装备();
+}
diff --git "a/NIKKE/NIKKE\350\256\276\347\275\256.js" "b/NIKKE/NIKKE\350\256\276\347\275\256.js"
index 770a9f4..b216521 100644
--- "a/NIKKE/NIKKE\350\256\276\347\275\256.js"
+++ "b/NIKKE/NIKKE\350\256\276\347\275\256.js"
@@ -114,78 +114,64 @@ ui.layout(
刷buff时只考虑以下增益效果:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 每日任务设置
+
+ 强化装备指定妮姬:
+
+
+
+ 强化装备部位:头
+
+
+
其他设置
@@ -255,7 +241,7 @@ function checkUpdate() {
const NIKKEstorage = storages.create("NIKKEconfig");
const todoTaskDefault = [
"商店", "基地收菜", "好友", "竞技场",
- "爬塔", "咨询", "模拟室"
+ "爬塔", "咨询", "模拟室", "每日任务"
];
const simulationRoomDefault = {
maxPass: 20,
@@ -283,6 +269,9 @@ ui.findView('竞技场').on('check', function (checked) {
ui.findView('模拟室').on('check', function (checked) {
ui.simulationRoom.attr('visibility', checked ? 'visible' : 'gone');
});
+ui.findView('每日任务').on('check', function (checked) {
+ ui.dailyMission.attr('visibility', checked ? 'visible' : 'gone');
+});
ui.buyCodeManual.setMin(0);
ui.buyCodeManual.setMax(4);
@@ -366,6 +355,17 @@ for (let task of todoTask)
for (let buffName of simulationRoom.preferredBuff)
ui.findView(buffName).setChecked(true);
+ui.equipEnhanceSlot.setMin(0);
+ui.equipEnhanceSlot.setMax(3);
+ui.equipEnhanceSlot.setOnSeekBarChangeListener({
+ onProgressChanged: function (seekbar, p, fromUser) {
+ ui.equipEnhanceSlotText.setText(`强化装备部位:${'头身手腿'[p]}`);
+ }
+});
+let dailyMission = NIKKEstorage.get('dailyMission', {});
+ui.equipEnhanceNikke.setText(dailyMission.equipEnhanceNikke || '');
+ui.equipEnhanceSlot.setProgress(dailyMission.equipEnhanceSlot || 0);
+
for (let generalOption of [
'mute', 'alreadyInGame', 'checkUpdateAuto',
'checkSale', 'exitGame', 'checkDailyLogin', 'v2rayNG'
@@ -414,10 +414,14 @@ ui.save.on("click", function () {
toast('模拟室编队格式有误,无法保存');
return;
}
+ if (ui.findView('每日任务').isChecked() && ui.equipEnhanceNikke.text().trim() == '') {
+ toast('强化装备指定妮姬不可留空,无法保存');
+ return;
+ }
let todoTask = [];
for (let task of [
- "基地收菜", "好友", "竞技场",
- "商店", "爬塔", "咨询", "模拟室"
+ "基地收菜", "好友", "竞技场", "商店",
+ "爬塔", "咨询", "模拟室", "每日任务"
])
if (ui.findView(task).isChecked())
todoTask.push(task);
@@ -440,6 +444,11 @@ ui.save.on("click", function () {
simulationRoom.preferredBuff.push(buffName);
NIKKEstorage.put('simulationRoom', JSON.stringify(simulationRoom));
+ let dailyMission = {};
+ dailyMission.equipEnhanceNikke = ui.equipEnhanceNikke.text().trim();
+ dailyMission.equipEnhanceSlot = ui.equipEnhanceSlot.getProgress();
+ NIKKEstorage.put('dailyMission', dailyMission);
+
for (let generalOption of [
'mute', 'alreadyInGame', 'checkUpdateAuto',
'checkSale', 'exitGame', 'checkDailyLogin', 'v2rayNG'
diff --git a/utils.js b/utils.js
index 52c166a..759ba7c 100644
--- a/utils.js
+++ b/utils.js
@@ -13,6 +13,7 @@ else {
getDisplaySize: getDisplaySize,
killApp: killApp,
buildRegion: buildRegion,
+ findContoursRect: findContoursRect,
findImageByFeature: findImageByFeature
};
}
@@ -255,6 +256,56 @@ function findImageByFeature(trainImg, queryImg, options) {
}
}
+function findContoursRect(img, options) {
+ options = options || {};
+ let thresh = options.thresh || 160;
+ let [x, y, w, h] = buildRegion(options.region, img);
+ let clipImg = images.clip(img, x, y, w, h);
+ let grayImg = images.cvtColor(clipImg, "BGR2GRAY");
+ let threImg = images.threshold(grayImg, thresh, 255, "BINARY_INV");
+ let ret = [];
+ with (JavaImporter(
+ org.opencv.imgproc.Imgproc,
+ com.stardust.autojs.core.opencv,
+ org.opencv.core.Core,
+ org.opencv.core.Point,
+ org.opencv.core.MatOfPoint2f,
+ org.opencv.core.Scalar,
+ com.stardust.autojs.core.opencv.Mat
+ )) {
+ let threImgMat = threImg.getMat();
+ let contours = java.lang.reflect.Array.newInstance(MatOfPoint, 0);
+ contours = java.util.ArrayList(java.util.Arrays.asList(contours));
+ Imgproc.findContours(threImgMat, contours, Mat(), Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);
+ for (let i = 0; i < contours.size(); ++i) {
+ let contour2f = MatOfPoint2f(contours.get(i).toArray());
+ let epsilon = Imgproc.arcLength(contour2f, true) * 0.1;
+ let approxCurve = MatOfPoint2f();
+ Imgproc.approxPolyDP(contour2f, approxCurve, epsilon, true);
+ let pts = MatOfPoint(approxCurve.toArray());
+ let rect = Imgproc.boundingRect(pts);
+ ret.push(android.graphics.Rect(
+ rect.x + x,
+ rect.y + y,
+ rect.x + rect.width + x,
+ rect.y + rect.height + y
+ ));
+ // Imgproc.rectangle(threImgMat, Point(rect.x, rect.y), Point(rect.x + rect.width, rect.y + rect.height), Scalar(150), 3);
+ }
+ // images.save(images.matToImage(threImgMat), `./images/nikkerror/${Date.now()}.jpg`);
+ }
+ threImg.recycle();
+ grayImg.recycle();
+ clipImg.recycle();
+ ret.sort((a, b) => {
+ let t = a.top - b.top;
+ if (Math.abs(t) < 20)
+ return a.left - b.left;
+ return t;
+ });
+ return ret;
+}
+
function killApp(packageName) {
var name = getPackageName(packageName);
if (!name) {