mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-03-19 03:59:51 +08:00
1437 lines
52 KiB
JavaScript
1437 lines
52 KiB
JavaScript
(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();
|
||
}
|
||
|
||
})();
|