From 866dc23a7e9333f46649e08fb4583984ce8bef81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BF=B7=E8=B7=AF=E3=81=AE=E9=BE=99=E7=8E=8B?= <3069177893@qq.com> Date: Tue, 27 May 2025 14:03:08 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=98=E6=AD=8C=E5=A3=B6=E4=B8=80=E6=9D=A1?= =?UTF-8?q?=E9=BE=99=20(#932)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update and rename readme.txt to readme.md * Update readme.md * Update and rename readme.md to README.md * Update main.js * Update manifest.json * Update README.md * Update README.md * Add files via upload * Add files via upload * Add files via upload * Update repo/js/尘歌壶一条龙/manifest.json Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: 秋云 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- repo/js/尘歌壶一条龙/main.js | 413 +++++++++++++++++++++++++++++ repo/js/尘歌壶一条龙/manifest.json | 14 + repo/js/尘歌壶一条龙/settings.json | 22 ++ 3 files changed, 449 insertions(+) create mode 100644 repo/js/尘歌壶一条龙/main.js create mode 100644 repo/js/尘歌壶一条龙/manifest.json create mode 100644 repo/js/尘歌壶一条龙/settings.json diff --git a/repo/js/尘歌壶一条龙/main.js b/repo/js/尘歌壶一条龙/main.js new file mode 100644 index 00000000..19647a4e --- /dev/null +++ b/repo/js/尘歌壶一条龙/main.js @@ -0,0 +1,413 @@ +async function main() { + + const today = new Date().getDay(); + const isMonday = today === 1; + + // 检查是否为周一,周三或周六 + if (!isScheduledDay()) { + log.info("今日非周一,周三或周六,脚本不执行"); + return; + } + + // 检查配置 + checkSettings(); + + // 打开背包并切换到小道具 + await openBackpack(); + + // 查找并使用尘歌壶 + await findAndUseSereniteaPot(); + + // 等待进入尘歌壶 + await waitForEnteringSereniteaPot(); + + // 找到阿圆 + await moveToTarget(settings.route); + + // 与阿圆对话 + keyPress("F"); + await sleep(2000); + click(960, 540); + await sleep(2000); + + // 领取好感度以及洞天宝钱 + await collectRewards(); + + if (isMonday) { + log.info("今天是周一,兑换物品"); + // 兑换物品 + await exchangeItems(); + } + + // 关闭与阿圆的对话 + await sleep(1000) + click(1360, 800); + await sleep(1000); + click(960, 540); + + // 周一执行锻造任务和烹饪任务 + if (isMonday) { + log.info("今天是周一,执行锻造任务"); + if (settings.forgingRoute) await handleForging(); + log.info("今天是周一,执行烹饪任务"); + if (settings.cookingRoute) await handleCooking(); + keyDown("a"); + await sleep(2000); + keyUp("a"); + } +} + +//============== 烹饪功能 ==============// +async function handleCooking() { + log.info("开始自动烹饪"); + try { + // 移动到烹饪点 + await moveToTarget(settings.cookingRoute); + + // 执行烹饪操作序列 + keyPress("F"); await sleep(1000); + click(1695, 1013); await sleep(1000); // 选择料理台 + click(785, 1015); await sleep(500); // 选择自动制作 + click(1018, 452); await sleep(500); // 选择制作 + keyPress("2"); await sleep(200); // 选择数量 + keyPress("0"); await sleep(200); + click(1159, 755); await sleep(2000); // 确认制作 + + // 关闭界面 + for(let i=0; i<3; i++) { + keyPress("Escape"); await sleep(500); + } + log.info("烹饪完成"); + } catch (e) { + log.info("烹饪失败: " + e.message); + } +} + +//============== 锻造功能 ==============// +async function handleForging() { + log.info("开始自动锻造"); + try { + // 移动到锻造点 + await moveToTarget(settings.forgingRoute); + + // 执行锻造操作序列 + keyPress("F"); await sleep(1500); + + // 完成材料 + for(let i=0; i<6; i++) { + click(1745, 1019); await sleep(300); + } + + click(217, 152); await sleep(800); // 选择条目 + click(546, 288); await sleep(1000); // 选择矿产 + + // 确认锻造 + for(let i=0; i<3; i++) { + click(1745, 1019); await sleep(300); + } + + keyPress("Escape"); await sleep(1000); // 关闭界面 + log.info("锻造完成"); + } catch (e) { + log.info("锻造失败: " + e.message); + } +} + +// 判断当前是否为周一,周三或周六 +function isScheduledDay() { + const today = new Date().getDay(); // 0=周日, 1=周一, ..., 6=周六 + return today === 1 || today === 3 || today === 6; // 周一,周三或周六 +} + +async function exchangeItems() { + if (!settings.itemsToBuy) { + log.warn("未配置要购买的物品"); + return; + } + + log.info("开始兑换物品"); + // 点击洞天百宝 + click(1386, 655); + await sleep(1000); + // 点击第一个选项卡 + click(712, 50) + await sleep(1000); + + // 获取用户想要购买的物品列表 + const itemsToBuy = settings.itemsToBuy.split(',').map(item => item.trim()); + log.info(`要购买的物品: ${itemsToBuy.join(', ')}`); + + // 设置固定的坐标 + const firstItemX = 193; + const firstItemY = 196; + const xOffset = 168; // 水平方向上的间距 + const yOffset = 190; // 垂直方向上的间距 + const itemsPerRow = 7; // 每行物品数量 + + // 临时变量,已找到的物品数组和上一个物品名称变量 + const foundItems = []; + let lastItemName = ""; + + // 遍历所有物品 + outerLoop: for (let row = 0; row < 3; row++) { + for (let col = 0; col < itemsPerRow; col++) { + // 计算当前物品中心点坐标 + const centerX = firstItemX + (xOffset * col); + const centerY = firstItemY + (yOffset * row); + + // 需要重复检查这个位置的物品 + let keepCheckingCurrentPosition = true; + + // 循环检查当前位置的物品,直到不再找到匹配的物品 + while (keepCheckingCurrentPosition) { + // 点击物品中心 + click(centerX, centerY); + await sleep(1000); + + // 获取物品详情区域截图 + let screen = captureGameRegion(); + let targetRegion = screen.DeriveCrop(1308, 120, 491, 56); + + // 使用OCR识别物品名称 + let ocrRo = RecognitionObject.Ocr(0, 0, targetRegion.Width, targetRegion.Height); + let ocrResult = targetRegion.find(ocrRo); + + if (ocrResult.isEmpty()) { + throw new Error("无法识别物品名称,请检查具体原因"); + } + + const itemName = ocrResult.Text.trim(); + // 检查是否与上一个物品名称相同 + if (itemName === lastItemName) { + break outerLoop; + } else { + lastItemName = itemName; + } + + // 检查物品是否已售罄 + let soldOutRegion = screen.DeriveCrop(1308, 403, 491, 100); + let soldOutOcrRo = RecognitionObject.Ocr(0, 0, soldOutRegion.Width, soldOutRegion.Height); + let soldOutResult = soldOutRegion.find(soldOutOcrRo); + + // 如果发现任何已售罄的物品,就认为所有可购买的物品都已检查过,结束搜索 + log.debug(`识别到的文字: ${soldOutResult.Text}`) + if (!soldOutResult.isEmpty() && soldOutResult.Text.includes("已售罄")) { + break outerLoop; + } + + // 检查是否是用户想要购买的物品(使用包含关系) + let matchedItem = itemsToBuy.find(item => itemName.includes(item)); + + if (matchedItem) { + log.info(`找到要购买的物品: ${itemName} (匹配: ${matchedItem})`); + // 记录已找到的物品 + if (!foundItems.includes(matchedItem)) { + foundItems.push(matchedItem); + } + + log.info(`开始购买物品: ${itemName}`); + + // 执行购买流程 + // 1. 鼠标移动到起始位置 + moveMouseTo(1448, 693); + await sleep(300); + + // 2. 按下鼠标左键 + leftButtonDown(); + await sleep(300); + + // 3. 移动到结束位置 + moveMouseTo(1753, 693); + await sleep(300); + + // 4. 松开鼠标左键 + leftButtonUp(); + await sleep(500); + + // 5. 点击确认按钮 + click(1698, 1022); + await sleep(1000); + + // 6. 关闭弹窗 + click(962, 763); + await sleep(1000); + + log.info(`成功购买物品: ${itemName}`); + + // 检查是否已找到所有物品 + if (foundItems.length === itemsToBuy.length) { + log.info("已找到所有需要购买的物品,提前结束搜索"); + break outerLoop; + } + } else { + // 如果不匹配,不继续检查当前位置 + keepCheckingCurrentPosition = false; + } + } + } + } + + // 如果浏览完所有格子后仍有未找到的物品 + const notFound = itemsToBuy.filter(item => !foundItems.includes(item)); + if (notFound.length > 0) { + log.warn(`浏览完所有物品后,以下物品未找到或已售罄: ${notFound.join(', ')}`); + } + + // 关闭兑换页面 + await sleep(1000); + click(1841, 47) + await sleep(1000); + +} + +// 检查配置 +function checkSettings() { + if (!settings.route) { + log.warn("当前未配置进入尘歌壶以后的路线,脚本可能无法正常运行"); + } + + // 记录是否跳过领取角色好感和洞天宝钱 + if (settings.skipCharacterReward) { + log.info("当前配置:不领取角色好感"); + } + + if (settings.skipTreasureReward) { + log.info("当前配置:不领取洞天宝钱"); + } +} + +// 打开背包并切换到小道具 +async function openBackpack() { + keyPress("B"); + await sleep(1000); + click(1048, 50); + await sleep(1000); +} + +// 查找并使用尘歌壶 +async function findAndUseSereniteaPot() { + await findSereniteaPot(); + await sleep(1000); + keyPress("F"); +} + +// 等待进入尘歌壶 +async function waitForEnteringSereniteaPot() { + // 先等待5秒,应该不会比这快 + await sleep(5000); + + // 等待传送完成 + let isEntering = true; + while (isEntering) { + let screen = captureGameRegion(); + let targetRegion = screen.DeriveCrop(85, 1025, 69, 28); + let ocrRo = RecognitionObject.Ocr(0, 0, targetRegion.Width, targetRegion.Height); + let ocrResult = targetRegion.find(ocrRo); + if (ocrResult.Text.toLowerCase().includes("enter")) { + isEntering = false; + } + await sleep(1000); + } + + // 进入尘歌壶以后,等待1秒 + await sleep(1000); +} + +// 移动到阿圆并领取奖励 +async function collectRewards() { + log.info("开始领取好感度以及洞天宝钱"); + + click(1370, 432); + await sleep(1000); + + // 领取好感度 + if (!settings.skipCharacterReward) { + log.info("领取角色好感度"); + click(1810, 715); + await sleep(1000); + + // 关闭洞天赠礼弹窗 + click(1346, 300); + await sleep(1000); + } else { + log.info("根据自定义配置,跳过领取角色好感度"); + } + + // 领取洞天宝钱 + if (!settings.skipTreasureReward) { + log.info("领取洞天宝钱"); + click(1080, 929); + await sleep(1000); + + // 关闭洞天财瓮弹窗 + click(1346, 300); + await sleep(1000); + } else { + log.info("根据自定义配置,跳过领取洞天宝钱"); + } + + // 关闭对话 + click(1864, 47); + await sleep(3000); +} + +async function findSereniteaPot() { + let currentX = 178; // 起始X坐标 + let searchCount = 0; // 添加查找次数计数器 + const MAX_SEARCH_COUNT = 5; // 最大查找次数 + + while (searchCount < MAX_SEARCH_COUNT) { + searchCount++; + // 点击当前坐标的小道具 + click(currentX, 188); + await sleep(1000); + + // 获取游戏区域截图 + let screen = captureGameRegion(); + + // 根据指定区域进行剪裁 + let targetRegion = screen.DeriveCrop(1307, 119, 493, 55); + + // 使用OCR识别 + let ocrRo = RecognitionObject.Ocr(0, 0, targetRegion.Width, targetRegion.Height); + let ocrResult = targetRegion.find(ocrRo); + + if (!ocrResult.isEmpty() && ocrResult.Text.includes("尘歌壶")) { + // 点击指定坐标 + click(1690, 1020); + await sleep(1000); + // 检查一下背包页面是否退出了,有可能当前角色状态没法放置尘歌壶,直接再判断一次截图区域文本是不是尘歌壶就行 + let screen = captureGameRegion(); + // 根据指定区域进行剪裁 + let targetRegion = screen.DeriveCrop(1307, 119, 493, 55); + let ocrRo = RecognitionObject.Ocr(0, 0, targetRegion.Width, targetRegion.Height); + let ocrResult = targetRegion.find(ocrRo); + if (!ocrResult.isEmpty() && ocrResult.Text.includes("尘歌壶")) { + throw new Error("当前无法放置尘歌壶,请检查具体原因"); + } + return; + } else { + currentX += 145; // 向右移动145像素,查找下一个格子的小道具 + await sleep(100); + } + } + + throw new Error(`查找尘歌壶次数超过${MAX_SEARCH_COUNT}次,请检查背包是否存在尘歌壶`); +} + +async function moveToTarget(routeConfig) { + if (!routeConfig) return; + + const routes = routeConfig.split(',').map(r => r.trim()); + for (const route of routes) { + const [direction, time] = route.split(' '); + if (!direction || !time) continue; + + keyDown(direction); + await sleep(parseInt(time)); + keyUp(direction); + await sleep(500); + } +} + +main(); diff --git a/repo/js/尘歌壶一条龙/manifest.json b/repo/js/尘歌壶一条龙/manifest.json new file mode 100644 index 00000000..8bc2ac93 --- /dev/null +++ b/repo/js/尘歌壶一条龙/manifest.json @@ -0,0 +1,14 @@ +{ + "manifest_version": 1, + "name": "尘歌壶一条龙", + "version": "1.0", + "description": "自动放置并进入尘歌壶,寻找阿圆,领取洞天宝钱和好感,做饭,锻造(需要配置进入尘歌壶以后的路线),支持自动购买指定物品。推荐洞天摹数81708444664", + "authors": [ + { + "name": "miludelongwang", + "link": "https://github.com/miludelongwang/GI-Model-Importer" + } + ], + "settings_ui": "settings.json", + "main": "main.js" +} diff --git a/repo/js/尘歌壶一条龙/settings.json b/repo/js/尘歌壶一条龙/settings.json new file mode 100644 index 00000000..2a24f402 --- /dev/null +++ b/repo/js/尘歌壶一条龙/settings.json @@ -0,0 +1,22 @@ +[ + { + "name": "route", + "type": "input-text", + "label": "进入尘歌壶以后寻找阿圆的路径\n填写规则:方向键+空格+时间(单位:毫秒)\n多个路径用英文逗号隔开,示例:A 1800,S 1300\n示例配套洞天摹数81708444664" + }, + { + "name": "itemsToBuy", + "type": "input-text", + "label": "想要购买的物品名称,支持只填写部分文字\n多个物品用英文逗号隔开,例如:祝圣精华,树脂" + }, + { + "name": "forgingRoute", + "type": "input-text", + "label": "锻造路径(格式同上),示例:D 2000\n周一自动执行" + }, + { + "name": "cookingRoute", + "type": "input-text", + "label": "烹饪路径(格式同上),示例:W 1000\n周一自动执行" + } +]