diff --git a/repo/js/OCR购买食材/assets/F_Dialogue.png b/repo/js/OCR购买食材/assets/F_Dialogue.png new file mode 100644 index 00000000..43f45e74 Binary files /dev/null and b/repo/js/OCR购买食材/assets/F_Dialogue.png differ diff --git a/repo/js/OCR购买食材/assets/枫丹咖啡厅露泽店主阿鲁埃.json b/repo/js/OCR购买食材/assets/枫丹咖啡厅露泽店主阿鲁埃.json new file mode 100644 index 00000000..aae0ecfa --- /dev/null +++ b/repo/js/OCR购买食材/assets/枫丹咖啡厅露泽店主阿鲁埃.json @@ -0,0 +1,58 @@ +{ + "info": { + "name": "枫丹咖啡厅露泽店主阿鲁埃", + "type": "collect", + "author": "吉吉喵", + "version": "1.0", + "description": "咖啡豆", + "bgiVersion": "0.42.3" + }, + "positions": [ + { + "id": 1, + "x": 4649.4873046875, + "y": 3467.8935546875, + "action": "", + "move_mode": "walk", + "action_params": "", + "type": "teleport" + }, + { + "id": 2, + "x": 4627.564453125, + "y": 3470.357421875, + "action": "", + "move_mode": "walk", + "action_params": "", + "type": "path" + }, + { + "id": 3, + "x": 4604.40869140625, + "y": 3510.25, + "action": "stop_flying", + "move_mode": "fly", + "action_params": "", + "type": "path" + }, + { + "id": 4, + "x": 4600.888671875, + "y": 3514.0810546875, + "action": "", + "move_mode": "walk", + "action_params": "", + "type": "target", + "locked": false + }, + { + "id": 5, + "x": 4599.888671875, + "y": 3516.081054687501, + "action": "", + "move_mode": "walk", + "action_params": "", + "type": "orientation" + } + ] +} \ No newline at end of file diff --git a/repo/js/OCR购买食材/assets/枫丹达莫维百货店主布希柯.json b/repo/js/OCR购买食材/assets/枫丹达莫维百货店主布希柯.json new file mode 100644 index 00000000..cd6741b9 --- /dev/null +++ b/repo/js/OCR购买食材/assets/枫丹达莫维百货店主布希柯.json @@ -0,0 +1,40 @@ +{ + "info": { + "name": "枫丹达莫维百货店主布希柯", + "type": "collect", + "author": "吉吉喵", + "version": "1.0", + "description": "杂货", + "bgiVersion": "0.35.1" + }, + "positions": [ + { + "id": 1, + "action": "", + "move_mode": "walk", + "type": "teleport", + "x": 4514.18, + "y": 3630.4, + "action_params": "", + "locked": false + }, + { + "id": 2, + "x": 4514.2802734375, + "y": 3604.35498046875, + "type": "path", + "move_mode": "fly", + "action": "stop_flying", + "action_params": "" + }, + { + "id": 3, + "x": 4470.1357421875, + "y": 3562.072265625, + "type": "path", + "move_mode": "fly", + "action": "", + "action_params": "" + } + ] +} \ No newline at end of file diff --git a/repo/js/OCR购买食材/assets/璃月万民堂老板卯师傅-2.json b/repo/js/OCR购买食材/assets/璃月万民堂老板卯师傅-2.json new file mode 100644 index 00000000..3ce54c61 --- /dev/null +++ b/repo/js/OCR购买食材/assets/璃月万民堂老板卯师傅-2.json @@ -0,0 +1,55 @@ +{ + "info": { + "name": "璃月万民堂老板卯师傅", + "type": "collect", + "author": "吉吉喵", + "version": "", + "description": "璃月万民堂老板卯师傅备选", + "bgiVersion": "0.42.3" + }, + "positions": [ + { + "id": 1, + "x": 267.9150390625, + "y": -665.1591796875, + "action": "", + "move_mode": "walk", + "type": "teleport", + "locked": false + }, + { + "id": 2, + "x": 232.9345703125, + "y": -663.775390625, + "action": "", + "move_mode": "walk", + "type": "path" + }, + { + "id": 3, + "x": 231.1435546875, + "y": -671.79248046875, + "action": "", + "move_mode": "walk", + "type": "target", + "locked": false + }, + { + "id": 4, + "x": 226.2607421875, + "y": -672.33740234375, + "action": "", + "move_mode": "walk", + "type": "target", + "locked": false + }, + { + "id": 5, + "x": 227.591796875, + "y": -671.0654296875, + "action": "", + "move_mode": "walk", + "type": "target" + } + ] +} \ No newline at end of file diff --git a/repo/js/OCR购买食材/assets/璃月万民堂老板卯师傅.json b/repo/js/OCR购买食材/assets/璃月万民堂老板卯师傅.json index 3ce54c61..f6b997e3 100644 --- a/repo/js/OCR购买食材/assets/璃月万民堂老板卯师傅.json +++ b/repo/js/OCR购买食材/assets/璃月万民堂老板卯师傅.json @@ -4,7 +4,7 @@ "type": "collect", "author": "吉吉喵", "version": "", - "description": "璃月万民堂老板卯师傅备选", + "description": "鱼肉+螃蟹", "bgiVersion": "0.42.3" }, "positions": [ @@ -19,34 +19,16 @@ }, { "id": 2, - "x": 232.9345703125, - "y": -663.775390625, + "x": 228.953125, + "y": -663.4853515625, "action": "", "move_mode": "walk", "type": "path" }, { "id": 3, - "x": 231.1435546875, - "y": -671.79248046875, - "action": "", - "move_mode": "walk", - "type": "target", - "locked": false - }, - { - "id": 4, - "x": 226.2607421875, - "y": -672.33740234375, - "action": "", - "move_mode": "walk", - "type": "target", - "locked": false - }, - { - "id": 5, - "x": 227.591796875, - "y": -671.0654296875, + "x": 227.083984375, + "y": -668.10791015625, "action": "", "move_mode": "walk", "type": "target" diff --git a/repo/js/OCR购买食材/assets/璃月荣发商铺店主东升.json b/repo/js/OCR购买食材/assets/璃月荣发商铺店主东升.json new file mode 100644 index 00000000..b41d4eff --- /dev/null +++ b/repo/js/OCR购买食材/assets/璃月荣发商铺店主东升.json @@ -0,0 +1,28 @@ +{ + "info": { + "name": "璃月荣发商铺店主东升", + "type": "collect", + "author": "吉吉喵", + "version": "1.0", + "description": "杂货", + "bgiVersion": "0.42.0" + }, + "positions": [ + { + "id": 1, + "action": "force_tp", + "move_mode": "walk", + "type": "teleport", + "x": 267.92, + "y": -665.01 + }, + { + "id": 2, + "x": 256.9208984375, + "y": -682.560546875, + "type": "path", + "move_mode": "walk", + "action": "" + } + ] +} \ No newline at end of file diff --git a/repo/js/OCR购买食材/assets/稻妻九十九物店主葵.json b/repo/js/OCR购买食材/assets/稻妻九十九物店主葵.json index 5296e0f7..8661478e 100644 --- a/repo/js/OCR购买食材/assets/稻妻九十九物店主葵.json +++ b/repo/js/OCR购买食材/assets/稻妻九十九物店主葵.json @@ -4,7 +4,7 @@ "type": "collect", "author": "吉吉喵", "version": "1.0", - "description": "购买杂货", + "description": "杂货", "bgiVersion": "0.42.0" }, "positions": [ diff --git a/repo/js/OCR购买食材/assets/稻妻志村屋店主志村勘兵卫.json b/repo/js/OCR购买食材/assets/稻妻志村屋店主志村勘兵卫.json index cb9a9350..3a5e036b 100644 --- a/repo/js/OCR购买食材/assets/稻妻志村屋店主志村勘兵卫.json +++ b/repo/js/OCR购买食材/assets/稻妻志村屋店主志村勘兵卫.json @@ -4,7 +4,7 @@ "type": "collect", "author": "吉吉喵", "version": "1.0", - "description": "购买鱼肉+螃蟹", + "description": "鱼肉+螃蟹", "bgiVersion": "0.42.0" }, "positions": [ diff --git a/repo/js/OCR购买食材/assets/蒙德百货销售员布兰琪.json b/repo/js/OCR购买食材/assets/蒙德百货销售员布兰琪.json new file mode 100644 index 00000000..6d839404 --- /dev/null +++ b/repo/js/OCR购买食材/assets/蒙德百货销售员布兰琪.json @@ -0,0 +1,36 @@ +{ + "info": { + "name": "蒙德百货销售员布兰琪", + "type": "collect", + "author": "吉吉喵", + "version": "1.0", + "description": "杂货", + "bgiVersion": "0.42.3" + }, + "positions": [ + { + "id": 1, + "x": -867.693359375, + "y": 2281.393310546875, + "action": "", + "move_mode": "walk", + "type": "teleport" + }, + { + "id": 2, + "x": -886.5966796875, + "y": 2259.00244140625, + "action": "", + "move_mode": "walk", + "type": "path" + }, + { + "id": 3, + "x": -894.9638671875, + "y": 2264.875244140625, + "action": "", + "move_mode": "walk", + "type": "target" + } + ] +} \ No newline at end of file diff --git a/repo/js/OCR购买食材/assets/须弥奥摩斯港鱼贩布特罗斯.json b/repo/js/OCR购买食材/assets/须弥奥摩斯港鱼贩布特罗斯.json index 603c07a1..57421f74 100644 --- a/repo/js/OCR购买食材/assets/须弥奥摩斯港鱼贩布特罗斯.json +++ b/repo/js/OCR购买食材/assets/须弥奥摩斯港鱼贩布特罗斯.json @@ -4,7 +4,7 @@ "type": "collect", "author": "吉吉喵", "version": "", - "description": "须弥奥摩斯港鱼贩布特罗斯", + "description": "鱼肉+螃蟹", "bgiVersion": "0.42.3" }, "positions": [ diff --git a/repo/js/OCR购买食材/main.js b/repo/js/OCR购买食材/main.js index 509ec968..c5075c89 100644 --- a/repo/js/OCR购买食材/main.js +++ b/repo/js/OCR购买食材/main.js @@ -1,23 +1,23 @@ // 定义所有食材及其对应的路径文件和 NPC -const mondstadtGroceryFilePath = `assets/蒙德杂货商布兰琪.json`; -const liyueGroceryFilePath = `assets/璃月杂货商东升.json`; +const mondstadtGroceryFilePath = `assets/蒙德百货销售员布兰琪.json`; +const liyueGroceryFilePath = `assets/璃月荣发商铺店主东升.json`; const liyueWanminFilePath = `assets/璃月万民堂老板卯师傅.json`; const groceryFilePath = `assets/稻妻九十九物店主葵.json`; const charcoalFilePath = `assets/稻妻志村屋店主志村勘兵卫.json`; -const fengdanGroceryFilePath = `assets/枫丹杂货商布希柯.json`; -const cafeLuzheFilePath = `assets/咖啡厅露泽店主阿鲁埃.json`; +const fengdanGroceryFilePath = `assets/枫丹达莫维百货店主布希柯.json`; +const cafeLuzheFilePath = `assets/枫丹咖啡厅露泽店主阿鲁埃.json`; const sumiCityFishPath = `assets/须弥城鱼贩珀姆.json`; const omosPortFishPath = `assets/须弥奥摩斯港鱼贩布特罗斯.json`; const azaleVillMerPath = `assets/须弥阿如村商人阿扎莱.json`; // 定义所有可能的食材,注意料理名字长度可能超过识图范围 const ingredients = [ - "枫达", "盐", "洋葱", "牛奶", "番茄", "卷心菜", "土豆", "小麦", "胡椒","稻米", "豆腐", "杏仁", "鱼肉", "螃蟹", "虾仁", "咖啡豆", "秃秃豆", "发酵果实汁" + "枫达", "盐", "洋葱", "牛奶", "番茄", "香辛料", "卷心菜", "土豆", "小麦", "胡椒","稻米", "豆腐", "杏仁", "鱼肉", "螃蟹", "虾仁", "咖啡豆", "秃秃豆", "发酵果实汁" ]; // 筛选出用户选择的食材及其对应的路径文件和 NPC -const selectedIngredients = []; // 在函数外部声明一次 -const selectedPaths = new Map(); +let selectedIngredients = []; // 在函数外部声明一次 +let selectedPaths = new Map(); const ingredientPaths = { "枫达": [fengdanGroceryFilePath, cafeLuzheFilePath], @@ -29,7 +29,7 @@ const ingredientPaths = { "土豆": [mondstadtGroceryFilePath, liyueGroceryFilePath, groceryFilePath, fengdanGroceryFilePath], "小麦": [mondstadtGroceryFilePath, liyueGroceryFilePath, groceryFilePath, fengdanGroceryFilePath], "胡椒": [mondstadtGroceryFilePath, liyueGroceryFilePath, groceryFilePath, fengdanGroceryFilePath], - "稻米": [liyueGroceryFilePath, groceryFilePath], + "稻米": [liyueGroceryFilePath, groceryFilePath],// "虾仁": [liyueGroceryFilePath, groceryFilePath, sumiCityFishPath, omosPortFishPath], "豆腐": [liyueGroceryFilePath, groceryFilePath], "杏仁": [liyueGroceryFilePath, fengdanGroceryFilePath], @@ -37,13 +37,14 @@ const ingredientPaths = { "螃蟹": [liyueWanminFilePath, charcoalFilePath, sumiCityFishPath, omosPortFishPath], "秃秃豆": [fengdanGroceryFilePath, azaleVillMerPath], "咖啡豆": [cafeLuzheFilePath], + "香辛料": [azaleVillMerPath], "发酵果实汁": [fengdanGroceryFilePath] }; // 定义所有NPC名,注意名字长度可能超过识图范围 const npcNames = { [mondstadtGroceryFilePath]: ["布兰琪"], [liyueGroceryFilePath]: ["东升"], - [liyueWanminFilePath]: ["卵师傅", "卯师傅"], + [liyueWanminFilePath]: ["卯师傅"],// ["卯师傅", "卵师傅"] [groceryFilePath]: ["葵"], [charcoalFilePath]: ["志村勘"], [fengdanGroceryFilePath]: ["布希柯"], @@ -53,7 +54,7 @@ const npcNames = { [azaleVillMerPath]: ["阿扎莱"] }; -for (const ingredient of ingredients) { +for (let ingredient of ingredients) { if (settings[ingredient]) { selectedIngredients.push(ingredient); ingredientPaths[ingredient].forEach(path => { @@ -70,7 +71,7 @@ if (selectedIngredients.length === 0) { throw new Error("未选择任何食材,任务终止"); // 抛出异常以终止任务 } // 汇总即将购买的食材信息 -const purchaseSummary = selectedIngredients.join(", "); +let purchaseSummary = selectedIngredients.join(", "); log.info(`即将购买: ${purchaseSummary}`); // 定义一个函数用于模拟按键操作 @@ -86,153 +87,201 @@ async function clickSelectedIngredients(selectedIngredients, filePath, npcNames) log.info(`加载路径文件: ${filePath}`); await pathingScript.runFile(filePath); await sleep(1000); - log.info("路径文件执行完成"); + // log.info("路径文件执行完成"); // 识别并交互 NPC - let attempts = 0; - const maxAttempts = 5; // 最大尝试次数 - const npcxRange = { min: 1190, max: 1320 }; // X轴固定区间 - const npcyRanges = [478, 514, 552]; // 可能的Y轴坐标 - const tolerance = 10; // 容错区间 - const npctolerance = 10; // 容错区间 + const npcxRange = { min: 1190, max: 1320 }; // npc X轴区间 + const FxRange = { min: 1050, max: 1150 }; // F X轴坐标 + const FyRange = { min: 400, max: 800 }; // F Y轴坐标 + let fDialogueRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/F_Dialogue.png"), FxRange.min, FyRange.min, FxRange.max - FxRange.min, FyRange.max - FyRange.min); + const tolerance = 12; // 容错区间 + const npctolerance = 5; // 容错区间 let npcOcrResult = { success: false }; // 初始化 npcOcrResult - // 判断 Y 坐标是否在容错范围内 - function isYWithinTolerance(y, targetY, tolerance) { - return y >= targetY - tolerance && y <= targetY + tolerance; - } - // 执行点击操作 async function performClickOperations(filePath) { if (filePath === liyueGroceryFilePath || filePath === groceryFilePath || filePath === sumiCityFishPath) { - log.info("执行璃月杂货商或稻妻九十九物店主的点击操作"); - await click(1300, 650); await sleep(1000); + log.info("执行璃月稻妻杂货商等的点击操作"); + await click(1300, 650); await sleep(500); // 双击增加低帧点击成功率 + await click(1300, 650); await sleep(500); await click(1300, 650); await sleep(1000); await click(1600, 1020); await sleep(1000); } else { log.info("执行其他路径文件的点击操作"); - await click(1300, 580); await sleep(1000); + await click(1300, 580); await sleep(500); + await click(1300, 580); await sleep(500); await click(1300, 580); await sleep(1000); await click(1600, 1020); await sleep(1000); } } - while (attempts < maxAttempts) { - attempts++; - log.info(`尝试识别 NPC,尝试次数: ${attempts}`); + // 检查 F 图标和右边水平对齐的文字 + async function checkNpcAndFAlignment(npcName, fDialogueRo) { + let ra = captureGameRegion(); + let fRes = ra.find(fDialogueRo); + if (!fRes.isExist()) { + let f_attempts = 0; // 初始化尝试次数 + while (f_attempts < 3) { // 最多尝试 3 次 + f_attempts++; + log.info(`当前尝试次数:${f_attempts}`); - for (const npcName of npcNames) { - log.info(`尝试识别 NPC: ${npcName}`); - npcOcrResult = await performOcr(npcName, npcxRange, { min: 470, max: 602 }, tolerance); - - if (npcOcrResult.success) { - if ( - isYWithinTolerance(npcOcrResult.y, 478, npctolerance) || - isYWithinTolerance(npcOcrResult.y, 514, npctolerance) - ) { - // 如果 Y 坐标在 478 或 514 的容错范围内,直接按下 F 键 - log.info(`直接按下 F 键与 NPC ${npcName} 交互...`); - keyPress("F"); - await sleep(2000); - - // 执行点击操作 - await performClickOperations(filePath); - break; // 成功交互,退出内层循环 - } else if (isYWithinTolerance(npcOcrResult.y, 552, npctolerance)) { - // 如果 Y 坐标在 552 的容错范围内,调整当前路径 - log.info(`Y 坐标在 552 的容错范围内,调整当前路径`); - await simulateKeyOperations("S", 600); // 后退 600 毫秒 + if (f_attempts === 1) { + // 第一次未找到 F 图标 + await simulateKeyOperations("S", 500); // 后退 500 毫秒 + await sleep(200); await simulateKeyOperations("W", 800); // 前进 800 毫秒 - } else { - log.error(`识别到的 Y 坐标 ${npcOcrResult.y} 不在预期范围内,尝试次数: ${attempts}`); - } - break; // 成功识别到 NPC,退出内层循环 - } else { - if (attempts === 1) { - // 第一次失败时,尝试调整位置 - await simulateKeyOperations("S", 600); // 后退 600 毫秒 - await simulateKeyOperations("W", 800); // 前进 800 毫秒 - } else if (attempts === 2) { - // 第二次失败时,重新加载路径文件 + } else if (f_attempts === 2) { + // 第二次未找到 F 图标 log.info("重新加载路径文件"); await pathingScript.runFile(filePath); - await sleep(1000); + await sleep(500); + } else { + // 第三次未找到 F 图标 + log.error("尝试次数已达上限"); + return false; } - log.error(`OCR 识别未找到 NPC: ${npcName},尝试次数: ${attempts}`); + log.error(`尝试 ${f_attempts + 1}:寻找 F 图标`); } } + // log.info(`F 图标x: ${fRes.x},y: ${fRes.y},width: ${fRes.width},height: ${fRes.height}`); + // 获取 F 图标的中心点 Y 坐标 + let centerYF = fRes.y + fRes.height / 2; - if (npcOcrResult.success) { - break; // 成功识别到 NPC,退出外层循环 + // 在 F 图标右侧水平方向上识别 NPC 名称 + let ocrResult = await performOcr(npcName, npcxRange, { min: fRes.y, max: fRes.y + fRes.height }, tolerance); + // log.info(`NPC 名称x: ${ocrResult.x},y: ${ocrResult.y},width: ${ocrResult.width},height: ${ocrResult.height}`); + if (!ocrResult.success) { + log.error(`OCR 识别未找到 NPC: ${npcName}`); + return false; + } + + // 获取 NPC 名称的中心点 Y 坐标 + let centerYnpcName = ocrResult.y + ocrResult.height / 2; + + // 检查 NPC 名称和 F 图标的中心点 Y 坐标是否在容错范围内 + if (Math.abs(centerYnpcName - centerYF) <= npctolerance) { + // log.info(`NPC '${npcName}' 和 F 图标水平对齐,执行交互, NPC: ${centerYnpcName}, F 图标: ${centerYF}`); + return true; + } else { + log.info(`NPC '${npcName}' 和 F 图标未水平对齐,尝试滚动, NPC: ${centerYnpcName}, F 图标: ${centerYF}`); + return false; } } - if (attempts >= maxAttempts) { - log.error(`识别 NPC 失败 ${maxAttempts} 次,放弃该路线`); - return; // 放弃该路线 - } - - // 记录已购买的食材 - const purchasedIngredients = new Set(); - - // 继续后续操作 - const ingredientXRange = { min: 220, max: 390 }; // X坐标范围 - const ingredientYRange = { min: 95, max: 950 }; // Y坐标范围 - const ingredientTolerance = 10; // 容错区间 - const clickOffset = 30; // 点击坐标容错 - - let allIngredientsFound = false; // 标记是否所有食材都已找到 + // 新增变量用于记录滚轮操作次数 let scrollAttempts = 0; - const maxScrollAttempts = 3; // 最大翻页次数 + const maxScrollAttempts = 5; // 最大滚轮操作次数限制 - while (!allIngredientsFound && scrollAttempts < maxScrollAttempts) { - allIngredientsFound = true; // 假设本轮所有食材都已找到,若后续发现未找到则修改为 false + for (const npcName of npcNames) { + log.info(`尝试识别 NPC: ${npcName}`); + let isAligned = await checkNpcAndFAlignment(npcName, fDialogueRo); - for (const ingredient of selectedIngredients) { - if (purchasedIngredients.has(ingredient)) { - log.info(`跳过已购买的食材: ${ingredient}`); - continue; // 跳过已购买的食材 - } + while (!isAligned && scrollAttempts < maxScrollAttempts) { + // 如果未水平对齐,执行滚轮操作 + await keyMouseScript.runFile(`assets/滚轮下翻.json`); + await sleep(1000); - const ocrResult = await performOcr(ingredient, ingredientXRange, ingredientYRange, ingredientTolerance); - if (ocrResult.success) { - log.info(`识别到 '${ingredient}',坐标: x=${ocrResult.x}, y=${ocrResult.y}`); - await click(ocrResult.x, ocrResult.y + clickOffset); - await sleep(1000); - - // 模拟购买操作的后续点击 - await click(1600, 1020); await sleep(1000); // 购买 - await click(1181, 600); await sleep(200); // 选择100个 - await click(1320, 780); await sleep(1000); // 最终确认 - await click(1320, 780); await sleep(1000); // 点击空白 - - // 记录已购买的食材 - purchasedIngredients.add(ingredient); - } else { - log.error(`OCR 识别未找到 '${ingredient}'`); - allIngredientsFound = false; // 本轮有食材未找到 - } - } - - if (!allIngredientsFound) { - log.info(`在当前页面未找到所有食材,尝试翻页`); - await PageScroll(1); // 每轮翻页滑动1次 - await sleep(600); + // 检查是否超过最大滚轮操作次数 scrollAttempts++; + if (scrollAttempts >= maxScrollAttempts) { + log.error(`滚轮操作次数已达上限 ${maxScrollAttempts} 次,退出循环`); + break; // 超过最大滚轮操作次数,终止循环 + } + + // 重新检查 F 图标和 NPC 名称是否对齐 + isAligned = await checkNpcAndFAlignment(npcName, fDialogueRo); + } + + if (isAligned) { + // 如果水平对齐,执行交互操作 + keyPress("F"); + await sleep(2500); + + // 执行点击操作 + await performClickOperations(filePath); + + // 只有在成功对齐并交互后,才执行后续的食材购买操作 + // 记录已购买的食材 + let purchasedIngredients = new Set(); + + // 继续后续操作 + const ingredientXRange = { min: 210, max: 390 }; // X坐标范围 + const ingredientYRange = { min: 105, max: 960 }; // Y坐标范围 + const ingredientTolerance = 10; // 容错区间 + const clickOffset = 30; // 点击坐标容错 + + let allIngredientsFound = false; // 标记是否所有食材都已找到 + let scrollAttemptsForIngredients = 0; + const maxScrollAttemptsForIngredients = 3; // 最大翻页次数 + + while (!allIngredientsFound && scrollAttemptsForIngredients < maxScrollAttemptsForIngredients) { + allIngredientsFound = true; // 假设本轮所有食材都已找到,若后续发现未找到则修改为 false + + for (const ingredient of selectedIngredients) { + if (purchasedIngredients.has(ingredient)) { + log.info(`跳过已购买的食材: ${ingredient}`); + continue; // 跳过已购买的食材 + } + + let ocrResult = await performOcr(ingredient, ingredientXRange, ingredientYRange, ingredientTolerance); + if (ocrResult.success) { + log.info(`识别到 '${ingredient}',坐标: x=${ocrResult.x}, y=${ocrResult.y}`); + await click(ocrResult.x, ocrResult.y + clickOffset); + await sleep(1000); + + // 模拟购买操作的后续点击 + await click(1600, 1020); await sleep(1000); // 购买 + await click(1181, 600); await sleep(200); // 选择100个 + await click(1320, 780); await sleep(1000); // 最终确认 + await click(1320, 780); await sleep(1000); // 点击空白 + + // 记录已购买的食材 + purchasedIngredients.add(ingredient); + } else { + log.error(`OCR 识别未找到 '${ingredient}'`); + allIngredientsFound = false; // 本轮有食材未找到 + } + } + + if (!allIngredientsFound) { + log.info(`在当前页面未找到所有食材,尝试翻页`); + await PageScroll(1); // 每轮翻页滑动1次 + await sleep(600); + scrollAttemptsForIngredients++; + } + } + + if (!allIngredientsFound) { + log.error(`在所有页面中未找到所有食材,跳过该路径`); + } + + // 最后点击退出按钮 + log.info("点击退出按钮..."); + await click(1845, 45); // 退出 + await sleep(2000); + + // 如果成功购买了所有食材,记录成功信息 + if (allIngredientsFound) { + log.info("成功购买了所有食材!"); + } else { + log.error("未能购买所有食材,部分食材可能未找到或未成功购买。"); + } + + return; // 结束函数,后续逻辑不再执行 + } else { + // 如果未水平对齐且超过最大滚轮操作次数,记录错误信息并跳过该 NPC + log.error(`未能找到正确的 NPC '${npcName}' 或未成功交互,跳过该 NPC`); } } - if (!allIngredientsFound) { - log.error(`在所有页面中未找到所有食材,跳过该路径`); - } - - // 最后点击退出按钮 - log.info("点击退出按钮..."); - await click(1845, 45); // 退出 - await sleep(2000); + // 如果没有找到任何 NPC 或未成功交互,则记录错误信息并退出 + log.error("未能找到正确的 NPC 或未成功交互,跳过该路径"); } + + + // 自动执行划页操作 async function PageScroll(scrollCount) { try { @@ -254,7 +303,7 @@ async function PageScroll(scrollCount) { leftButtonDown(); // 将鼠标移动到目标位置,模拟更自然的拖动操作 - log.info("移动鼠标"); + // log.info("移动鼠标"); const steps = totalDistance / stepDistance; // 分成若干步移动 for (let j = 0; j < steps; j++) { @@ -268,18 +317,24 @@ async function PageScroll(scrollCount) { await sleep(100); } } catch (error) { - log.error(`执行划页操作时发生错误:${error.message}`); + log.error(`执行滑动操作时发生错误:${error.message}`); } } +// 定义替换映射表 +const replacementMap = { + "监": "盐", + "卵": "卯" +}; + // 定义一个函数用于执行OCR识别 async function performOcr(targetText, xRange, yRange, tolerance) { // 调整区域范围以包含容错区间 - const adjustedXMin = xRange.min - tolerance; - const adjustedXMax = xRange.max + tolerance; - const adjustedYMin = yRange.min - tolerance; - const adjustedYMax = yRange.max + tolerance; - /*/ log.info(` + let adjustedXMin = xRange.min - tolerance; + let adjustedXMax = xRange.max + tolerance; + let adjustedYMin = yRange.min - tolerance; + let adjustedYMax = yRange.max + tolerance; + /*log.info(` adjustedXMin: ${adjustedXMin} adjustedXMax: ${adjustedXMax} adjustedYMin: ${adjustedYMin} @@ -287,9 +342,8 @@ async function performOcr(targetText, xRange, yRange, tolerance) { `);*/ // 在捕获的区域内进行OCR识别 - const ra = captureGameRegion(); - - const resList = ra.findMulti(RecognitionObject.ocr( + let ra = captureGameRegion(); + let resList = ra.findMulti(RecognitionObject.ocr( adjustedXMin, adjustedYMin, adjustedXMax - adjustedXMin, adjustedYMax - adjustedYMin )); @@ -297,9 +351,17 @@ async function performOcr(targetText, xRange, yRange, tolerance) { // 遍历识别结果,检查是否找到目标文本 for (let i = 0; i < resList.count; i++) { - if (resList[i].text.includes(targetText)) { + let res = resList[i]; + // log.info("0CR结果-"+ res.text); + // 后处理:根据替换映射表检查和替换错误识别的字符 + let correctedText = res.text; + for (let [wrongChar, correctChar] of Object.entries(replacementMap)) { + correctedText = correctedText.replace(wrongChar, correctChar); + } + + if (correctedText.includes(targetText)) { // 如果找到目标文本,直接返回坐标 - return { success: true, x: resList[i].x, y: resList[i].y }; // 找到符合条件的文本,返回坐标 + return { success: true, x: resList[i].x, y: resList[i].y, width: resList[i].width, height: resList[i].height }; // 找到符合条件的文本,返回坐标 } } return { success: false }; // 未找到符合条件的文本 @@ -310,8 +372,8 @@ async function AutoPath() { log.info("开始执行自动寻路任务"); // 加载路径文件和 NPC 名称 - for (const [path, ingredients] of selectedPaths) { - const npcName = npcNames[path]; + for (let [path, ingredients] of selectedPaths) { + let npcName = npcNames[path]; await clickSelectedIngredients(ingredients, path, npcName); } } diff --git a/repo/js/OCR购买食材/manifest.json b/repo/js/OCR购买食材/manifest.json index 058d4fc4..ac28fa8d 100644 --- a/repo/js/OCR购买食材/manifest.json +++ b/repo/js/OCR购买食材/manifest.json @@ -1,8 +1,8 @@ { "manifest_version": 1, "name": "选择购买食材OCR", - "version": "1.20401", - "description": "寻路杂货商,更新OCR版,对NPC和材料文字识别,可自定义购买食材。一般食材杂货在蒙德、璃月、稻妻、枫丹杂货商购买,10鱼肉、10螃蟹在卯师傅、珀姆、布特罗斯、阿扎莱和志村勘兵卫购买。", + "version": "1.20403", + "description": "寻路杂货商,更新OCR版,对NPC和材料文字识别,一般食材杂货在蒙德、璃月、稻妻、枫丹杂货商购买,10鱼肉、10螃蟹在卯师傅、珀姆、布特罗斯、阿扎莱和志村勘兵卫购买。至少需要0.44版本bgi,增加对话F图像识别,增加个别字识别容错;增加香辛料,在阿扎莱处购买", "authors": [ { "name": "吉吉喵" diff --git a/repo/js/OCR购买食材/settings.json b/repo/js/OCR购买食材/settings.json index 6c9412f1..c72a4dc9 100644 --- a/repo/js/OCR购买食材/settings.json +++ b/repo/js/OCR购买食材/settings.json @@ -4,6 +4,21 @@ "type": "checkbox", "label": "选择食材:\n============\n咖啡豆" }, + { + "name": "鱼肉", + "type": "checkbox", + "label": "-----------------\n鱼肉" + }, + { + "name": "螃蟹", + "type": "checkbox", + "label": "-----------------\n螃蟹" + }, + { + "name": "香辛料", + "type": "checkbox", + "label": "-----------------\n香辛料" + }, { "name": "秃秃豆", "type": "checkbox", @@ -19,16 +34,6 @@ "type": "checkbox", "label": "-----------------\n发酵果实汁" }, - { - "name": "鱼肉", - "type": "checkbox", - "label": "-----------------\n鱼肉" - }, - { - "name": "螃蟹", - "type": "checkbox", - "label": "-----------------\n螃蟹" - }, { "name": "稻米", "type": "checkbox",