import { findText, findTextAndClick, findImgAndClick, waitUntilTextAppear, waitUntilImgDisappear, waitUntilImgAppear } from "../../../packages/utils/tool"; import fold_triangle from "assets/fold_triangle.png"; import check_box from "assets/check_box.png"; import exit_room from "assets/exit_room.png"; import paimon from "../../../packages/assets/imgs/paimon_menu.png"; const duration = 1000; // 默认点击等待延时 const storePath = "data/store.json" const runJS = settings.runJS; const achievementMode = settings.achievementMode; const starMode = settings.starMode; const roomID = settings.room || "37135473336"; const starRoomName = settings.starRoomName || "碰碰墙"; const userAttempts = Number(settings.thisAttempts || "0"); const useFixedAttempts = userAttempts > 0; const weekMaxExp = Number(settings.weekMaxExp || "4000"); const singleExp = Number(settings.singleExp || "270"); let weekTotal = initWeekTotal(); // 读取存档 function loadWeekData() { try { const t = file.readTextSync(storePath); return JSON.parse(t); } catch (_) { return null; } } // 保存存档 function saveWeekData(data) { file.writeTextSync(storePath, JSON.stringify(data)); } // 判断两个时间是否属于同一周 function isSameWeek(t1, t2) { const getMonday = (time) => { const d = new Date(time); const day = d.getDay(); // 0=周日 const diff = day === 0 ? -6 : 1 - day; d.setDate(d.getDate() + diff); d.setHours(0, 0, 0, 0); return d.getTime(); }; return getMonday(t1) === getMonday(t2); } // 初始化或更新 weekTotal function initWeekTotal() { const stored = loadWeekData(); const calculated = Math.ceil(weekMaxExp / singleExp); const now = Date.now(); // 无存档 -> 初始化 if (!stored) { const data = { weekMaxExp, singleExp, weekTotal: calculated, lastRunTime: now }; saveWeekData(data); return calculated; } // 跨周 -> 重置次数 if (!isSameWeek(stored.lastRunTime, now)) { stored.weekTotal = calculated; stored.lastRunTime = now; saveWeekData(stored); log.info("检测到跨周,已重置每周次数"); return calculated; } // 配置变化 -> 重算 if ( stored.weekMaxExp !== weekMaxExp || stored.singleExp !== singleExp ) { stored.weekMaxExp = weekMaxExp; stored.singleExp = singleExp; stored.weekTotal = calculated; stored.lastRunTime = now; saveWeekData(stored); return calculated; } // 正常情况,仅更新时间 stored.lastRunTime = now; saveWeekData(stored); return stored.weekTotal; } // 刷完一次 -> 计数 -1 function decreaseWeekTotal() { const stored = loadWeekData(); if (!stored) return; stored.weekTotal = Math.max(stored.weekTotal - 1, 0); stored.lastRunTime = Date.now(); saveWeekData(stored); weekTotal = stored.weekTotal; } // 升级特殊界面点击 async function findAndClickWhiteSpaceNext() { const result = await findText(["点击", "继续"],610, 950, 700, 60); if (result) { await sleep(duration); click(610, 950); } } // 折叠展开的置顶栏 async function checkAndFold() { const top_text = await findText("置顶", 1400, 650, 400, 100); if (top_text) { await waitUntilImgDisappear( fold_triangle, async () => { await findImgAndClick(fold_triangle, 1400, 650, 400, 100, 200); await sleep(duration); }, 1400, 650, 400, 100 ); } } // 查找要删除的存档 async function findSaveInList(keyword) { const maxScroll = 15; const keywords = keyword.trim().split(" "); for (let i = 0; i < maxScroll; i++) { const region = await findText( keywords, 200, 250, 1500, 700, 3 ); if (region) { return region; } moveMouseTo(890, 800); // 向下滚动 for (let count = 0; count < 5; count++) { verticalScroll(-10); } } return null; } // 清除游玩数据 async function deleteSource() { if (!achievementMode) return; await genshin.returnMainUi(); log.info("开始自动删除关卡存档"); await sleep(duration); // 打开奇域收藏 keyPress("VK_B"); await sleep(duration); await findTextAndClick("管理关卡", 960, 0, 960, 100, 50, 50); await findTextAndClick("管理", 960, 980, 960, 100, 50, 50); // 查找目标存档 const saveRegion = await findSaveInList(starRoomName); if (!saveRegion) { log.warn("未找到目标存档,跳过删除"); await genshin.returnMainUi(); return; } // 计算复选框位置 const sy = saveRegion.y - 30; await sleep(300); await findImgAndClick(check_box, 0, sy, 1480, saveRegion.height + 70, 2000); // 删除 await sleep(duration); await findTextAndClick("删除", 960, 980, 960, 100, 50, 100); await findTextAndClick("确认", 960, 600, 960, 400, 50, 100); await findTextAndClick("确认", 960, 600, 960, 400, 50, 100); log.info("关卡存档删除完成"); await sleep(duration); await genshin.returnMainUi(); } // 进入千星奇域的全部奇域页面 async function enterSourcePage() { // 1. 检测是否在房间内,在则退出 const inRoom = await findText("房间", 1500, 0, 420, 500, 5, 100); if (inRoom) { keyPress("VK_P"); await waitUntilTextAppear( "确认", async () => { await findImgAndClick(exit_room, 960, 0, 960, 540, 5000); }, 960, 600, 960, 400, 50, 100 ); await findTextAndClick("确认", 960, 600, 960, 400, 50); await genshin.returnMainUi(); keyPress("VK_F6"); } else { keyPress("VK_F6"); } await sleep(duration); } // 进入千星奇域的收藏奇域页面 async function enterStarSourcePage() { // 1. 检测是否在房间内,在则退出 const inRoom = await findText("房间", 1500, 0, 420, 500, 5, 100); if (inRoom) { keyPress("VK_P"); await waitUntilTextAppear( "确认", async () => { await findImgAndClick(exit_room, 960, 0, 960, 540, 500); }, 960, 600, 960, 400, 100 ); await findTextAndClick("确认", 960, 600, 960, 400); await genshin.returnMainUi(); keyPress("VK_B"); } else { keyPress("VK_F6"); await sleep(duration); await findTextAndClick("收藏", 0, 850, 300, 230); } await sleep(duration); } // 搜索关卡 async function searchMap() { await findTextAndClick("搜索", 1320, 0, 600, 95); await findTextAndClick("搜索", 0, 120, 1920, 60, 10, 100, 50, 200); inputText(roomID); await sleep(duration); await findTextAndClick("搜索", 0, 120, 1920, 60); await sleep(duration); click(355, 365); await sleep(duration); } // 从收藏搜索关卡 async function searchStarMap() { await checkAndFold(); await findTextAndClick("搜索", 0, 0, 1920, 120, 10, 100, 50, 200); inputText(starRoomName); await sleep(duration); await findTextAndClick("搜索", 0, 0, 1920, 120); await sleep(duration); click(420, 830); await sleep(duration); } // 创建房间 async function createRoom() { const result = await findTextAndClick("房间",960, 100, 960, 200, 2); if (!result) { await findTextAndClick("大厅", 960, 600, 960, 400, 2); await waitUntilTextAppear("房间", () => {},960, 100, 960, 200, 50, 1000); await findTextAndClick("房间",960, 100, 960, 200, 20, 50, 200); } await findText("开始游戏", 960, 540, 960, 540); click(770, 275); await sleep(duration); } // 游玩关卡 async function playMap() { const stored = loadWeekData(); const leave = stored ? stored.weekTotal : weekTotal; const total = useFixedAttempts ? userAttempts : leave; if (starMode) { await searchStarMap(); } else { await searchMap(); } await createRoom(); await findTextAndClick("开始游戏", 960, 540, 960, 540, 5, 50, 50); log.info("开始执行第{i}/{total}次奇域挑战", 1, total); let firstOutputCount = 0; await waitUntilTextAppear( "返回大厅", async () => { await findAndClickWhiteSpaceNext(); if (firstOutputCount % 16 === 0) { log.info("等待本次关卡结束..."); } firstOutputCount++; }, 960, 540, 960, 540, 500, 2000 ); await findTextAndClick("返回大厅", 960, 540, 960, 540); if (!useFixedAttempts) { decreaseWeekTotal(); } log.info("本次关卡结束"); await deleteSource(); for (let i = 1; i < total; i++) { const inRoom = await findText("房间", 1500, 0, 420, 500); if (inRoom) { await sleep(duration); keyPress("VK_P"); await sleep(duration); await findTextAndClick("开始游戏", 960, 540, 960, 540, 20, 50, 50); log.info("开始执行第{i}/{total}次奇域挑战", i + 1, total); let outputCount = 0; await waitUntilTextAppear( "返回大厅", async () => { await findAndClickWhiteSpaceNext(); if (outputCount % 16 === 0) { log.info("等待本次关卡结束..."); } outputCount++; }, 960, 540, 960, 540, 500, 2000 ); await findTextAndClick("返回大厅", 960, 540, 960, 540); if (!useFixedAttempts) { decreaseWeekTotal(); } await deleteSource(); } } } // 退出到提瓦特 async function exitToTeyvat() { await genshin.returnMainUi(); await sleep(duration); keyPress("VK_F2"); await sleep(duration); await findTextAndClick("返回", 960, 0, 960, 100); await sleep(duration); await findTextAndClick("确认", 960, 600, 960, 400); await waitUntilImgAppear(paimon); // 有镜头拉近动画 await sleep(duration); } (async function () { if (!runJS) { log.error("您未同意此脚本的免责声明,请先同意后重新运行此脚本!"); return; } await genshin.returnMainUi(); if (useFixedAttempts) { // 手动模式:忽略本周计数 log.info( "已进入指定次数模式,本次将执行{count}次挑战(不计入周进度)", userAttempts ); } else { // 每周模式 const stored = loadWeekData(); const leave = stored.weekTotal; const done = Math.ceil(weekMaxExp / singleExp) - leave; log.info( "本周共需刷取 {total} 次,已刷 {done} 次,剩余 {leave} 次", Math.ceil(weekMaxExp / singleExp), done, leave ); } if (starMode) { log.info("已使用收藏模式"); await enterStarSourcePage(); } else { await enterSourcePage(); } await playMap(); await exitToTeyvat(); })();