mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-03-16 03:33:25 +08:00
* 自定義參數的自動秘境腳本 可自訂義樹脂數量、刷取輪次、隊伍等參數的自動秘境腳本 * 支持週期性素材 支持天賦書、武器升級素材 * 支持週期性素材刷取 支持武器素材、天賦書刷取,顯示從秘境名稱改為以掉落物為主 * 适配月之四版本,重构以便后续维护 1.适配月之四版本:新增圣遗物秘境 2.重构以便后续维护:将秘境信息与main.js拆分 * Add files via upload
266 lines
13 KiB
JavaScript
266 lines
13 KiB
JavaScript
// Version: 1.1
|
||
(async function () {
|
||
// =========================================================================
|
||
// 0. 动态加载数据 (基于 Genshin_Domains_SC_Live_Source.json)
|
||
// =========================================================================
|
||
let MATERIAL_DB = {};
|
||
const DB_FILENAME = "Genshin_Domains_SC_Live_Source.json";
|
||
|
||
try {
|
||
let rawContent = file.ReadTextSync(DB_FILENAME);
|
||
|
||
if (!rawContent) {
|
||
throw new Error("读取文件返回空内容");
|
||
}
|
||
|
||
let sourceData = JSON.parse(rawContent);
|
||
|
||
if (!sourceData || !sourceData.domains) {
|
||
throw new Error("JSON文件格式不正确,缺少 domains 字段");
|
||
}
|
||
|
||
// --- 1. 转换角色天赋素材 ---
|
||
if (sourceData.domains.talent_books) {
|
||
sourceData.domains.talent_books.forEach(item => {
|
||
let domain = item.domain_name_sc;
|
||
let schedule = item.schedule;
|
||
if (schedule.Mon_Thu) MATERIAL_DB[schedule.Mon_Thu] = { domain: domain, idx: 1 };
|
||
if (schedule.Tue_Fri) MATERIAL_DB[schedule.Tue_Fri] = { domain: domain, idx: 2 };
|
||
if (schedule.Wed_Sat) MATERIAL_DB[schedule.Wed_Sat] = { domain: domain, idx: 3 };
|
||
});
|
||
}
|
||
|
||
// --- 2. 转换武器升级素材 ---
|
||
if (sourceData.domains.weapon_materials) {
|
||
sourceData.domains.weapon_materials.forEach(item => {
|
||
let domain = item.domain_name_sc;
|
||
let schedule = item.schedule;
|
||
if (schedule.Mon_Thu) MATERIAL_DB[schedule.Mon_Thu] = { domain: domain, idx: 1 };
|
||
if (schedule.Tue_Fri) MATERIAL_DB[schedule.Tue_Fri] = { domain: domain, idx: 2 };
|
||
if (schedule.Wed_Sat) MATERIAL_DB[schedule.Wed_Sat] = { domain: domain, idx: 3 };
|
||
});
|
||
}
|
||
|
||
// --- 3. 转换圣遗物 (type: 'artifact') ---
|
||
if (sourceData.domains.artifacts) {
|
||
sourceData.domains.artifacts.forEach(item => {
|
||
let domain = item.domain_name_sc;
|
||
let key = item.drops.join(" / ");
|
||
MATERIAL_DB[key] = { domain: domain, type: "artifact" };
|
||
});
|
||
}
|
||
|
||
log.info(`【系统】成功加载外部数据文件: ${DB_FILENAME},包含 ${Object.keys(MATERIAL_DB).length} 条记录`);
|
||
|
||
} catch (e) {
|
||
log.error(`【致命错误】无法读取或解析 ${DB_FILENAME}`);
|
||
log.error(`错误详情: ${e.message}`);
|
||
return;
|
||
}
|
||
|
||
// =========================================================================
|
||
// 1. 读取并验证用户设置 (防呆机制)
|
||
// =========================================================================
|
||
let userConfig = settings;
|
||
let enableDebug = userConfig.EnableDebug;
|
||
|
||
let pTalent = userConfig.TargetTalentMaterialName;
|
||
let pWeapon = userConfig.TargetWeaponMaterialName;
|
||
let pArtifact = userConfig.TargetArtifactName;
|
||
let pForceRunMode = userConfig.ForceRunMode;
|
||
|
||
let selectedCount = (pTalent ? 1 : 0) + (pWeapon ? 1 : 0) + (pArtifact ? 1 : 0);
|
||
|
||
if (selectedCount === 0) {
|
||
log.error("【配置错误】您未选择任何素材!请在天赋、武器或圣遗物中选择一项。");
|
||
return;
|
||
}
|
||
|
||
if (selectedCount > 1) {
|
||
log.error("【配置冲突】您同时选择了多种类型的素材!请只保留一项,将其余两项设为空。");
|
||
return;
|
||
}
|
||
|
||
let pTargetMaterial = pTalent || pWeapon || pArtifact;
|
||
let pPartyName = userConfig.PartyName || "";
|
||
let pRunUntilDepleted = userConfig.RunUntilResinDepleted;
|
||
let pAutoArtifactSalvage = userConfig.AutoArtifactSalvage;
|
||
let pMaxArtifactStar = userConfig.MaxArtifactStar || "4";
|
||
|
||
let pDomainName = "";
|
||
let pSundaySelectedValue = "";
|
||
|
||
// --- 数值读取与防呆验证 ---
|
||
let pOriginalAmount = parseInt(userConfig.OriginalResinAmount) || 0;
|
||
let pOriginal40 = Math.floor(pOriginalAmount / 40);
|
||
let pOriginal20 = Math.floor((pOriginalAmount % 40) / 20);
|
||
|
||
let pCondensed = parseInt(userConfig.CondensedResinUseCount) || 0;
|
||
let pTransient = parseInt(userConfig.TransientResinUseCount) || 0;
|
||
|
||
// 脆弱树脂 (手动输入框防呆)
|
||
let pFragileRaw = parseInt(userConfig.FragileResinUseCount);
|
||
let pFragile = (isNaN(pFragileRaw) || pFragileRaw < 0) ? 0 : pFragileRaw;
|
||
if (userConfig.FragileResinUseCount && (isNaN(pFragileRaw) || pFragileRaw < 0)) {
|
||
log.warn("【配置警告】脆弱树脂刷取数量输入无效或为负数,已自动重置为 0。");
|
||
}
|
||
|
||
// 秘境轮数 (手动输入框防呆)
|
||
let pDomainRoundNumRaw = parseInt(userConfig.DomainRoundNum);
|
||
let pDomainRoundNum = (isNaN(pDomainRoundNumRaw) || pDomainRoundNumRaw < 0) ? 0 : pDomainRoundNumRaw;
|
||
if (userConfig.DomainRoundNum && (isNaN(pDomainRoundNumRaw) || pDomainRoundNumRaw < 0)) {
|
||
log.warn("【配置警告】秘境刷取轮数输入无效,已自动重置为 0 (无限轮直至树脂耗尽)。");
|
||
}
|
||
|
||
// 战斗后等待时间 (手动输入框防呆)
|
||
let pFightEndDelayRaw = parseInt(userConfig.FightEndDelay);
|
||
let pFightEndDelay = (isNaN(pFightEndDelayRaw) || pFightEndDelayRaw < 0) ? 5 : pFightEndDelayRaw;
|
||
if (userConfig.FightEndDelay && (isNaN(pFightEndDelayRaw) || pFightEndDelayRaw < 0)) {
|
||
log.warn("【配置警告】战斗完成后等待时间输入无效,已恢复默认值 5 秒。");
|
||
}
|
||
|
||
// 树脂刷取顺序防呆 (正则过滤与去重)
|
||
let rawOrderStr = (userConfig.ResinUsageOrder || "").toString().trim();
|
||
if (/[^12345]/.test(rawOrderStr) && !pRunUntilDepleted) {
|
||
log.warn(`【配置警告】树脂刷取顺序包含无效字符,非 1~5 的内容已被自动过滤。`);
|
||
}
|
||
|
||
// 仅保留1~5,并去除重复数字
|
||
let pOrderStr = [...new Set(rawOrderStr.replace(/[^12345]/g, '').split(''))].join('');
|
||
if (rawOrderStr.replace(/[^12345]/g, '').length !== pOrderStr.length && !pRunUntilDepleted) {
|
||
log.warn(`【配置警告】树脂刷取顺序中存在重复设定的数字,已自动去重处理为: ${pOrderStr}`);
|
||
}
|
||
|
||
let priorityList = [];
|
||
for (let char of pOrderStr) {
|
||
if (char === '1') priorityList.push("浓缩树脂");
|
||
else if (char === '2') priorityList.push("原粹树脂40");
|
||
else if (char === '3') priorityList.push("原粹树脂20");
|
||
else if (char === '4') priorityList.push("须臾树脂");
|
||
else if (char === '5') priorityList.push("脆弱树脂");
|
||
}
|
||
|
||
// 零动作警告
|
||
if (!pRunUntilDepleted && pOriginalAmount === 0 && pCondensed === 0 && pTransient === 0 && pFragile === 0 && pDomainRoundNum === 0) {
|
||
log.warn("【配置警告】您未设置任何树脂消耗数量,也未限制秘境轮数!脚本可能进本后无事可做。");
|
||
}
|
||
|
||
// =========================================================================
|
||
// 2. 智能逻辑处理 (日期检查)
|
||
// =========================================================================
|
||
const WEEK_MAP = ["日", "一", "二", "三", "四", "五", "六"];
|
||
let materialInfo = MATERIAL_DB[pTargetMaterial];
|
||
|
||
if (!materialInfo) {
|
||
log.error(`【数据错误】无法在数据库中找到项目:${pTargetMaterial}`);
|
||
return;
|
||
}
|
||
|
||
if (materialInfo.type === 'artifact') {
|
||
pDomainName = materialInfo.domain;
|
||
pSundaySelectedValue = "";
|
||
log.info(`【圣遗物模式】目标:${pTargetMaterial}`);
|
||
} else {
|
||
let requiredIdx = materialInfo.idx;
|
||
pDomainName = materialInfo.domain;
|
||
pSundaySelectedValue = requiredIdx.toString();
|
||
|
||
let serverOffsetMs = ServerTime.GetServerTimeZoneOffset();
|
||
let utcNow = Date.now();
|
||
let logicTimeMs = utcNow + serverOffsetMs - (4 * 60 * 60 * 1000);
|
||
let logicDate = new Date(logicTimeMs);
|
||
let dayOfWeek = logicDate.getUTCDay();
|
||
let dayStr = WEEK_MAP[dayOfWeek];
|
||
|
||
if (enableDebug) {
|
||
let serverTimeDate = new Date(utcNow + serverOffsetMs);
|
||
log.info(`[DEBUG] 游戏服务器时间: ${serverTimeDate.toUTCString()}`);
|
||
}
|
||
|
||
let isDateOpen = (dayOfWeek === 0) ||
|
||
(requiredIdx === 1 && (dayOfWeek === 1 || dayOfWeek === 4)) ||
|
||
(requiredIdx === 2 && (dayOfWeek === 2 || dayOfWeek === 5)) ||
|
||
(requiredIdx === 3 && (dayOfWeek === 3 || dayOfWeek === 6));
|
||
|
||
log.info(`【智能匹配】目标: ${pTargetMaterial} (游戏内星期${dayStr})`);
|
||
|
||
if (!isDateOpen && !pForceRunMode) {
|
||
log.error(`【停止运行】今日非该素材开放日。若需强制运行,请在设置中勾选。`);
|
||
return;
|
||
}
|
||
}
|
||
|
||
// =========================================================================
|
||
// 3. 执行主流程
|
||
// =========================================================================
|
||
while (true) {
|
||
try {
|
||
let taskParam = new AutoDomainParam(pDomainRoundNum);
|
||
taskParam.DomainName = pDomainName;
|
||
taskParam.PartyName = pPartyName;
|
||
taskParam.AutoArtifactSalvage = pAutoArtifactSalvage;
|
||
taskParam.MaxArtifactStar = pMaxArtifactStar;
|
||
taskParam.SundaySelectedValue = pSundaySelectedValue;
|
||
|
||
taskParam.SpecifyResinUse = !pRunUntilDepleted;
|
||
|
||
if (!pRunUntilDepleted) {
|
||
// 赋值各类型树脂次数
|
||
taskParam.OriginalResin20UseCount = pOriginal20;
|
||
taskParam.OriginalResin40UseCount = pOriginal40;
|
||
taskParam.OriginalResinUseCount = 0; // 核心逻辑已改用 20/40 独立计算,此项设为0
|
||
taskParam.CondensedResinUseCount = pCondensed;
|
||
taskParam.TransientResinUseCount = pTransient;
|
||
taskParam.FragileResinUseCount = pFragile;
|
||
|
||
// 逻辑冲突警告检查
|
||
if (pOrderStr === "") {
|
||
log.warn("【配置警告】树脂刷取顺序完全留空!在指定次数模式下,脚本将不会消耗任何树脂。");
|
||
} else {
|
||
if (pCondensed > 0 && !pOrderStr.includes('1')) log.warn("【配置警告】浓缩树脂数量大于0,但未配置在刷取顺序(1)中,将被底层忽略!");
|
||
if (pOriginal40 > 0 && !pOrderStr.includes('2')) log.warn("【配置警告】原粹树脂需要消耗40体力,但未配置在刷取顺序(2)中,将被底层忽略!");
|
||
if (pOriginal20 > 0 && !pOrderStr.includes('3')) log.warn("【配置警告】原粹树脂需要消耗20体力,但未配置在刷取顺序(3)中,将被底层忽略!");
|
||
if (pTransient > 0 && !pOrderStr.includes('4')) log.warn("【配置警告】须臾树脂数量大于0,但未配置在刷取顺序(4)中,将被底层忽略!");
|
||
if (pFragile > 0 && !pOrderStr.includes('5')) log.warn("【配置警告】脆弱树脂数量大于0,但未配置在刷取顺序(5)中,将被底层忽略!");
|
||
}
|
||
|
||
// 传入自定义优先级
|
||
if (priorityList.length > 0) {
|
||
taskParam.SetResinPriorityList(...priorityList);
|
||
} else {
|
||
// 若留空,传递空字串防止报错
|
||
taskParam.SetResinPriorityList("");
|
||
}
|
||
} else {
|
||
taskParam.SetResinPriorityList("浓缩树脂", "原粹树脂");
|
||
}
|
||
|
||
await dispatcher.RunAutoDomainTask(taskParam);
|
||
|
||
if (pFightEndDelay > 0) {
|
||
log.info(`[脚本] 任务结束,等待 ${pFightEndDelay} 秒...`);
|
||
await sleep(pFightEndDelay * 1000);
|
||
}
|
||
break;
|
||
} catch (ex) {
|
||
let msg = ex.message || "";
|
||
if (msg.includes("背包物品已满") || msg.includes("未检测到秘境结束")) {
|
||
log.warn(`[脚本] 任务可能已完成,但检测到: ${msg}`);
|
||
break;
|
||
} else if (msg.includes("复苏")) {
|
||
log.warn(`[脚本] 角色死亡,5秒后重试...`);
|
||
await sleep(5000);
|
||
continue;
|
||
} else if (msg.includes("TaskCanceledException")) {
|
||
log.info("[脚本] 任务已取消。");
|
||
break;
|
||
} else if (msg.includes("未找到对应的秘境")) {
|
||
log.error("请等待BetterGI本体更新支援新秘境");
|
||
throw ex;
|
||
} else {
|
||
log.error(`[脚本] 错误: ${msg}`);
|
||
throw ex;
|
||
}
|
||
}
|
||
}
|
||
})(); |