Files
bettergi-scripts-list/repo/js/DeerGameMeat/main.js
躁动的氨气 c94eb36699 菈乌玛兽肉支持少女 (#2705)
* 菈乌玛兽肉支持少女

* 自动修复 JSON 格式和版本号 [ci skip]

---------

Co-authored-by: GitHub Actions Bot <actions@github.com>
2026-01-17 16:55:14 +08:00

306 lines
11 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 () {
setGameMetrics(1920, 1080, 1);
// 读取用户设置
const enableDampDetection = settings.enableDampDetection === true; // 默认启用
const maxWaitAttempts = parseInt(settings.maxWaitAttempts) || 5; // 转换数字输入
const enableHighRiskRoutes = settings.enableHighRiskRoutes === true; // 默认启用高危路线
const partyName = settings.partyName || ""; // 队伍名称
// 检测当前队伍角色
function checkRequiredCharacters() {
const avatars = getAvatars();
let hasLayla = false;
let hasColumbina = false;
let hasKazuha = false;
if (avatars && avatars.length > 1) {
for (let i = 0; i < avatars.length; i++) {
if (avatars[i] === "菈乌玛") hasLayla = true;
if (avatars[i] === "哥伦比娅") hasColumbina = true;
if (avatars[i] === "枫原万叶") hasKazuha = true;
}
const hasOne = hasLayla || hasColumbina;
if (!hasOne || !hasKazuha) {
log.error(`队伍角色检查失败 - 菈乌玛或哥伦比娅:${hasOne ? '✓' : '✗'} 枫原万叶:${hasKazuha ? '✓' : '✗'}`);
return false;
}
return true;
}
return false;
}
// 高危路线数组目前只有07路线
const highRiskRoutes = ["07"];
log.info(`兽肉路线脚本启动 - 潮湿检测:${enableDampDetection ? '启用' : '禁用'} 高危路线:${enableHighRiskRoutes ? '启用' : '禁用'} 队伍:${partyName || '未设置'}`);
// 切换队伍函数
async function switchPartyIfNeeded(partyName) {
if (!partyName) {
await genshin.returnMainUi();
return;
}
try {
partyName = partyName.trim();
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 readFolder(folderPath, onlyJson) {
const folderStack = [folderPath];
const files = [];
while (folderStack.length > 0) {
const currentPath = folderStack.pop();
// 读取当前路径下的所有文件和子文件夹路径
const filesInSubFolder = file.ReadPathSync(currentPath);
// 临时数组,用于存储子文件夹路径
const subFolders = [];
for (const filePath of filesInSubFolder) {
if (file.IsFolder(filePath)) {
// 如果是文件夹,先存储到临时数组中
subFolders.push(filePath);
} else {
if (filePath.endsWith(".js")) {
//跳过js结尾的文件
continue;
}
// 如果是文件,根据 onlyJson 判断是否存储
if (onlyJson) {
if (filePath.endsWith(".json")) {
const fileName = filePath.split('\\').pop(); // 提取文件名
const folderPathArray = filePath.split('\\').slice(0, -1); // 提取文件夹路径数组
files.push({
fullPath: filePath,
fileName: fileName,
folderPathArray: folderPathArray
});
}
} else {
const fileName = filePath.split('\\').pop(); // 提取文件名
const folderPathArray = filePath.split('\\').slice(0, -1); // 提取文件夹路径数组
files.push({
fullPath: filePath,
fileName: fileName,
folderPathArray: folderPathArray
});
}
}
}
// 将子文件夹路径添加到堆栈中
for (let i = subFolders.length - 1; i >= 0; i--) {
folderStack.push(subFolders[i]);
}
}
return files;
}
// 动态获取兽肉路线文件
async function getMeatRoutes() {
try {
// 使用与锄地一条龙相同的方式读取路径文件
const pathsDir = "paths";
const allRoutes = [];
const routeOptions = [];
// 读取路径文件夹中的所有文件
const pathings = await readFolder(pathsDir, true);
for (const pathing of pathings) {
const fullPath = pathing.fullPath;
const fileName = pathing.fileName;
allRoutes.push(fullPath);
// 提取路线ID和名称用于选项
const routeId = fileName.match(/^(\d+)/)?.[1];
if (routeId) {
const routeName = fileName.replace('.json', '');
routeOptions.push({
value: routeId,
label: routeName
});
}
}
return allRoutes;
} catch (err) {
log.error("获取路线文件时出错:", err);
return [];
}
}
// 根据设置选择要运行的路线
const allRoutes = await getMeatRoutes();
let meatRoutes = allRoutes.filter(route => {
// 从路径中提取路线ID假设文件名以数字开头
const fileName = route.split('\\').pop(); // 使用反斜杠分割因为Windows路径
const routeId = fileName.match(/^(\d+)/)?.[1];
if (!routeId) return false;
// 如果是高危路线,需要检查是否启用高危路线
if (highRiskRoutes.includes(routeId)) {
return enableHighRiskRoutes;
}
// 非高危路线默认运行
return true;
});
// 检查是否找到路线文件
if (meatRoutes.length === 0) {
log.error("未找到任何路线文件请确保paths目录下存在路线文件。");
return;
}
log.info(`将运行 ${meatRoutes.length} 条路线`);
// 检测潮湿状态
async function checkDampStatus() {
try {
// 读取模板图像
const templateImage = file.ReadImageMatSync("assets/damp.png");
if (!templateImage) {
log.warn("无法读取潮湿状态模板图像");
return false;
}
// 创建模板匹配对象
const dampRo = RecognitionObject.TemplateMatch(templateImage, 700, 880, 260, 200);
dampRo.threshold = 0.8;
dampRo.InitTemplate();
const gameRegion = captureGameRegion();
// 执行模板匹配
const result = gameRegion.find(dampRo);
gameRegion.dispose();
return result.isExist();
} catch (err) {
log.error("检测潮湿状态时出错:", err.message || err);
return false;
}
}
// 循环检测并调整潮湿状态
async function handleDampStatus() {
let attempts = 0;
while (attempts < maxWaitAttempts) {
if (await checkDampStatus()) {
log.info(`检测到潮湿状态,第${attempts + 1}次调整时间`);
await genshin.setTime(6, 0);
await sleep(3000); // 等待调时间生效
} else {
log.info("潮湿状态已解除");
return true;
}
attempts++;
}
log.warn("潮湿状态调整超时");
return false;
}
// 传送到路线第一个点位
async function teleportToFirstPoint(routePath) {
try {
// 读取路线文件获取第一个点位坐标
const routeContent = file.readTextSync(routePath);
const routeData = JSON.parse(routeContent);
if (!routeData || !routeData.positions || routeData.positions.length === 0) {
log.error(`路线文件格式错误: ${routePath}`);
return false;
}
const firstPoint = routeData.positions[0];
if (typeof firstPoint.x !== "number" || typeof firstPoint.y !== "number"
|| Number.isNaN(firstPoint.x) || Number.isNaN(firstPoint.y)) {
log.error(`坐标无效: ${routePath}`);
return false;
}
// 使用传送功能传送到第一个点位
await genshin.tp(firstPoint.x, firstPoint.y);
await sleep(2000); // 等待传送完成
return true;
} catch (err) {
log.error(`传送失败 ${routePath}:`, err);
return false;
}
}
// 运行单条兽肉路线
async function runMeatRoute(routePath) {
try {
// 运行路径追踪脚本
await pathingScript.runFile(routePath);
} catch (err) {
log.error(`路线运行失败 ${routePath}:`, err);
}
}
// 主执行逻辑
// 设置游戏分辨率和DPI缩放
setGameMetrics(1920, 1080, 1);
// 切换队伍
await switchPartyIfNeeded(partyName);
// 检查队伍角色
if (!checkRequiredCharacters()) {
log.error("队伍角色检查失败,脚本终止");
return;
}
// 开启自动拾取
dispatcher.addTimer(new RealtimeTimer("AutoPick"));
for (let i = 0; i < meatRoutes.length; i++) {
const route = meatRoutes[i];
log.info(`路线 ${i + 1}/${meatRoutes.length}: ${route.split('\\').pop()}`);
// 先传送到路线的第一个点位
const teleportSuccess = await teleportToFirstPoint(route);
if (!teleportSuccess) {
log.error(`传送失败,跳过路线`);
continue;
}
// 检测潮湿状态
if (enableDampDetection) {
await sleep(2000);
if (await checkDampStatus()) {
await handleDampStatus();
}
}
// 运行路线
await runMeatRoute(route);
// 路线间等待
if (i < meatRoutes.length - 1) {
await sleep(2000);
}
}
log.info("所有路线运行完成");
})();