js:选择购买食材 (#516)

Co-authored-by: 秋云 <physligl@gmail.com>
This commit is contained in:
JJMdzh
2025-04-04 00:23:30 +08:00
committed by GitHub
parent 216e2db9a1
commit 565f674403
13 changed files with 438 additions and 172 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 B

View File

@@ -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"
}
]
}

View File

@@ -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": ""
}
]
}

View File

@@ -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"
}
]
}

View File

@@ -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"

View File

@@ -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": ""
}
]
}

View File

@@ -4,7 +4,7 @@
"type": "collect",
"author": "吉吉喵",
"version": "1.0",
"description": "购买杂货",
"description": "杂货",
"bgiVersion": "0.42.0"
},
"positions": [

View File

@@ -4,7 +4,7 @@
"type": "collect",
"author": "吉吉喵",
"version": "1.0",
"description": "购买鱼肉+螃蟹",
"description": "鱼肉+螃蟹",
"bgiVersion": "0.42.0"
},
"positions": [

View File

@@ -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"
}
]
}

View File

@@ -4,7 +4,7 @@
"type": "collect",
"author": "吉吉喵",
"version": "",
"description": "须弥奥摩斯港鱼贩布特罗斯",
"description": "鱼肉+螃蟹",
"bgiVersion": "0.42.3"
},
"positions": [

View File

@@ -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);
}
}

View File

@@ -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": "吉吉喵"

View File

@@ -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",