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