diff --git a/repo/js/铁匠铺/assets/RecognitionObject/Confirm Deploy Button.png b/repo/js/铁匠铺/assets/RecognitionObject/Confirm Deploy Button.png new file mode 100644 index 00000000..6c870dfc Binary files /dev/null and b/repo/js/铁匠铺/assets/RecognitionObject/Confirm Deploy Button.png differ diff --git a/repo/js/铁匠铺/assets/RecognitionObject/Forge.png b/repo/js/铁匠铺/assets/RecognitionObject/Forge.png new file mode 100644 index 00000000..d0abc490 Binary files /dev/null and b/repo/js/铁匠铺/assets/RecognitionObject/Forge.png differ diff --git a/repo/js/铁匠铺/assets/RecognitionObject/ForgingInterface.png b/repo/js/铁匠铺/assets/RecognitionObject/ForgingInterface.png new file mode 100644 index 00000000..37743aa1 Binary files /dev/null and b/repo/js/铁匠铺/assets/RecognitionObject/ForgingInterface.png differ diff --git a/repo/js/铁匠铺/assets/RecognitionObject/全部领取.png b/repo/js/铁匠铺/assets/RecognitionObject/全部领取.png new file mode 100644 index 00000000..49f3efc0 Binary files /dev/null and b/repo/js/铁匠铺/assets/RecognitionObject/全部领取.png differ diff --git a/repo/js/铁匠铺/main.js b/repo/js/铁匠铺/main.js index 70350bfd..e9b9da5c 100644 --- a/repo/js/铁匠铺/main.js +++ b/repo/js/铁匠铺/main.js @@ -1,3 +1,10 @@ +//锻造按钮模板 +const ConfirmDeployButtonRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/Confirm Deploy Button.png"), 0, 870, 1920, 210); +const ForgingInterfaceRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/ForgingInterface.png"), 0, 0, 140, 100); +const ForgeRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/Forge.png"), 1260, 300, 600, 600); + + + (async function () { // 设置通知状态 let notice = settings.notice ?? false; @@ -12,8 +19,8 @@ // 读取用户配置 let smithyName = settings.smithyName || "枫丹铁匠铺"; let primaryOre = settings.ore || "水晶块"; - let secondaryOre = settings.secondaryOre || "萃凝晶"; // 新增备选矿物2 - let tertiaryOre = settings.tertiaryOre || "紫晶块"; // 新增备选矿物3 + let secondaryOre = settings.secondaryOre || "萃凝晶"; + let tertiaryOre = settings.tertiaryOre || "紫晶块"; // 定义矿物名称和图片文件名的映射表 const ingredientImageMap = { @@ -38,7 +45,6 @@ // 行列数的排列组合 const rows = [1, 2, 3]; // 行数 const cols = [1, 2, 3, 4, 5]; // 列数 - const gridCoordinates = []; for (const row of rows) { @@ -122,75 +128,163 @@ log.info(`开始识别矿石: ${OreChineseMap[oreType]}`); const scanOffset = { x: -35, y: -35 }; - for (const coordinate of gridCoordinates) { - const scanX = coordinate.x + scanOffset.x; - const scanY = coordinate.y + scanOffset.y; - const imageResult = recognizeImage(imagePath, scanX, scanY, 70, 70); - if (imageResult) { - imageResult.click(); - await sleep(2000); - if (notice) { - notification.send(`通过图像识别找到矿石: ${OreChineseMap[oreType]}`); - } else { - log.info(`通过图像识别找到矿石: ${OreChineseMap[oreType]}`); - } + // 最大尝试次数 + const maxAttempts = 3; + for (let attempt = 0; attempt < maxAttempts; attempt++) { + let found = false; + for (const coordinate of gridCoordinates) { + const scanX = coordinate.x + scanOffset.x; + const scanY = coordinate.y + scanOffset.y; + const imageResult = recognizeImage(imagePath, scanX, scanY, 70, 70); - determineOre(oreType); - // 点击"开始锻造"3次 - for (let i = 0; i < 3; i++) { + if (imageResult) { + found = true; + imageResult.click(); await sleep(1000); - click(1645, 1015); + + if (notice) { + notification.send(`通过图像识别找到矿石: ${OreChineseMap[oreType]}`); + } + determineOre(oreType); + + // 点击“开始锻造”按钮3次,每次点击后进行OCR识别提示 + const ocrRegion = { x: 660, y: 495, width: 1250 - 660, height: 550 - 495 }; + + // 内部点击循环——点击“开始锻造”按钮后,进行OCR识别 + let clickAttempts = 0; + let forgingTriggered = false; + + while (clickAttempts < 3 && !forgingTriggered) { + // 点击“开始锻造” + let ConfirmButton = captureGameRegion().find(ConfirmDeployButtonRo); + if (ConfirmButton.isExist()) { + //log.info("识别到确定按钮:({x},{y},{w},{h})", ConfirmButton.x, ConfirmButton.y, ConfirmButton.Width, ConfirmButton.Height); + ConfirmButton.click(); + } else { + //log.warn("未能识别到确定按钮"); + } + await sleep(1500); // 等待提示出现 + + // 执行OCR识别提示区域内的文字 + let ocrResults = captureGameRegion().find( + RecognitionObject.ocr(ocrRegion.x, ocrRegion.y, ocrRegion.width, ocrRegion.height) + ); + + if (ocrResults) { + log.info(`${ocrResults.text}`); + if (ocrResults.text.includes("今日已无法锻造")) { + if (notice) { + notification.send("检测到 今日已无法锻造 停止脚本"); + } else { + log.info("检测到 今日已无法锻造 停止脚本"); + } + return true; // 完全终止锻造流程 + } else if (ocrResults.text.includes("材料不足")) { + if (notice) { + notification.send("检测到 材料不足 跳过当前矿物。请检查背包,及时补充矿物。"); + } else { + log.info("检测到 材料不足 跳过当前矿物。请检查背包,及时补充矿物。"); + } + await click(960, 800); // 点击确定关闭提示 + await sleep(1000); + return false; // 直接返回,跳过识别当前矿物 + } else { + // 如果OCR识别结果没有检测到错误提示,则认为本次锻造指令有效 + forgingTriggered = true; + } + } else { + //log.warn("未能识别到任何文字"); + } + clickAttempts++; + } } - return true; + } + // 如果本次尝试未识别到矿石,则等待后重试 + if (!found) { + if (notice) { + //notification.error(`未能识别到矿石: ${OreChineseMap[oreType]},重试中... (${attempt + 1}/${maxAttempts})`); + } + log.error(`未能识别到矿石: ${OreChineseMap[oreType]},重试中... (${attempt + 1}/${maxAttempts})`); + + await sleep(1000); } } - if (notice) { - notification.error(`未能识别到矿石: ${OreChineseMap[oreType]}`); + notification.error(`未能识别到矿石: ${OreChineseMap[oreType]},停止尝试`); } else { - log.error(`未能识别到矿石: ${OreChineseMap[oreType]}`); + log.error(`未能识别到矿石: ${OreChineseMap[oreType]},停止尝试`); } return false; } // 锻造矿石操作 const forgeOre = async function (smithyName) { - // 对话 + // 对话部分(如果需要可打开注释) await sleep(1000); keyPress("F"); - await sleep(1000); await click(960, 600); - await sleep(1000); await click(960, 600); - await sleep(1000); await click(1375, 500); - await sleep(1000); await click(960, 600); await sleep(1000); - await click(960, 600); await sleep(1000); + await sleep(1000); await click(960, 1042); + await sleep(1000); await click(960, 1042); + let Forge = captureGameRegion().find(ForgeRo); + if (Forge.isExist()) { + //log.info("识别到锻造图标:({x},{y},{w},{h})", Forge.x, Forge.y, Forge.Width, Forge.Height); + await Forge.click(); + } else { + log.warn("未能识别到锻造图标"); + } + await sleep(1000); await click(960, 1042); + + await sleep(1000); await click(960, 1042); + + //检测到锻造界面 + for (let i = 0; i < 3; i++) { + let ForgingInterface = captureGameRegion().find(ForgingInterfaceRo); + if (ForgingInterface.isExist()) { + log.info("已进入锻造界面,准备锻造"); + break; + } else { + await sleep(1000); + } + } + + // 锻造领取(如果需要可打开注释) + //领取全部 + const ClaimAllRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("Assets/RecognitionObject/全部领取.png"), 0, 900, 1920, 180); + let ClaimAll = captureGameRegion().find(ClaimAllRo); + if (ClaimAll.isExist()) { + //log.info("识别到全部领取按钮:({x},{y},{w},{h})", ClaimAll.x, ClaimAll.y, ClaimAll.Width, ClaimAll.Height); + ClaimAll.click(); + await sleep(1000); // 等待提示出现 + + //确认领取 + let ConfirmButton = captureGameRegion().find(ConfirmDeployButtonRo); + if (ConfirmButton.isExist()) { + //log.info("识别到确定按钮:({x},{y},{w},{h})", ConfirmButton.x, ConfirmButton.y, ConfirmButton.Width, ConfirmButton.Height); + ConfirmButton.click(); + } else { + //log.warn("未能识别到确定按钮"); + } + + } else { + //log.warn("未能识别到全部领取按钮"); + } - log.info("已进入锻造界面,准备锻造"); - // 锻造领取 - await click(520, 140); await sleep(1000); - await click(170, 1010); await sleep(1000); - await click(960, 900); await sleep(1000); click(220, 150); await sleep(1000); - // 按优先级尝试识别矿石 let forgeSuccess = false; - - // 尝试主选矿石 - if (!forgeSuccess) { - forgeSuccess = await tryForgeOre(primaryOre, []); + // 尝试主选矿石 + if (await tryForgeOre(primaryOre, [])) { + forgeSuccess = true; } - - // 如果主选矿石识别失败,尝试备选矿石2(跳过与主选相同的) - if (!forgeSuccess) { - forgeSuccess = await tryForgeOre(secondaryOre, [primaryOre]); + // 如果主选识别失败,尝试备选矿石2 + else if (await tryForgeOre(secondaryOre, [primaryOre])) { + forgeSuccess = true; } - - // 如果备选矿石2也识别失败,尝试备选矿石3(跳过与主选和备选2相同的) - if (!forgeSuccess) { - forgeSuccess = await tryForgeOre(tertiaryOre, [primaryOre, secondaryOre]); + // 如果备选矿石2也失败,尝试备选矿石3 + else if (await tryForgeOre(tertiaryOre, [primaryOre, secondaryOre])) { + forgeSuccess = true; } - - // 如果所有矿石都识别失败 - if (!forgeSuccess) { + // 所有备选矿石都未能识别,结束锻造 + else { if (notice) { notification.error("所有备选矿石都未能识别,结束锻造"); } else { @@ -198,7 +292,7 @@ } } - // 退出锻造界面 + // 退出锻造界面(如果需要可打开注释) await click(520, 140); await sleep(1000); if (notice) { notification.send("锻造结束,退出界面"); @@ -208,6 +302,7 @@ await genshin.returnMainUi(); }; + // 执行步骤 await autoSmithy(smithyName); await forgeOre(smithyName); await genshin.returnMainUi(); @@ -216,4 +311,4 @@ if (notice) { notification.send("自动锻造矿石脚本结束"); } -})(); +})(); \ No newline at end of file diff --git a/repo/js/铁匠铺/manifest.json b/repo/js/铁匠铺/manifest.json index 469661f1..c3a42a27 100644 --- a/repo/js/铁匠铺/manifest.json +++ b/repo/js/铁匠铺/manifest.json @@ -1,9 +1,9 @@ { "manifest_version": 1, "name": "自动锻造魔矿", - "version": "1.40521(2025.05.21版)", + "version": "2.0\n(2025.05.22版)", "bgi_version": "0.44.0", - "description": "自动选择铁匠铺和使用矿物去锻造精锻矿。\n \n使用前请阅读“readme”文件。 \n---更新说明--- \n- 新增矿石未能识别时自动选择备用选矿", + "description": "自动选择铁匠铺和使用矿物去锻造精锻矿。\n \n使用前请阅读“readme”文件。 \n---更新说明--- \n- 新增矿石不足时自动选择备用选矿", "tags": ["铁匠铺", "锻造", "精锻用矿"], "authors": [ { diff --git a/repo/js/铁匠铺/readme(25.05.21).md b/repo/js/铁匠铺/readme(25.05.22).md similarity index 94% rename from repo/js/铁匠铺/readme(25.05.21).md rename to repo/js/铁匠铺/readme(25.05.22).md index 3207cb8e..91f5413a 100644 --- a/repo/js/铁匠铺/readme(25.05.21).md +++ b/repo/js/铁匠铺/readme(25.05.22).md @@ -55,6 +55,9 @@ ## 更新日志 +### 2.0(2025.05.22) +- 新增矿石不足时自动选择备用选矿 + ### 1.40521(2025.05.21) - 新增矿石未能识别时自动选择备用选矿