mirror of
https://github.com/babalae/bettergi-scripts-list.git
synced 2026-04-18 21:39:11 +08:00
* V0.10 * 调整战斗策略设置方式 * 在显示日志中新增说明 * 读我文件排版 * 调试模式新增显示传入参数 * 修正刷完樹脂模式 修正刷完樹脂模式的邏輯 * 修正設置文字 修正刷完模式的文字描述
302 lines
15 KiB
JavaScript
302 lines
15 KiB
JavaScript
// Version: 1.7
|
||
// Modified Date: 2026-04-11
|
||
(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 字段");
|
||
|
||
// 转换角色天赋素材
|
||
if (sourceData.domains.talent_books) {
|
||
sourceData.domains.talent_books.forEach(item => {
|
||
let domain = item.domain_name_sc;
|
||
if (item.schedule.Mon_Thu) MATERIAL_DB[item.schedule.Mon_Thu] = { domain: domain, idx: 1 };
|
||
if (item.schedule.Tue_Fri) MATERIAL_DB[item.schedule.Tue_Fri] = { domain: domain, idx: 2 };
|
||
if (item.schedule.Wed_Sat) MATERIAL_DB[item.schedule.Wed_Sat] = { domain: domain, idx: 3 };
|
||
});
|
||
}
|
||
// 转换武器升级素材
|
||
if (sourceData.domains.weapon_materials) {
|
||
sourceData.domains.weapon_materials.forEach(item => {
|
||
let domain = item.domain_name_sc;
|
||
if (item.schedule.Mon_Thu) MATERIAL_DB[item.schedule.Mon_Thu] = { domain: domain, idx: 1 };
|
||
if (item.schedule.Tue_Fri) MATERIAL_DB[item.schedule.Tue_Fri] = { domain: domain, idx: 2 };
|
||
if (item.schedule.Wed_Sat) MATERIAL_DB[item.schedule.Wed_Sat] = { domain: domain, idx: 3 };
|
||
});
|
||
}
|
||
// 转换圣遗物
|
||
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. 读取并验证用户设置 (全 input-text 防呆机制)
|
||
// =========================================================================
|
||
let userConfig = settings;
|
||
let enableDebug = userConfig.EnableDebug;
|
||
|
||
// --- 调试模式输出所有使用者设定参数 ---
|
||
if (enableDebug) {
|
||
log.info("[DEBUG] ====== 收到使用者设定参数 (User Config) ======");
|
||
for (let key in userConfig) {
|
||
log.info(`[DEBUG] ${key}: ${userConfig[key]}`);
|
||
}
|
||
log.info("[DEBUG] ==============================================");
|
||
}
|
||
|
||
let pForceRunMode = userConfig.ForceRunMode;
|
||
let pRunUntilDepleted = userConfig.RunUntilResinDepleted;
|
||
let pAutoArtifactSalvage = userConfig.AutoArtifactSalvage;
|
||
let pMaxArtifactStar = userConfig.MaxArtifactStar || "4";
|
||
|
||
// --- 1.1 秘境目标防呆 ---
|
||
let pTalent = userConfig.TargetTalentMaterialName;
|
||
let pWeapon = userConfig.TargetWeaponMaterialName;
|
||
let pArtifact = userConfig.TargetArtifactName;
|
||
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;
|
||
|
||
// --- 1.2 队伍名称防呆 (input-text) ---
|
||
let pPartyName = (userConfig.PartyName || "").toString().trim();
|
||
if (pPartyName !== "") {
|
||
try {
|
||
new RegExp(pPartyName); // 测试正则表达式是否合法
|
||
} catch (e) {
|
||
log.warn(`【配置警告】队伍名称的正则表达式语法错误: ${pPartyName},已重置为空 (不执行队伍切换)。`);
|
||
pPartyName = "";
|
||
}
|
||
}
|
||
|
||
// --- 1.3 战斗策略防呆 (select + input-text) ---
|
||
let pCombatStrategyType = (userConfig.CombatStrategyType || "").toString().trim();
|
||
let pSpecifiedCombatStrategy = (userConfig.SpecifiedCombatStrategy || "").toString().trim();
|
||
let pCombatStrategyPath = "";
|
||
|
||
if (pCombatStrategyType === "指定战斗策略") {
|
||
if (!pSpecifiedCombatStrategy) {
|
||
log.warn("【配置警告】您选择了'指定战斗策略'但未填写策略名称,系统将自动退回'根据队伍自动选择'。");
|
||
} else if (/[\\/:*?"<>|]/.test(pSpecifiedCombatStrategy)) {
|
||
log.warn(`【配置警告】指定的战斗策略名称包含非法字元: ${pSpecifiedCombatStrategy},系统将自动退回'根据队伍自动选择'。`);
|
||
} else {
|
||
pCombatStrategyPath = pSpecifiedCombatStrategy;
|
||
}
|
||
}
|
||
|
||
// --- 1.4 各项数值与树脂防呆 (input-text 与 select) ---
|
||
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;
|
||
|
||
// 脆弱树脂 (input-text)
|
||
let pFragileRaw = parseInt(userConfig.FragileResinUseCount);
|
||
let pFragile = (isNaN(pFragileRaw) || pFragileRaw < 0) ? 0 : pFragileRaw;
|
||
if (userConfig.FragileResinUseCount && (isNaN(pFragileRaw) || pFragileRaw < 0)) {
|
||
log.warn("【配置警告】脆弱树脂刷取数量输入无效或为负数,已自动重置为 0。");
|
||
}
|
||
|
||
// 秘境轮数 (input-text)
|
||
let pDomainRoundNumRaw = parseInt(userConfig.DomainRoundNum);
|
||
let pDomainRoundNum = (isNaN(pDomainRoundNumRaw) || pDomainRoundNumRaw < 0) ? 0 : pDomainRoundNumRaw;
|
||
if (userConfig.DomainRoundNum && (isNaN(pDomainRoundNumRaw) || pDomainRoundNumRaw < 0)) {
|
||
log.warn("【配置警告】秘境刷取轮数输入无效,已自动重置为 0 (无限轮直至树脂耗尽)。");
|
||
}
|
||
|
||
// 战斗后等待时间 (input-text)
|
||
let pFightEndDelayRaw = parseInt(userConfig.FightEndDelay);
|
||
let pFightEndDelay = (isNaN(pFightEndDelayRaw) || pFightEndDelayRaw < 0) ? 5 : pFightEndDelayRaw;
|
||
if (userConfig.FightEndDelay && (isNaN(pFightEndDelayRaw) || pFightEndDelayRaw < 0)) {
|
||
log.warn("【配置警告】战斗完成后等待时间输入无效,已恢复默认值 5 秒。");
|
||
}
|
||
|
||
// 树脂刷取顺序 (input-text)
|
||
let rawOrderStr = (userConfig.ResinUsageOrder || "").toString().trim();
|
||
if (/[^12345]/.test(rawOrderStr)) {
|
||
log.warn(`【配置警告】树脂刷取顺序包含无效字符,非 1~5 的内容已被自动过滤。`);
|
||
}
|
||
let pOrderStr = [...new Set(rawOrderStr.replace(/[^12345]/g, '').split(''))].join('');
|
||
if (rawOrderStr.replace(/[^12345]/g, '').length !== pOrderStr.length) {
|
||
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];
|
||
let pDomainName = "";
|
||
let pSundaySelectedValue = "";
|
||
|
||
if (!materialInfo) {
|
||
log.error(`【数据错误】无法在数据库中找到项目:${pTargetMaterial}`);
|
||
return;
|
||
}
|
||
|
||
if (materialInfo.type === 'artifact') {
|
||
pDomainName = materialInfo.domain;
|
||
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 dayOfWeek = new Date(logicTimeMs).getUTCDay();
|
||
let dayStr = WEEK_MAP[dayOfWeek];
|
||
|
||
if (enableDebug) {
|
||
log.info(`[DEBUG] 游戏服务器时间: ${new Date(utcNow + serverOffsetMs).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. 执行主流程
|
||
// =========================================================================
|
||
let taskParam = new AutoDomainParam(pDomainRoundNum);
|
||
taskParam.DomainName = pDomainName;
|
||
taskParam.PartyName = pPartyName;
|
||
taskParam.AutoArtifactSalvage = pAutoArtifactSalvage;
|
||
taskParam.MaxArtifactStar = pMaxArtifactStar;
|
||
taskParam.SundaySelectedValue = pSundaySelectedValue;
|
||
|
||
// 调用底层方法以支持路径转换,并将回传值賦予屬性
|
||
taskParam.CombatStrategyPath = taskParam.SetCombatStrategyPath(pCombatStrategyPath);
|
||
|
||
taskParam.SpecifyResinUse = !pRunUntilDepleted;
|
||
|
||
// 樹脂數量與警告邏輯
|
||
if (!pRunUntilDepleted) {
|
||
taskParam.OriginalResin20UseCount = pOriginal20;
|
||
taskParam.OriginalResin40UseCount = pOriginal40;
|
||
taskParam.OriginalResinUseCount = 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)中,将被底层忽略!");
|
||
}
|
||
} else {
|
||
if (pOrderStr === "") {
|
||
log.warn("【配置警告】树脂刷取顺序完全留空!在耗尽模式下,脚本将不会消耗任何树脂。");
|
||
}
|
||
}
|
||
|
||
// 統一由 priorityList 決定刷取順序 (包含耗盡模式)
|
||
if (priorityList.length > 0) {
|
||
taskParam.SetResinPriorityList(...priorityList);
|
||
} else {
|
||
taskParam.SetResinPriorityList("");
|
||
}
|
||
|
||
while (true) {
|
||
try {
|
||
await dispatcher.RunAutoDomainTask(taskParam);
|
||
|
||
if (pFightEndDelay > 0) {
|
||
log.info(`[脚本] 任务结束,等待 ${pFightEndDelay} 秒...`);
|
||
await sleep(pFightEndDelay * 1000);
|
||
}
|
||
break;
|
||
} catch (ex) {
|
||
let msg = ex.message || "";
|
||
|
||
// --- 战斗策略档案不存在的降级重试逻辑 ---
|
||
if (msg.includes("战斗脚本文件不存在")) {
|
||
if (taskParam.CombatStrategyPath && taskParam.CombatStrategyPath !== "") {
|
||
log.warn(`[脚本] 找不到指定的战斗策略档案!`);
|
||
log.warn(`[脚本] 已触发降级机制:退回【根据队伍自动选择】模式,3 秒后重新启动任务...`);
|
||
|
||
// 调用底层方法正确切换为目录路径,并将回传值賦予屬性
|
||
taskParam.CombatStrategyPath = taskParam.SetCombatStrategyPath("");
|
||
|
||
await sleep(3000);
|
||
continue;
|
||
} else {
|
||
log.error("[脚本] 自动匹配战斗脚本失败:请检查 User/AutoFight 目录下是否有 txt 脚本,且脚本内角色是否符合当前队伍。");
|
||
break;
|
||
}
|
||
}
|
||
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
})();
|