Files
bettergi-scripts-list/repo/js/AutoMonday/main.js
江紫烟owo a0617b3898 AutoMonday - V1.4版本更新 (#2790)
* AutoMonday - V1.4版本更新

1. 添加了每月兑换粉球蓝球的功能
2. 修复了一些bug

* Auto Monday- 1.4版本更新

做了些许改动
2026-01-28 15:34:25 +08:00

1437 lines
52 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
(async function () {
// ===== 1. 预处理部分 =====
// 人机验证
if (!settings.ifCheck) { log.error("请阅读readme文件并做好相关设置后再运行此脚本"); return; }
//初始化配置
var TEAM;
var Material = settings.Material;
const actiontime = 180;//最大等待时间,单位秒
const BH = `assets/RecognitionObject/${Material}.png`;
const ZHIBIANYI = "assets/RecognitionObject/zhibian.png";
const CHA = "assets/RecognitionObject/cha.png";
const xingChen = "assets/RecognitionObject/星尘.png";
const ifAkf = settings.ifAkf;
const chargingMethod = settings.chargingMethod;
const ifCooking = settings.ifCooking;
const ifduanZao = settings.ifduanZao;
const ifShouling = settings.ifShouling;
const ifMijing = settings.ifMijing;
const ifbuyNet = settings.ifbuyNet;
const ifbuyTzq = settings.ifbuyTzq;
const ifPink = settings.ifPink;
const ifBlue = settings.ifBlue;
const ifChange = ifPink || ifBlue;
const ifZBY = settings.ifZBY;
const ifYB = settings.ifYB;
const food = settings.food; // 要烹饪的食物
const cookCount = settings.cookCount;//烹饪数量
const mineral = settings.mineral;// 矿石种类
const mineralFile = `assets/RecognitionObject/${mineral}.png`;// 矿石模板路径
const BossPartyName = settings.BossPartyName;// 战斗队伍
let mijingCount = 1;// 自动秘境计数
// OCR对象用于检测战斗文本
const ocrRo2 = RecognitionObject.Ocr(0, 0, 1920, 1080);
// 创建材质到ITEM的映射表
// 养成道具=1食物=2材料=3
const materialToItemMap = {
"牛角": 1,
"苹果": 2, "日落果": 2, "泡泡桔": 2,
"白铁块": 3, "水晶块": 3, "薄荷": 3, "菜": 3,
"鸡腿": 3, "蘑菇": 3, "鸟蛋": 3, "兽肉": 3, "甜甜花": 3
};
// 直接通过映射获取ITEM值未匹配时默认0
const ITEM = materialToItemMap[Material] || 0;
if (ifZBY && chargingMethod == "法器角色充能" && (!settings.TEAMname || settings.TEAMname.trim() === "")) {
log.error("您选择了法器角色充能,请在配置页面填写包含法器角色的队伍名称!!!");
return;// 没选就报错后停止
}
//检查用户是否配置队伍
if (ifZBY && ifAkf && (!settings.TEAMname || settings.TEAMname.trim() === "")) {
log.error("您选择了拥有爱可菲,请在配置页面填写包含爱可菲的队伍名称!!!");
return;// 没选就报错后停止
}
TEAM = settings.TEAMname;
const username = settings.username || "默认账户";
const cdRecordPath = `record/${username}_cd.txt`;// 修改CD记录文件路径包含用户名
// 定义任务列表
const tasks = [
{ condition: ifZBY, func: autoZhibian, name: "质变仪" },
{ condition: ifYB, func: Jingdie, name: "晶蝶诱捕装置" },
{ condition: ifCooking, func: Cooking, name: "做菜" },
{ condition: ifduanZao, func: duanZao, name: "锻造" },
{ condition: ifShouling, func: hitBoss, name: "首领" },
{ condition: ifMijing, func: AutoDomain, name: "秘境" },
{ condition: ifbuyNet, func: buyNet, name: "购买四方八方之网" },
{ condition: ifbuyTzq, func: buyTzq, name: "购买投资券" },
{ condition: ifChange, func: getPinkandBlue, name: "粉球篮球兑换" }
];
// ===== 2. 子函数定义部分 =====
/**
* 封装函数,执行图片识别及点击操作(测试中,未封装完成,后续会优化逻辑)
* @param {string} imagefilePath - 模板图片路径
* @param {number} timeout - 超时时间(秒)
* @param {number} afterBehavior - 识别后行为(0:无,1:点击,2:按F键)
* @param {number} debugmodel - 调试模式(0:关闭,1:详细日志)
* @param {number} xa - 识别区域X坐标
* @param {number} ya - 识别区域Y坐标
* @param {number} wa - 识别区域宽度
* @param {number} ha - 识别区域高度
* @param {boolean} clickCenter - 是否点击目标中心
* @param {number} clickOffsetX - 点击位置X轴偏移量
* @param {number} clickOffsetY - 点击位置Y轴偏移量
* @param {number} tt - 匹配阈值(0-1)
*/
async function imageRecognitionEnhanced(
imagefilePath = "空参数",
timeout = 10,
afterBehavior = 0,
debugmodel = 0,
xa = 0,
ya = 0,
wa = 1920,
ha = 1080,
clickCenter = false, // 新增:是否点击中心
clickOffsetX = 0, // 新增X轴偏移量
clickOffsetY = 0, // 新增Y轴偏移量
tt = 0.8
) {
// 参数验证
if (xa + wa > 1920 || ya + ha > 1080) {
log.info("图片区域超出屏幕范围");
return { found: false, error: "区域超出屏幕范围" };
}
const startTime = Date.now();
let captureRegion = null;
let result = { found: false };
try {
// 读取模板图像
const templateImage = file.ReadImageMatSync(imagefilePath);
if (!templateImage) {
throw new Error("无法读取模板图像");
}
const Imagidentify = RecognitionObject.TemplateMatch(templateImage, true);
if (tt !== 0.8) {
Imagidentify.Threshold = tt;
Imagidentify.InitTemplate();
}
// 循环尝试识别
for (let attempt = 0; attempt < 10; attempt++) {
if (Date.now() - startTime > timeout * 1000) {
if (debugmodel === 1) {
log.info(`${timeout}秒超时退出,未找到图片`);
}
break;
}
captureRegion = captureGameRegion();
if (!captureRegion) {
await sleep(200);
continue;
}
try {
const croppedRegion = captureRegion.DeriveCrop(xa, ya, wa, ha);
const res = croppedRegion.Find(Imagidentify);
if (res.isEmpty()) {
if (debugmodel === 1) {
log.info("识别图片中...");
}
} else {
// 计算基准点击位置(目标的左上角)
let clickX = res.x + xa;
let clickY = res.y + ya;
// 如果要求点击中心,计算中心点坐标
if (clickCenter) {
clickX += Math.floor(res.width / 2);
clickY += Math.floor(res.height / 2);
}
// 应用自定义偏移量
clickX += clickOffsetX;
clickY += clickOffsetY;
if (debugmodel === 1) {
log.info("计算后点击位置:({x},{y})", clickX, clickY);
}
// 执行识别后行为
if (afterBehavior === 1) {
await sleep(1000);
click(clickX, clickY);
} else if (afterBehavior === 2) {
await sleep(1000);
keyPress("F");
}
result = {
x: clickX,
y: clickY,
w: res.width,
h: res.height,
found: true
};
break;
}
} finally {
if (captureRegion) {
captureRegion.dispose();
captureRegion = null;
}
}
await sleep(200);
}
} catch (error) {
log.info(`图像识别错误: ${error.message}`);
result.error = error.message;
}
return result;
}
/**
* 文字OCR识别封装函数支持空文本匹配任意文字
* @param {string} text - 要识别的文字,默认为"空参数",空字符串会匹配任意文字
* @param {number} timeout - 超时时间单位为秒默认为10秒
* @param {number} afterBehavior - 点击模式0=不点击1=点击文字位置2=按F键默认为0
* @param {number} debugmodel - 调试模式0=无输出1=基础日志2=详细输出3=立即返回默认为0
* @param {number} x - OCR识别区域起始X坐标默认为0
* @param {number} y - OCR识别区域起始Y坐标默认为0
* @param {number} w - OCR识别区域宽度默认为1920
* @param {number} h - OCR识别区域高度默认为1080
* @param {number} matchMode - 匹配模式0=包含匹配1=精确匹配默认为0
* @returns {object} 包含识别结果的对象 {text, x, y, found}
*/
async function textOCREnhanced(
text = "空参数",
timeout = 10,
afterBehavior = 0,
debugmodel = 0,
x = 0,
y = 0,
w = 1920,
h = 1080,
matchMode = 0
) {
const startTime = Date.now();
const timeoutMs = timeout * 1000;
let lastResult = null;
let captureRegion = null; // 用于存储截图对象
// 只在调试模式1下输出基本信息
if (debugmodel === 1) {
if (text === "") {
log.info(`OCR: 空文本模式 - 匹配任意文字`);
} else if (text === "空参数") {
log.warn(`OCR: 使用默认参数"空参数"`);
}
}
while (Date.now() - startTime < timeoutMs) {
try {
// 获取截图并进行OCR识别
captureRegion = captureGameRegion();
const resList = captureRegion.findMulti(RecognitionObject.ocr(x, y, w, h));
// 遍历识别结果
for (let i = 0; i < resList.count; i++) {
const res = resList[i];
// 检查是否匹配
let isMatched = false;
if (text === "") {
// 空文本匹配任意文字
isMatched = true;
} else if (matchMode === 1) {
// 精确匹配
isMatched = res.text === text;
} else {
// 包含匹配(默认)
isMatched = res.text.includes(text);
}
if (isMatched) {
// 只在调试模式1下输出匹配成功信息
if (debugmodel === 1) {
log.info(`OCR成功: "${res.text}" 位置(${res.x},${res.y})`);
}
// 调试模式3: 立即返回
if (debugmodel === 3) {
// 释放内存
if (captureRegion) {
captureRegion.dispose();
}
return { text: res.text, x: res.x, y: res.y, found: true };
}
// 执行后续行为
switch (afterBehavior) {
case 1: // 点击文字位置
await sleep(1000);
click(res.x, res.y);
break;
case 2: // 按F键
await sleep(100);
keyPress("F");
break;
default:
// 不执行任何操作
break;
}
// 记录最后一个匹配结果但不立即返回
lastResult = { text: res.text, x: res.x, y: res.y, found: true };
}
}
// 释放截图对象内存
if (captureRegion) {
captureRegion.dispose();
}
// 如果找到匹配结果,根据调试模式决定是否立即返回
if (lastResult && debugmodel !== 2) {
return lastResult;
}
// 短暂延迟后继续下一轮识别
await sleep(100);
} catch (error) {
// 发生异常时释放内存
if (captureRegion) {
captureRegion.dispose();
}
log.error(`OCR异常: ${error.message}`);
await sleep(100);
}
}
if (debugmodel === 1) {
// 超时处理
if (text === "") {
log.info(`OCR超时: ${timeout}秒内未找到任何文字`);
} else {
log.info(`OCR超时: ${timeout}秒内未找到"${text}"`);
}
}
// 返回最后一个结果或未找到
return lastResult || { found: false };
}
//判断队内角色
async function includes(characterName) {
var avatars = getAvatars();
for (let i = 0; i < avatars.length; i++) {
if (avatars[i] === characterName) {
await keyPress(String(i + 1));
await sleep(1500);
return true;
}
}
return false;
}
//兑换功能函数,用于自动完成兑换操作
async function Exchange(exchangeObject, objName) {
try {
await sleep(1000);
moveMouseTo(1900, 205);
await leftButtonDown();
await sleep(1500);
await leftButtonUp();
let object = await imageRecognitionEnhanced(exchangeObject, 5, 1, 0, 496, 224, 556, 221, true);
if (!object.found) {
log.warn("未找到物品:{objName},可能本月已兑换", objName);
moveMouseTo(1900, 210);
await sleep(800);
await leftButtonDown();
await sleep(800);
moveMouseTo(1900, 960);
await sleep(800);
await leftButtonUp();
let waitObj = await imageRecognitionEnhanced(`assets/RecognitionObject/待刷新${objName}.png`, 5, 0, 0, 441, 163, 1350, 829, true);
if (waitObj.found) {
log.info("在已兑换的物品中找到了{objName}", objName);
return true;
} else {
log.error("经过查找仍未找到物品:{objName}", objName);
return false;
}
}
await sleep(1000);
// 识别"兑换"文字按钮的位置
let duiHuan = await textOCREnhanced("兑换", 5, 0, 0, 1123, 762, 115, 40, 1);
// 如果找到"兑换"按钮,则执行点击操作
if (duiHuan.found) {
// 连续点击指定位置4次每次间隔150毫秒
for (let i = 0; i < 4; i++) {
await click(1290, 600);
await sleep(150);
}
// 最后点击"兑换"按钮
await click(duiHuan.x, duiHuan.y);
log.info("本月{objName}已完成兑换", objName);
await sleep(1000);
await keyPress("VK_ESCAPE");
return true;
} else {
log.warn("未找到兑换按钮,请重试");
return false;
}
} catch (error) {
if (error.message === "A task was canceled." || error.message === "取消自动任务") { throw error; }
log.error("执行粉球篮球兑换过程中出现错误: {error}", error.message);
}
}
// 等待质变仪完成提示出现。 若超时则强制结束流程。
async function waitTransformer(deployed) {
var startTime = new Date();
await sleep(500);
var NowTime = new Date();
var getFood = 0;
var lastIncrementTime = 0; // 上次增加getFood的时间
const intervalTime = 3000; // 3秒的时间间隔单位为毫秒
// 质变仪判断逻辑
if (deployed) {
await sleep(800);
await keyDown("S");
await sleep(500);
await keyUp("S");
if (chargingMethod == "法器角色充能") {
const ifbblIn = await includes("芭芭拉");
if (!ifbblIn) { throw new Error("队伍中未包含角色:芭芭拉"); }
}
while ((NowTime - startTime) < actiontime * 1000) {
const ocrRes = await textOCREnhanced("质变产生了以下物质", 0.7, 1, 0, 539, 251, 800, 425);
if (ocrRes.found) {
click(970, 760);
if (!ifAkf) { return true; }
await sleep(150);
break;
}
if (chargingMethod == "法器角色充能") {
leftButtonClick();
await sleep(150);
}
NowTime = new Date();
}
}
// 厨艺机关判断逻辑
if (ifAkf) {
if ((chargingMethod == "电气水晶充能")) {
await AutoPath("全自动爱可菲");//厨艺机关的部署动作用路径追踪执行
} else if (chargingMethod == "法器角色充能") {
const ifakfIn = await includes("爱可菲");
if (!ifakfIn) { throw new Error("队伍中未包含角色:爱可菲"); }
keyDown("E");
await sleep(1000);
keyUp("E");
await sleep(800);
await includes("芭芭拉");
}
while ((NowTime - startTime) < actiontime * 1000) {
const ifEarn = await textOCREnhanced("获得", 0.2, 0, 3, 159, 494, 75, 44);
if (ifEarn.found) {
const currentTime = new Date().getTime();
if (currentTime - lastIncrementTime >= intervalTime) {
getFood++;
lastIncrementTime = currentTime;
log.warn(`获得料理数量: ${getFood}`);
if (getFood >= 10) {
log.warn("获得料理数量已达10结束流程");
await genshin.returnMainUi(); // 提前退出循环
return true;
}
}
}
if (chargingMethod == "法器角色充能") {
leftButtonClick();
await sleep(150);
}
await sleep(50);
NowTime = new Date();
}
}
await genshin.returnMainUi();
log.error(`${actiontime}秒超时,结束流程!`);
}
//放置质变仪
async function deployTransformer() {
//放置质变仪
await sleep(500);
await keyPress("B");
await sleep(1000);
await handleExpiredItems(); //处理过期物品
await sleep(1000);
await click(1067, 57);//点开背包,可做图像识别优化
const bagOk = await textOCREnhanced("小道具", 3, 0, 3, 126, 17, 99, 53); if (!bagOk.found) { throw new Error("未打开'小道具'页面,请确保背包已正确打开并切换到小道具标签页"); }//确认在小道具界面
await sleep(500);
const ZbyResult = await imageRecognitionEnhanced(ZHIBIANYI, 1, 1, 0);//识别质变仪图片
if (!ZbyResult.found) {
await genshin.returnMainUi();
log.warn("'质变仪CD中'或'未找到质变仪!'");
return false;//质变仪找不到就直接退出
} else {
await sleep(1000);
await click(1699, 1004);
await sleep(1000);//点击部署操作
await genshin.returnMainUi();
}
return true;
}
//参量质变仪放入“薄荷”交互流程
async function insertMaterial() {
log.info("请确保所选材料足够,现在开始部署!!");
//检测并进入质变仪界面
await middleButtonClick();
await sleep(1000);
let Fmeun = await textOCREnhanced("参量质变仪", 2, 2, 0, 1205, 508, 140, 53);//单条F检测
await keyPress("F");
let CHAx = await imageRecognitionEnhanced(CHA, 3, 0, 0, 1766, 3, 140, 90);
if (!Fmeun.found && !CHAx.found) { return false; }
//检测是否到达材料页面
const startTransform = await textOCREnhanced("进行质变", 3, 0, 3, 1675, 994, 150, 50); if (!startTransform.found) { throw new Error("质变仪页面未打开"); }//单条F检测
await sleep(500);
let itemResult;
switch (ITEM) {
case 1:
await click(863, 47); // 初始化与'1养成道具'相关的设置或资源
itemResult = await textOCREnhanced("养成道具", 3, 0, 3, 120, 19, 240, 50); if (!itemResult.found) { throw new Error("'养成道具'页面未打开"); }
break;
case 2:
await click(959, 45);// 初始化与'2食物'相关的设置或资源
itemResult = await textOCREnhanced("食物", 3, 0, 3, 124, 16, 93, 63); if (!itemResult.found) { throw new Error("'食物'页面未打开"); }
break;
case 3:
await click(1050, 50); // 初始化与'3材料'相关的设置或资源
itemResult = await textOCREnhanced("材料", 3, 0, 3, 124, 16, 93, 63); if (!itemResult.found) { throw new Error("'材料'页面未打开"); }
break;
default:
// 处理未知ITEM值的情况
break;
}
//滚轮预操作
await moveMouseTo(1287, 131);
await sleep(100);
await leftButtonDown();
await sleep(100);
await moveMouseTo(1287, 161);
// 薄荷图片检测
let YOffset = 0; // Y轴偏移量根据需要调整
const maxRetries = 20; // 最大重试次数
let retries = 0; // 当前重试次数
while (retries < maxRetries) {
const ifBh = await imageRecognitionEnhanced(BH, 1, 0, 0, 115, 115, 1155, 845);
if (ifBh.found) {
await leftButtonUp();
await sleep(500);
await click(ifBh.x, ifBh.y);
await sleep(1000);
await click(440, 1008); //选择最大数量
await sleep(1000);
await click(1792, 1019); //质变按钮
const zbPanel = await textOCREnhanced("参量质变仪", 3, 0, 3, 828, 253, 265, 73); if (!zbPanel.found) { log.error("单种材料不足,退出!"); }
await sleep(1000);
await click(1183, 764); //确认 ;
await sleep(1000);
await genshin.returnMainUi();
return true
}
retries++; // 重试次数加1
//滚轮操作
YOffset += 50;
await sleep(500);
if (retries === maxRetries || 161 + YOffset > 1080) {
await leftButtonUp();
await sleep(100);
await moveMouseTo(1287, 131);
await genshin.returnMainUi();
log.error("未找到材料!");
}
await moveMouseTo(1287, 161 + YOffset);
await sleep(300);
}
log.info("材料准备完成,开始任务!!!");
}
//切换队伍
async function switchPartyIfNeeded(partyName) {
if (!partyName) {
await genshin.returnMainUi();
return;
}
try {
log.info("正在尝试切换至" + partyName);
if (!await genshin.switchParty(partyName)) {
log.info("切换队伍失败,前往七天神像重试");
await genshin.tpToStatueOfTheSeven();
await genshin.switchParty(partyName);
}
} catch {
log.error("队伍切换失败,可能处于联机模式或其他不可切换状态");
notification.error(`队伍切换失败,可能处于联机模式或其他不可切换状态`);
await genshin.returnMainUi();
}
}
//寻路函数
async function AutoPath(locationName) {
try {
let filePath = `assets/${locationName}.json`;
await pathingScript.runFile(filePath);
} catch (error) {
log.error(`执行 ${locationName} 路径时发生错误`);
}
}
// 背包过期物品识别
async function handleExpiredItems() {
const ifGuoqi = await textOCREnhanced("物品过期", 1.5, 0, 3, 870, 280, 170, 40);
if (ifGuoqi.found) {
log.info("检测到过期物品,正在处理...");
await sleep(500);
await click(980, 750); // 点击确认按钮,关闭提示
} else {
log.info("未检测到过期物品");
}
}
// 获取当前时间七天后的时间戳
function getSevenDaysLater() {
const now = new Date();
const sevenDaysLater = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); // 当前时间 + 7天
return sevenDaysLater.toISOString();
}
// 返回当前时间的下周一四点的时间戳
function getNextMonday4AMISO() {
const now = new Date();
// 获取当前是星期几
const currentDay = now.getDay();
// 计算距离下周一还有几天
let daysUntilMonday = 1 - currentDay;
if (daysUntilMonday <= 0) {
daysUntilMonday += 7;
}
// 创建下周一4点的日期对象
const nextMonday4AM = new Date(now);
nextMonday4AM.setDate(now.getDate() + daysUntilMonday);
nextMonday4AM.setHours(4, 0, 0, 0);
return nextMonday4AM.toISOString();
}
// 返回下月1号四点的时间戳
function getNextMonthFirst4AMISO() {
const now = new Date();
// 获取当前月份并加一个月
let nextMonth = new Date(now.getFullYear(), now.getMonth() + 1, 1, 4, 0, 0, 0);
return nextMonth.toISOString();
}
// 检查文件是否存在
async function checkFileExists(filePath) {
try {
// 尝试读取文件,如果成功则文件存在
await file.readText(filePath);
return true;
} catch (e) {
// 如果读取失败,则文件可能不存在
return false;
}
}
// 读取CD记录
async function readCDRecords() {
let records = {};
// 使用基础方法检查文件是否存在
const fileExists = await checkFileExists(cdRecordPath);
if (fileExists) {
try {
const content = await file.readText(cdRecordPath);
const lines = content.split('\n');
for (const line of lines) {
if (line.trim()) {
const [name, timestamp] = line.split('::');
records[name] = timestamp;
}
}
} catch (e) {
log.error(`读取CD记录失败: ${e}`);
}
}
return records;
}
// 写入CD记录
async function writeCDRecords(records) {
let content = '';
for (const name in records) {
content += `${name}::${records[name]}\n`;
}
try {
// 尝试创建目录(如果环境支持)
try {
if (typeof file.mkdir === 'function') {
file.mkdir('record');
}
} catch (e) {
// 忽略目录创建错误
}
await file.writeText(cdRecordPath, content);
} catch (e) {
log.error(`写入CD记录失败: ${e}`);
}
}
// 检查路线是否可执行CD是否已刷新
function isRouteAvailable(routeName, cdRecords) {
const now = new Date();
// 如果记录中没有该路线,说明是第一次执行,可以执行
if (!cdRecords[routeName]) {
return true;
}
// 检查CD时间是否已过
const cdTime = new Date(cdRecords[routeName]);
return now >= cdTime;
}
// 自动战斗函数
async function autoFight(timeout) {
const cts = new CancellationTokenSource();
dispatcher.runTask(new SoloTask("AutoFight"), cts);
const startTime = Date.now();
let fightResult = false;
while (Date.now() - startTime < timeout) {
let captureRegion = null;
try {
captureRegion = captureGameRegion();
if (recognizeFightText(captureRegion)) {
fightResult = true;
break;
}
} finally {
// 确保捕获的区域被正确释放
if (captureRegion) {
captureRegion.dispose();
captureRegion = null;
}
}
await sleep(1000);
}
cts.cancel();
return fightResult;
}
// 战斗文本识别函数
function recognizeFightText(captureRegion) {
try {
const result = captureRegion.find(ocrRo2);
const text = result.text;
const keywords = ["挑战成功", "达成", "挑战达成"];
for (const keyword of keywords) {
if (text.includes(keyword)) {
return true;
}
}
return false;
} catch (error) {
log.error("OCR识别出错: {0}", error);
return false;
}
}
// 自动秘境
async function fuben() {
await genshin.tp(1167.9833984375, 662.7353515625);// 太山府
await sleep(1500);
keyPress("F");
await textOCREnhanced("单人挑战", 8, 1, 0, 1615, 990, 220, 50);// 等待“单人挑战”出现
await sleep(10);
await textOCREnhanced("开始挑战", 8, 1, 0, 1615, 990, 220, 50);// 等待“开始挑战”出现
await sleep(10);
await textOCREnhanced("地脉异常", 10, 1, 0, 840, 405, 180, 55);// 等待“地脉异常”出现
await sleep(1000);
let success;
for (let attempt = 0; attempt < 10; attempt++) {
success = await textOCREnhanced("启动", 0.5, 0, 3, 1210, 500, 85, 85);
if (success.found) {
keyPress("F");
break;
} else {
keyDown("W");
await sleep(2500);
keyUp("W");
}
}
if (!success.found) {
log.warn("未找到秘境启动按钮!");
return false;
}
}
// 晶蝶诱捕装置
async function Jingdie() {
try {
// 读取CD记录
const cdRecords = await readCDRecords();
let updatedRecords = { ...cdRecords };
const routeName = "晶蝶诱捕装置";
// 检查CD
if (!isRouteAvailable(routeName, cdRecords)) {
log.info(routeName + "CD未刷新跳过本次执行");
return;
}
keyPress("M");
await sleep(1000);
// 判断是否诱捕完成
const res2 = await textOCREnhanced("晶蝶诱捕装置", 1, 0, 3, 0, 0, 360, 500);
if (!res2.found) {
log.warn("诱捕未完成,不执行后续操作");
await genshin.returnMainUi();
return;
} else {
//执行晶蝶诱捕装置代码
await AutoPath("晶蝶诱捕装置");
//进行交互
await sleep(1000);
keyPress("F");//领取奖励
await sleep(2000);
click(960, 900);//点击奖励弹窗
await sleep(1000);
keyPress("F");//再次启动
await sleep(1000);
click(1750, 1020);//点击启动
await sleep(1000);
click(1180, 750);//点击确认
log.info("已完成 领取晶蝶诱捕装置");
await sleep(1000);
// 更新CD记录设置为七天后
updatedRecords[routeName] = getSevenDaysLater();
await writeCDRecords(updatedRecords);
log.info("本周晶蝶诱捕装置收取完成!");
}
} catch (error) {
if (error.message === "A task was canceled." || error.message === "取消自动任务") { throw error; }
log.error("执行晶蝶诱捕任务过程中出现错误: {error}", error.message);
}
}
// 质变仪和爱可菲
async function autoZhibian() {
try {
// 读取CD记录
const cdRecords = await readCDRecords();
let updatedRecords = { ...cdRecords };
const routeName = "质变仪&爱可菲";
// 检查CD
if (!isRouteAvailable(routeName, cdRecords)) {
log.info(routeName + "CD未刷新跳过本次执行");
return;
}
await sleep(500);
await keyPress("B");
await sleep(1000);
await handleExpiredItems(); //处理过期物品
await sleep(1000);
await click(1067, 57);//点开背包,可做图像识别优化
const ifXdj = await textOCREnhanced("小道具", 3, 0, 3, 126, 17, 99, 53); if (!ifXdj.found) { throw new Error("未打开'小道具'页面,请确保背包已正确打开并切换到小道具标签页"); }//确认在小道具界面
await sleep(500);
const res1 = await imageRecognitionEnhanced(ZHIBIANYI, 1, 1, 0);//识别质变仪图片
if (res1.found) {
await genshin.returnMainUi();
log.info("质变仪CD已刷新");
} else {
log.warn("'质变仪CD中'或'未找到质变仪!'");
await genshin.returnMainUi();
return;
}
await switchPartyIfNeeded(TEAM); //切换到指定队伍
if (chargingMethod == "电气水晶充能") {
await AutoPath("全自动质变仪");
} else if (chargingMethod == "法器角色充能") {
await genshin.tp(-874.724609375, 2276.950439453125);
}
const deployed = await deployTransformer();//部署质变仪
if (!deployed) {
log.error("质变仪未找到或在cd中");
} else {
await insertMaterial();//放入材料并开始质变流程
}
await waitTransformer(deployed)//等待质变完成
log.info("任务执行完成!!!");
// 更新CD记录设置为七天后
updatedRecords[routeName] = getSevenDaysLater();
await writeCDRecords(updatedRecords);
log.info("本周质变仪&爱可菲任务已完成!");
} catch (error) {
if (error.message === "A task was canceled." || error.message === "取消自动任务") { throw error; }
log.error("执行质变仪&爱可菲任务过程中出现错误: {error}", error.message);
}
}
// 每周做菜
async function Cooking() {
try {
// 读取CD记录
const cdRecords = await readCDRecords();
let updatedRecords = { ...cdRecords };
const routeName = "每周做菜";
// 检查CD
if (!isRouteAvailable(routeName, cdRecords)) {
log.info(routeName + "CD未刷新跳过本次执行");
return;
}
await AutoPath("每周做菜");
await sleep(10);
keyDown("VK_MENU");
await sleep(500);
const res1 = await textOCREnhanced("烹饪", 5, 0, 3, 1150, 460, 155, 155);
if (res1.found) {
click(res1.x + 15, res1.y + 15);
}
await sleep(800);
keyUp("VK_MENU");
await sleep(1000);
click(145, 1015);// 筛选
await sleep(800);
click(195, 1015);// 重置
await sleep(800);
click(500, 1020);// 确认筛选
await sleep(800);
//滚轮预操作
await moveMouseTo(1287, 131);
await sleep(100);
await leftButtonDown();
await sleep(100);
await moveMouseTo(1287, 161);
let YOffset = 0; // Y轴偏移量根据需要调整
const maxRetries = 20; // 最大重试次数
let retries = 0; // 当前重试次数
while (retries < maxRetries) {
const res2 = await textOCREnhanced(food, 1, 0, 3, 116, 116, 1165, 880);
if (res2.found) {
await leftButtonUp();
await sleep(500);
await click(res2.x + 50, res2.y - 60);
await sleep(1000);
await sleep(1000);
click(1700, 1020);// 制作
await sleep(1000);
await textOCREnhanced("自动烹饪", 5, 1, 0, 725, 1000, 130, 45);
await sleep(800);
click(960, 460);
await sleep(800);
inputText(cookCount);
await sleep(800);
click(1190, 755);
await sleep(2500); // 等待烹饪完成
await genshin.returnMainUi();
log.info("本周烹饪任务已完成!");
// 更新CD记录
updatedRecords[routeName] = getNextMonday4AMISO();
await writeCDRecords(updatedRecords);
return;
}
retries++; // 重试次数加1
//滚轮操作
YOffset += 50;
await sleep(500);
if (retries === maxRetries || 161 + YOffset > 1080) {
await leftButtonUp();
await sleep(100);
await moveMouseTo(1287, 131);
await genshin.returnMainUi();
log.error("料理未找到!");
}
await moveMouseTo(1287, 161 + YOffset);
await sleep(300);
}
} catch (error) {
if (error.message === "A task was canceled." || error.message === "取消自动任务") { throw error; }
log.error("执行烹饪任务过程中出现错误: {error}", error.message);
}
}
// 每周锻造
async function duanZao() {
try {
// 读取CD记录
const cdRecords = await readCDRecords();
let updatedRecords = { ...cdRecords };
const routeName = "每周锻造";
// 检查CD
if (!isRouteAvailable(routeName, cdRecords)) {
log.info(routeName + "CD未刷新跳过本次执行");
return;
}
await AutoPath("瓦格纳");
keyDown("VK_MENU");
await textOCREnhanced("瓦格纳", 5, 1, 0, 1150, 460, 155, 155);
await sleep(800);
keyUp("VK_MENU");
click(960, 540);// 对话
await sleep(1000);
await textOCREnhanced("委托锻造", 5, 1, 0, 1150, 400, 300, 300);
await sleep(1500);
click(960, 540);// 对话
await sleep(1500);
const res1 = await textOCREnhanced("可收取", 1, 0, 3, 625, 265, 130, 50);
if (res1.found) {
click(180, 1015);// 全部领取
await sleep(1500);
click(980, 900);// 确认按钮
await sleep(1500);
click(220, 145);// 点击配方
await sleep(1000);
}
click(360, 1015);// 筛选按钮
await sleep(1500);
await textOCREnhanced("武器升级材料", 5, 1, 0, 30, 170, 410, 60);
await sleep(1500);
await imageRecognitionEnhanced(mineralFile, 10, 1, 0, 40, 210, 720, 770)
await sleep(1500);
for (let i = 0; i < 4; i++) {
click(1760, 1015);// 开始锻造
await sleep(300);
}
await genshin.returnMainUi();
log.info("本周锻造任务已完成!");
// 更新CD记录
updatedRecords[routeName] = getNextMonday4AMISO();
await writeCDRecords(updatedRecords);
} catch (error) {
if (error.message === "A task was canceled." || error.message === "取消自动任务") { throw error; }
log.error("执行锻造任务过程中出现错误: {error}", error.message);
}
}
// 每周首领
async function hitBoss() {
try {
// 读取CD记录
const cdRecords = await readCDRecords();
let updatedRecords = { ...cdRecords };
const routeName = "每周首领";
// 检查CD
if (!isRouteAvailable(routeName, cdRecords)) {
log.info(routeName + "CD未刷新跳过本次执行");
return;
}
await genshin.tpToStatueOfTheSeven();// 先去神像确保状态和队伍切换
await switchPartyIfNeeded(BossPartyName);
await sleep(5000);
for (let i = 1; i <= 10; i++) {
if (i % 2 == 0) { await AutoPath("爆炎树"); }
else if (i % 2 != 0) { await AutoPath("急冻树"); }
await sleep(10);
log.info("第" + i + "次首领已击败!")
}
log.info("本周首领击败任务已完成!");
// 更新CD记录
updatedRecords[routeName] = getNextMonday4AMISO();
await writeCDRecords(updatedRecords);
} catch (error) {
if (error.message === "A task was canceled." || error.message === "取消自动任务") { throw error; }
log.error("执行首领任务过程中出现错误: {error}", error.message);
}
}
// 每周秘境
async function AutoDomain() {
try {
// 读取CD记录
const cdRecords = await readCDRecords();
let updatedRecords = { ...cdRecords };
const routeName = "每周秘境";
// 检查CD
if (!isRouteAvailable(routeName, cdRecords)) {
log.info(routeName + "CD未刷新跳过本次执行");
return;
}
await genshin.tpToStatueOfTheSeven();// 先去神像确保状态和队伍切换
await switchPartyIfNeeded(BossPartyName);
await sleep(5000);
while (mijingCount <= 10) {
log.info(`正在进行第${mijingCount}次秘境挑战`);
await fuben();
// 开始自动战斗
log.info("开始自动战斗");
const fightResult = await autoFight(120000); // 120秒战斗超时
if (fightResult) {
log.info(`战斗成功!当前完成 ${mijingCount}`);
} else {
log.error("战斗失败,终止脚本");
break;
}
await sleep(1500);
mijingCount++;
}
log.info("本周秘境任务已完成!");
// 更新CD记录
updatedRecords[routeName] = getNextMonday4AMISO();
await writeCDRecords(updatedRecords);
await genshin.tpToStatueOfTheSeven();// 回一次神像
await sleep(5000);
} catch (error) {
if (error.message === "A task was canceled." || error.message === "取消自动任务") { throw error; }
log.error("执行秘境任务过程中出现错误: {error}", error.message);
}
}
// 购买四方八方之网
async function buyNet() {
try {
// 读取CD记录
const cdRecords = await readCDRecords();
let updatedRecords = { ...cdRecords };
const routeName = "购买四方网";
// 检查CD
if (!isRouteAvailable(routeName, cdRecords)) {
log.info(routeName + "CD未刷新跳过本次执行");
return;
}
await AutoPath("四方八方之网");
await sleep(800);
keyPress("F");
await sleep(1300);
click(960, 540);// 对话
await sleep(1000);
await textOCREnhanced("购买", 3, 1, 0, 1320, 630, 130, 60);// 对话:购买四方八方之网
await sleep(1000);
const res1 = await textOCREnhanced("已售罄", 1, 0, 3, 1515, 920, 90, 35);
if (!res1.found) {
click(1670, 1015);
await sleep(800);
for (let i = 0; i < 7; i++) {// 拉满拉满TMD全部拉满
click(1290, 600);
await sleep(150);
}
click(1175, 780);// 点击购买
await sleep(300);
await genshin.returnMainUi();
log.info("本周四方网购买任务已完成!");
// 更新CD记录
updatedRecords[routeName] = getNextMonday4AMISO();
await writeCDRecords(updatedRecords);
} else {
log.warn("四方网CD未刷新");
}
} catch (error) {
if (error.message === "A task was canceled." || error.message === "取消自动任务") { throw error; }
log.error("执行四方网任务过程中出现错误: {error}", error.message);
}
}
// 购买投资券
async function buyTzq() {
try {
// 读取CD记录
const cdRecords = await readCDRecords();
let updatedRecords = { ...cdRecords };
const routeName = "投资券";
// 检查CD
if (!isRouteAvailable(routeName, cdRecords)) {
log.info(routeName + "CD未刷新跳过本次执行");
return;
}
await AutoPath("投资券");
await sleep(1000);
keyPress("F");
await sleep(1000);
click(960, 540);
await sleep(2000);
await textOCREnhanced("我要结算", 3, 1, 0, 1325, 550, 250, 55);
await sleep(1000);
click(960, 540);
await sleep(1000);
const notHave = await textOCREnhanced("没有投资券", 3, 0, 3, 830, 925, 160, 50);
if (notHave.found) {
click(960, 540);
await sleep(1500);
click(960, 540);
await sleep(1500);
click(1700, 1000);
await sleep(1000);
for (let i = 0; i < 8; i++) {
click(1295, 600);
await sleep(100);
}
click(1180, 780);
await sleep(1000);
await genshin.returnMainUi();
await sleep(1000);
keyPress("F");
await sleep(1000);
click(960, 540);
await sleep(1500);
await textOCREnhanced("我要结算", 3, 1, 0, 1325, 500, 250, 80);
await sleep(1000);
click(960, 540);
await sleep(1000);
}
keyPress("F");
await sleep(1000);
click(110, 185);
await sleep(1000);
click(1235, 815);
await sleep(1000);
click(1620, 1020);
await sleep(2500);
click(1620, 1020);
log.info("本周投资券已提交!");
// 更新CD记录
updatedRecords[routeName] = getNextMonday4AMISO();
await writeCDRecords(updatedRecords);
} catch (error) {
if (error.message === "A task was canceled." || error.message === "取消自动任务") { throw error; }
log.error("执行投资券过程中出现错误: {error}", error.message);
}
}
// 粉球蓝球入口
async function getPinkandBlue() {
if (ifPink) { await stardustExchange("纠缠之缘"); }
if (ifBlue) { await stardustExchange("相遇之缘"); }
await genshin.returnMainUi();
}
// 粉球蓝球兑换
async function stardustExchange(routeName) {
try {
// 读取CD记录
const cdRecords = await readCDRecords();
let updatedRecords = { ...cdRecords };
// 检查CD
if (!isRouteAvailable(routeName, cdRecords)) {
log.info(routeName + "CD未刷新跳过本次执行");
return;
}
log.info("正在进行本月{routeName}兑换……", routeName);
let ifXingChen = await imageRecognitionEnhanced(xingChen, 5, 0, 0, 1130, 355, 315, 300);
if (!ifXingChen.found) {
await genshin.returnMainUi();
await sleep(1000);
await keyPress("VK_ESCAPE");
await sleep(1000);
await textOCREnhanced("祈愿", 10, 1, 0, 318, 863, 65, 30, 1);
await textOCREnhanced("尘辉兑换", 10, 1, 0, 100, 1005, 110, 35, 1);
await textOCREnhanced("星尘兑换", 10, 1, 0, 768, 104, 260, 46, 1);
ifXingChen = await imageRecognitionEnhanced(xingChen, 5, 0, 0, 1226, 451, 100, 60);
if (!ifXingChen.found) {
await textOCREnhanced("星尘兑换", 10, 1, 0, 768, 104, 260, 46, 1);
}
await sleep(1000);
}
let getIt = await Exchange(`assets/RecognitionObject/${routeName}.png`, routeName);
if (getIt) {
// 更新CD记录
updatedRecords[routeName] = getNextMonthFirst4AMISO();
await writeCDRecords(updatedRecords);
}
} catch (error) {
if (error.message === "A task was canceled." || error.message === "取消自动任务") { throw error; }
log.error("执行粉球篮球兑换过程中出现错误: {error}", error.message);
}
}
// 版本信息
async function outputVersion() {
let scriptVersion, scriptname;
const manifestContent = file.readTextSync("manifest.json");
const manifest = JSON.parse(manifestContent);
scriptVersion = manifest.version;
scriptname = manifest.name;
log.warn(`${scriptname}V${scriptVersion}`);
}
// ===== 3. 主函数执行部分 =====
try {
//设置分辨率和缩放
setGameMetrics(1920, 1080, 1);
await genshin.returnMainUi();
await outputVersion(); // 输出版本信息
// 执行所有启用的任务
for (const task of tasks) {
if (task.condition) {
log.info("开始执行任务:{name}", task.name);
await task.func();
await sleep(10);
}
}
} catch (error) {
if (error.message === "A task was canceled." || error.message === "取消自动任务") { throw error; }
log.error(`执行过程中发生错误:${error.message}`);
} finally {
await genshin.returnMainUi();
}
})();