308 lines
10 KiB
JavaScript
308 lines
10 KiB
JavaScript
(async function () {
|
||
// 脚本配置参数
|
||
// const ACTIVITY_LOCATION = { x: "1200.0", y: "1500.0" }; // 活动坐标
|
||
const PATH_FILE_START = "assets/pathing/start.json"; // 地图追踪路径文件
|
||
const PATH_FILE_CONTINUE = "assets/pathing/continue.json"; // 地图追踪路径文件
|
||
|
||
await sleep(1000);
|
||
|
||
log.info("自动吃金币活动, 启动!")
|
||
|
||
// 1. 脚本开始前确保在主界面
|
||
log.info("确保游戏在主界面状态");
|
||
await genshin.returnMainUi();
|
||
await sleep(1000);
|
||
|
||
// 在循环前添加游戏次数限制
|
||
// const MAX_GAMES = 2;
|
||
const MAX_GAMES = typeof (settings.max_games) === 'undefined' ? 20 : parseInt(settings.max_games, 10);
|
||
let gameCount = 0;
|
||
|
||
log.info("最大游戏次数设定: {MAX_GAMES}次", MAX_GAMES)
|
||
|
||
|
||
// 只要积分未满且游戏次数未达上限,就循环进行匹配和游戏
|
||
while (gameCount < MAX_GAMES) {
|
||
gameCount++; // 增加游戏计数
|
||
log.info("开始第{count}场游戏", gameCount);
|
||
|
||
// 2. 使用地图追踪走到活动入口
|
||
log.info("正在使用地图追踪前往活动入口");
|
||
try {
|
||
// 运行路径追踪脚本
|
||
if (gameCount == 1) {
|
||
await pathingScript.runFile(PATH_FILE_START);
|
||
} else {
|
||
await pathingScript.runFile(PATH_FILE_CONTINUE);
|
||
}
|
||
|
||
log.info("已到达活动入口");
|
||
} catch (error) {
|
||
log.error("地图追踪失败: {error}", error);
|
||
return;
|
||
}
|
||
|
||
// 3. 检测F键交互窗口 - 使用正确的OCR方法
|
||
let foundActivity = false;
|
||
for (let i = 0; i < 10; i++) { // 最多尝试10次
|
||
// 获取游戏截图
|
||
const screenshot = captureGameRegion();
|
||
|
||
// 对整个区域进行OCR - 使用ocrThis
|
||
const activityTextRegions = screenshot.findMulti(RecognitionObject.ocrThis);
|
||
|
||
// 遍历所有OCR结果
|
||
for (let j = 0; j < activityTextRegions.count; j++) {
|
||
const region = activityTextRegions[j];
|
||
|
||
if (region.text.includes("跨界挑战")) {
|
||
log.info("检测到活动入口");
|
||
foundActivity = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (foundActivity) break;
|
||
|
||
keyPress('W');
|
||
moveMouseBy(0, 100); // 轻微移动视角帮助识别
|
||
await sleep(1000);
|
||
}
|
||
|
||
// 4. 按F进入活动界面
|
||
log.info("进入活动界面");
|
||
keyPress("F");
|
||
await sleep(2000); // 等待界面加载
|
||
|
||
// 5. 精确识别积分信息
|
||
const scoreRegion = captureGameRegion().deriveCrop(
|
||
1248, // x
|
||
360, // y
|
||
150, // width
|
||
30 // height
|
||
);
|
||
|
||
// 对积分区域进行OCR
|
||
const scoreResults = scoreRegion.findMulti(RecognitionObject.ocrThis);
|
||
|
||
let currentScore = 0;
|
||
let maxScore = 0;
|
||
let scoreFound = false;
|
||
// 遍历所有识别结果
|
||
for (let i = 0; i < scoreResults.count; i++) {
|
||
const res = scoreResults[i];
|
||
|
||
// 使用正则表达式匹配积分格式
|
||
const match = res.text.match(/(\d+)\s*\/\s*(\d+)/);
|
||
if (match && match.length >= 3) {
|
||
currentScore = parseInt(match[1]);
|
||
maxScore = parseInt(match[2]);
|
||
scoreFound = true;
|
||
break;
|
||
}
|
||
}
|
||
if (!scoreFound) {
|
||
log.error("未识别到积分信息");
|
||
// await genshin.returnMainUi();
|
||
return;
|
||
}
|
||
log.info("积分状态: {current}/{max}", currentScore, maxScore);
|
||
if (currentScore >= maxScore) {
|
||
log.info("PVP活动已完成");
|
||
// notification.send("PVP活动已完成");
|
||
await genshin.returnMainUi();
|
||
await sleep(1000);
|
||
return;
|
||
}
|
||
|
||
|
||
// 6. 点击开始匹配
|
||
log.info("匹配挑战");
|
||
// 假设开始按钮在屏幕中间下方位置
|
||
click(1560, 1012);
|
||
await sleep(1000);
|
||
|
||
// 7. 等待并确认匹配
|
||
let matchFound = false,matchFound_1st = false; //matchFound_1st:确认按钮是否点击过
|
||
let matchTimeout = 0; //联机确认按钮超时等待(单位:秒)
|
||
let beRefusedCount = 0; //被拒绝次数
|
||
for (let i = 0; i < 60; i++) { // 最多等待60秒
|
||
const confirmRegion = captureGameRegion().deriveCrop(
|
||
1037,
|
||
706,
|
||
280,
|
||
64
|
||
);
|
||
|
||
// 执行OCR识别
|
||
const confirmResults = confirmRegion.findMulti(RecognitionObject.ocrThis);
|
||
log.info("匹配确认区域OCR识别结果数量: {count}", confirmResults.count);
|
||
|
||
/*处理联机确认按钮
|
||
执行逻辑:(如有报错,自己改 或者 反馈naralan0502@gmail.com)
|
||
如果OCR识别结果数量等于0,判断是否已经点击过确认按钮(通过变量matchFound_1st确认)
|
||
是:超时等待时长matchTimeout++,若超时等待时长==13,设置matchFound为true,跳出循环
|
||
否:继续循环
|
||
如果OCR识别结果数量大于0,遍历所有识别结果
|
||
如果存在确认按钮,设置变量matchFound_1st = true,超时等待t=0
|
||
*/
|
||
if(confirmResults.count){
|
||
// 遍历所有识别结果
|
||
for (let j = 0; j < confirmResults.count; j++) {
|
||
const region = confirmResults[j];
|
||
// log.info("匹配确认区域OCR结果:位置({x},{y},{w},{h}), 文本: {text}",
|
||
// region.x, region.y, region.width, region.height, region.text);
|
||
|
||
if (region.text.includes("接受")) {
|
||
click(1182, 737); // 点击确认按钮
|
||
if(matchFound_1st && (++beRefusedCount >= 3)) log.info("兄啊有点点背,被拒绝了{count}次诶", beRefusedCount);
|
||
matchFound_1st = true;
|
||
log.info("匹配成功, 点击接受");
|
||
matchTimeout = 0;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
else{
|
||
if(matchFound_1st && (++matchTimeout == 13)) { //超时等待13s(游戏内联机确认超时时长10s+冷却CD3s)
|
||
matchFound = true;
|
||
log.info("点击确认成功");
|
||
break;
|
||
}
|
||
}
|
||
|
||
await sleep(1000);
|
||
}
|
||
|
||
if (!matchFound) {
|
||
notification.error("匹配超时");
|
||
return;
|
||
}
|
||
|
||
// 7 等待进入游戏(直到出现"第1回合"提示)
|
||
let roundStarted = false;
|
||
const roundStartTime = Date.now();
|
||
const ROUND_TIMEOUT = 90 * 1000; // 90秒超时
|
||
|
||
while (!roundStarted && Date.now() - roundStartTime < ROUND_TIMEOUT) {
|
||
const roundRegion = captureGameRegion().deriveCrop(
|
||
770,
|
||
246,
|
||
373,
|
||
60
|
||
);
|
||
|
||
const roundText = roundRegion.find(RecognitionObject.ocrThis);
|
||
if (roundText && roundText.text && roundText.text.includes("第1回合")) {
|
||
log.info("游戏开始");
|
||
roundStarted = true;
|
||
break;
|
||
}
|
||
|
||
await sleep(1000);
|
||
}
|
||
|
||
if (!roundStarted) {
|
||
log.error("未检测到回合开始提示");
|
||
notification.error("进入游戏失败");
|
||
return;
|
||
}
|
||
|
||
// 8. 进入游戏后模拟操作
|
||
log.info("开始模拟操作");
|
||
|
||
// 随机选择操作
|
||
const actions = [
|
||
// Shift+W 冲刺前进1秒
|
||
async () => {
|
||
keyDown("SHIFT");
|
||
keyDown("W");
|
||
await sleep(1000);
|
||
keyUp("W");
|
||
keyUp("SHIFT");
|
||
},
|
||
// Shift+A 冲刺左移1秒
|
||
async () => {
|
||
keyDown("SHIFT");
|
||
keyDown("A");
|
||
await sleep(1000);
|
||
keyUp("A");
|
||
keyUp("SHIFT");
|
||
},
|
||
// Shift+S 冲刺后退1秒
|
||
async () => {
|
||
keyDown("SHIFT");
|
||
keyDown("S");
|
||
await sleep(1000);
|
||
keyUp("S");
|
||
keyUp("SHIFT");
|
||
},
|
||
// Shift+D 冲刺右移1秒
|
||
async () => {
|
||
keyDown("SHIFT");
|
||
keyDown("D");
|
||
await sleep(1000);
|
||
keyUp("D");
|
||
keyUp("SHIFT");
|
||
},
|
||
// 空格跳跃1秒
|
||
async () => {
|
||
keyDown("SPACE");
|
||
await sleep(1000);
|
||
keyUp("SPACE");
|
||
},
|
||
// 1秒内按两下E(元素战技)
|
||
async () => {
|
||
// 第一次按E
|
||
keyPress("E");
|
||
await sleep(700); // 短暂间隔
|
||
|
||
// 第二次按E
|
||
keyPress("E");
|
||
await sleep(300); // 总时间1秒
|
||
}
|
||
];
|
||
|
||
const startTime = Date.now();
|
||
const MAX_GAME_DURATION = 300 * 1000;
|
||
|
||
while (Date.now() - startTime < MAX_GAME_DURATION) {
|
||
// 在屏幕顶部中央检测"挑战完成"文本
|
||
const completionRegion = captureGameRegion().deriveCrop(
|
||
800, 180, 320, 100
|
||
);
|
||
|
||
const completionResults = completionRegion.findMulti(RecognitionObject.ocrThis);
|
||
let challengeCompleted = false;
|
||
|
||
// 遍历识别结果
|
||
for (let i = 0; i < completionResults.count; i++) {
|
||
const region = completionResults[i];
|
||
if (region.text.includes("挑战完成")) {
|
||
challengeCompleted = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (challengeCompleted) {
|
||
log.info("挑战完成");
|
||
break;
|
||
}
|
||
// 随机执行一个操作
|
||
const action = actions[Math.floor(Math.random() * actions.length)];
|
||
await action();
|
||
|
||
}
|
||
|
||
await sleep(20000);
|
||
await genshin.returnMainUi();
|
||
await sleep(1000);
|
||
await genshin.returnMainUi();
|
||
}
|
||
|
||
log.info("已达到最大游戏次数{max}次", MAX_GAMES);
|
||
return;
|
||
|
||
|
||
})();
|