添加新BOSS支持,添加新的刷取逻辑 (#2356)

* 添加新BOSS支持,添加新的刷取逻辑

* 补充readme
This commit is contained in:
DarkFlameMaster
2025-11-16 09:26:47 +08:00
committed by GitHub
parent 84687c8456
commit 03182ce5b0
12 changed files with 418 additions and 378 deletions

View File

@@ -1,40 +1,20 @@
# 批量讨伐角色养成材料BOSS
## 零、脚本特点
## 一、功能简介
1. 一次性配置多个角色材料的boss
2. 体力不足时保存进度,每次运行时断点续打
## 一、调度器设置
1. **调度器配置组设置**
* **开启**:战斗配置
* **开启** 自动检测战斗结束
* **选择战斗策略** 根据队伍自动选择
2. **战斗超时时间**
* **位置**:调度器 -> 【战斗配置】 -> 【战斗超时(秒)】
* **建议**:请设置一个**较长**的超时时间。此时间应大于你所有已配置Boss中打的最慢的那个所需的时间并额外增加一些容错时间例如30-60秒。如果超时脚本会判定战斗结束。
* **替代方案**:如果不使用调度器的【战斗配置】,可以在独立任务中设置超时时间。
3. 支持三种刷取模式,包括一次性刷取、一次性刷取但每日限量、每日重复刷取
## 二、不支持的BOSS
以下Boss目前**未添加**尚未添加支持:
* 无相之风
* 黄金王兽
* 无相之冰
* 深海龙蜥之群
## 三、脚本使用指南
## 二、脚本使用指南
### 1. 首次运行配置添加Boss
* **步骤**
1. 右键点击脚本。
2. 选择【修改JS脚本自定义配置】。
3. 选择【选择模式】 -> 【追加boss】。
4. 在弹出的界面中选择要挑战的Boss、设置讨伐队伍、是否每次回七天神像回血、以及讨伐次数
3. 【选择模式】 -> 【追加boss】。
4. 在弹出的界面中选择要挑战的Boss、设置讨伐队伍、是否每次回七天神像回血、以及讨伐次数
5. **关闭**该配置窗口。
6. 运行一次脚本完成Boss的添加。
@@ -52,6 +32,30 @@
* **追加Boss**:此操作是**新增**一个Boss条目到列表末尾**不会**合并或增加同名Boss的数量。
* *示例*:列表中已有“急冻树”和“爆炎树”,再次追加“急冻树”,列表将变为:“急冻树”、“爆炎树”、“急冻树”。
* **删除Boss**:执行删除操作会**清除所有**同名的Boss条目。
### 4.选项说明
> !!!暂未生效需要等BGI更新再更新!!! 配置后会保存在config之后版本更新后会沿用这个配置。
>1. **战斗策略名**
> * 如果对战斗策略没特殊要求,不需要修改,**保证在`\BetterGI\User\AutoFight\`目录下有适合你配队的策略即可**
> * **如果需要自定义策略,需注意:**
> * 必须在`\BetterGI\User\AutoFight\`目录下存在,只需要填写文件名,不需要后缀,比如文件名是`1.四神挂机[推荐].txt`,只需要填`1.四神挂机>[推荐]`
> * 如果在文件夹内,必须包含目录结构,比如战斗策略在`\BetterGI\User\AutoFight\群友分享\仆人纯火.txt`,你需要填写`群友分享\仆人纯火`
> * 简单来说,按`BGI本体->独立任务->自动战斗->选择战斗策略`中的格式填写
>
>2. **战斗超时时间**
> * **每个boss独立设置** 单位为秒默认为240秒即4分钟如果超过这个时间强制结束战斗
3. **刷取模式**
>刷取的前提是有体力,没体力会自动停止
* **一次性**boss刷取次数完成后不再刷取这个配置。且按添加顺序刷完一个配置后才会刷取下一个配置。需配置`讨伐次数`。选择此模式时,`每日限量次数`选项无效
* **一次性-每日限量**:跟一次性类似,但可以在`每日限量次数`限制刷取的次数,刷够次数后会按添加顺序刷取下一配置,需同时配置`讨伐次数``每日限量次数`
* **每日重置**:简单说就是每天都刷取`每日限量次数`指定的次数,无论刷完与否,次日重置。选择此模式时,`讨伐次数`选项无效
## 三、不支持的BOSS
以下Boss目前**未添加**尚未添加支持:
* 无相之风
* 黄金王兽
* 无相之冰
* 深海龙蜥之群
## 四、手动编辑配置文件 (config.json)
@@ -64,39 +68,37 @@
```json
[
{
"name": "爆炎树", // Boss名称
"totalCount": 20, // 总讨伐次数比如20次
"completedCount": 0, // 已完成次数填0
"remainingCount": 20, // 剩余次数,手动添加时填写总讨伐次数比如20次
"team": "不切换", // 讨伐队伍,填不切换就不会换队伍,填队伍名会自动切换队伍
"returnToStatueAfterEachRound": false // 每轮结束后是否回七天神像回血
},
{
"name": "掣电树",
"totalCount": 4,
"completedCount": 0,
"remainingCount": 4,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "爆炎树",
"totalCount": 2,
"completedCount": 0,
"remainingCount": 2,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
"name": "魔像督军", // Boss名称
"totalCount": 20, // 总讨伐次数
"remainingCount": 20, // 剩余次数,手动添加时填写总讨伐次数
"team": "四神", // 讨伐队伍名,默认不切换
"returnToStatueAfterEachRound": true, // 每轮结束后是否回七天神像回血
"farmMode": "一次性-每日限量", // 刷取模式,可选:一次性、一次性-每日限量、每日重置
"lastFarmTime": null, // 上次刷取时间用于每日判断格式YYYYMMDD
"dailyLimitCount": 1, // 每日限量次数,在一次性-每日限量 和 每日重置 模式下生效
"dailyRemainingCount": 1, // 今日剩余可刷取次数
"fightParam": { // 战斗参数配置 (暂未实装)
"timeout": 240, // 战斗超时时间单位为秒默认240秒 (暂未实装)
"strategyName": "根据队伍自动选择" // 战斗策略名需与AutoFight目录下的策略文件名对应暂未实装
}
}
]
```
## 五、BUG反馈or建议
有任何问题或者功能需求,欢迎加群
* QQ群[1025022262](https://qm.qq.com/q/7i92V2JYF)
## 六、更新日志
### 2025.11.16 V0.5
* !!注意!!
本次版本更新后可能会重置且不支持老版本config.json强烈建议备份后重新配置
* 新增两种刷取模式:
* **一次性-每日限量** :与上版本的 **一次性** 类似,但可以在`每日限量次数`限制刷取的次数,刷够次数后会按添加顺序刷取下一配置,次日循环,刷完总数量为止。
* **每日重置**:每日都会刷取`每日限量次数`指定的次数。无论刷完与否都会在次日重置次数。
* 新增两个BOSS路线支持**重拳出击鸭**、**霜夜巡天灵主**
### 2025.08.23 V0.3
@@ -107,7 +109,7 @@
### 2025.08.21
* fix 截图资源未释放
* update 地图追踪文件 【从别的大佬那里偷来的】
* update 地图追踪文件
### 2025.08.21 V0.1

View File

@@ -0,0 +1,44 @@
{
"info": {
"authors": [],
"bgi_version": "0.45.0",
"description": "",
"enable_monster_loot_split": false,
"last_modified_time": 1763000407374,
"map_match_method": "",
"map_name": "Teyvat",
"name": "重拳出击鸭",
"tags": [],
"type": "collect",
"version": "1.0"
},
"positions": [
{
"action": "",
"action_params": "",
"id": 1,
"move_mode": "walk",
"type": "teleport",
"x": 10018.619140625,
"y": 1538.62646484375
},
{
"action": "",
"action_params": "",
"id": 2,
"move_mode": "walk",
"type": "path",
"x": 10041.8623046875,
"y": 1483.87255859375
},
{
"action": "combat_script",
"action_params": "keypress(f),wait(3),keypress(f),wait(1),keypress(f),wait(1),keypress(f)",
"id": 3,
"move_mode": "walk",
"type": "target",
"x": 10044.5068359375,
"y": 1473.15869140625
}
]
}

View File

@@ -0,0 +1,26 @@
{
"info": {
"authors": [],
"bgi_version": "0.45.0",
"description": "",
"enable_monster_loot_split": false,
"last_modified_time": 1763000508226,
"map_match_method": "",
"map_name": "Teyvat",
"name": "重拳出击鸭-打完返回",
"tags": [],
"type": "collect",
"version": "1.0"
},
"positions": [
{
"action": "combat_script",
"action_params": "keypress(f),wait(3),keypress(f),wait(1),keypress(f),wait(1),keypress(f)",
"id": 1,
"move_mode": "walk",
"type": "target",
"x": 10044.5068359375,
"y": 1473.15869140625
}
]
}

View File

@@ -0,0 +1,44 @@
{
"info": {
"authors": [],
"bgi_version": "0.45.0",
"description": "",
"enable_monster_loot_split": false,
"last_modified_time": 1762998844804,
"map_match_method": "",
"map_name": "Teyvat",
"name": "霜夜巡天灵主",
"tags": [],
"type": "collect",
"version": "1.0"
},
"positions": [
{
"action": "",
"action_params": "",
"id": 1,
"move_mode": "walk",
"type": "teleport",
"x": 10789.005859375,
"y": 2277.687744140625
},
{
"action": "",
"action_params": "",
"id": 2,
"move_mode": "walk",
"type": "path",
"x": 10773.37890625,
"y": 2294
},
{
"action": "",
"action_params": "",
"id": 3,
"move_mode": "walk",
"type": "path",
"x": 10761.36328125,
"y": 2319.513427734375
}
]
}

View File

@@ -0,0 +1,26 @@
{
"info": {
"authors": [],
"bgi_version": "0.45.0",
"description": "",
"enable_monster_loot_split": false,
"last_modified_time": 1762999379940,
"map_match_method": "",
"map_name": "Teyvat",
"name": "霜夜巡天灵主-打完重新靠近",
"tags": [],
"type": "collect",
"version": "1.0"
},
"positions": [
{
"action": "",
"action_params": "",
"id": 1,
"move_mode": "walk",
"type": "path",
"x": 10761.2197265625,
"y": 2319.93359375
}
]
}

View File

@@ -1,274 +1,17 @@
[
{
"name": "爆炎树",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "掣电树",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "纯水精灵",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "翠翎恐簟",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "风蚀沙虫",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "歌裴莉娅的葬送",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "古岩龙蜥",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "恒常机关阵列",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "急冻树",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "金焰绒翼龙暴君",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "科培琉司的劫罚",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "雷音权现",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "灵觉隐修的迷者",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "秘源机兵·构型械",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "秘源机兵·统御械",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "魔偶剑鬼",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "魔像督军",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"totalCount": 20,
"remainingCount": 20,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "千年珍珠骏麟",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "熔岩辉龙像",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "深罪浸礼者",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "深邃摹结株",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "实验性场力发生装置",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "水形幻人",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "贪食匿叶龙山王",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "铁甲熔火帝皇",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "无相之草",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "无相之火",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "无相之雷",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "无相之水",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "无相之岩",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "遗迹巨蛇",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "隐山猊兽",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "兆载永劫龙兽",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
},
{
"name": "半永恒统辖矩阵",
"totalCount": 0,
"completedCount": 0,
"remainingCount": 0,
"team": "不切换",
"returnToStatueAfterEachRound": false
"returnToStatueAfterEachRound": true,
"farmMode": "一次性-每日限量",
"lastFarmTime": null,
"dailyLimitCount": 1,
"dailyRemainingCount": 1,
"fightParam": {
"timeout": 240,
"strategyName": "根据队伍自动选择"
}
}
]

View File

@@ -1,25 +1,67 @@
eval(file.readTextSync("reward.js"));
eval(file.readTextSync("utils.js"));
(async function () {
const FARM_MODES = {
ONCE: "一次性",
DAILY_LIMIT: "一次性-每日限量",
DAILY: "每日重置"
};
try {
/**
* 追加Boss配置
*/
function addBoss() {
async function addBoss() {
//总次数
const rounds = parseInt(settings.rounds, 10);
if (isNaN(rounds) || rounds < 0) {
console.warn(`⚠️无效的挑战次数: ${settings.rounds},将使用 1 作为默认值。`);
log.warn(`⚠️无效的挑战次数: {rounds},将使用 1 作为默认值。`, settings.rounds);
}
const totalCount = isNaN(rounds) ? 1 : rounds;
// 每日刷取上限
let dailyLimitCount = parseInt(settings.dailyLimitCount, 10);
if (isNaN(dailyLimitCount) || dailyLimitCount < 0) {
log.warn(`⚠️无效的每日上限: {dailyLimitCount},将使用 1 作为默认值。`, settings.dailyLimitCount);
}
dailyLimitCount = isNaN(dailyLimitCount) ? 1 : dailyLimitCount;
//战斗超时时间
let timeout = parseInt(settings.timeout, 10);
if (isNaN(timeout)) {
log.warn(`⚠️无效的超时时间: {timeout},将使用 240 秒作为默认值。`, settings.timeout)
timeout = 240;
}
// 刷取模式
if (settings.farmMode === FARM_MODES.ONCE) {
farmMode = FARM_MODES.ONCE
} else if (settings.farmMode === FARM_MODES.DAILY_LIMIT) {
farmMode = FARM_MODES.DAILY_LIMIT
} else if (settings.farmMode === FARM_MODES.DAILY) {
farmMode = FARM_MODES.DAILY
} else {
throw new Error(`无效的farmMode: ${settings.farmMode}`);
}
const newBoss = {
name: settings.bossSelection,
totalCount: totalCount,
completedCount: 0,
remainingCount: totalCount,
team: settings.switchPartyName,
returnToStatueAfterEachRound: settings.returnToStatueBeforeStart
returnToStatueAfterEachRound: settings.returnToStatueBeforeStart,
farmMode: farmMode,
lastFarmTime: null,
dailyLimitCount: dailyLimitCount,
dailyRemainingCount: dailyLimitCount,
fightParam: {
timeout: timeout,
strategyName: settings.strategyName,
}
};
config.push(newBoss);
log.info(`✅Boss "${settings.bossSelection}" 已追加。`);
log.info(`✅Boss "{bossSelection}" 已追加。`, settings.bossSelection);
}
/**
@@ -44,20 +86,26 @@ eval(file.readTextSync("reward.js"));
* 遍历整个boss讨伐列表然后按照讨伐次数自动讨伐并领取奖励
* @async
* @param {boolean} goToBoss - 是否需要导航到Boss。
* @param {boolean} isClaimFailed - 是否因为体力不足而中止。
* @param {boolean} isInsufficientResin - 是否因为体力不足而中止。
* @param {boolean} battleSuccess - 当前一轮讨伐是否成功。
* @param {boolean} returnToStatueAfterEachRound - 是否在每次讨伐后回到七天神像。
*/
async function runMain() {
// --- 打印所有Boss的剩余次数 ---
for (let i = 0; i < config.length; i++) {
if (i % 10 === 0) {
let currentPage = Math.floor(i / 10) + 1;
log.info(`--- 当前boss队列 (第 ${currentPage} 页) ---`);
log.info(`--- 当前boss队列 (第 {currentPage} 页) ---`, currentPage);
}
log.info(`🎵${i + 1}.${config[i]["name"]} - 剩余: ${config[i]["remainingCount"]}/${config[i]["totalCount"]}, 队伍: ${config[i]["team"]}`);
log.info(`🎵{i}.{name} - 剩余: {remainingCount}/{totalCount}, 队伍: {team}`,
i + 1,
config[i]["name"],
config[i]["remainingCount"],
config[i]["totalCount"],
config[i]["team"]
);
const isEndOfPage = (i + 1) % 10 === 0;
const isLastItem = i === config.length - 1;
@@ -71,7 +119,7 @@ eval(file.readTextSync("reward.js"));
if (isEndOfPage && !isLastItem) {
let currentPage = Math.floor((i + 1) / 10);
log.info(`⌛️当前第 ${currentPage} 页结束5秒后显示下一页`);
log.info(`⌛️当前第 {currentPage} 页结束5秒后显示下一页`, currentPage);
await sleep(5000);
} else if (isLastItem) {
log.info(`🔚列表显示完毕5秒后继续`);
@@ -79,61 +127,101 @@ eval(file.readTextSync("reward.js"));
}
}
}
try {
let isClaimFailed = false;
let isInsufficientResin = false;
// --- 遍历Boss列表 ---
for (const boss of config) {
for (let boss of config) {
let goToBoss = true;
const returnToStatueAfterEachRound = boss.returnToStatueAfterEachRound
// --- 检查体力是否足够 ---
if (isClaimFailed) {
break; // 如果体力不足,跳出循环
if (isInsufficientResin) {
log.info(`体力不足结束刷取BOSS材料`)
break;
};
//刷取模式为 每日限量 or 每日重置 时
if (boss.farmMode === FARM_MODES.DAILY_LIMIT || boss.farmMode === FARM_MODES.DAILY) {
//如果今天还未刷取,重置今日已刷取次数
if (!isToday(boss.lastFarmTime)) {
log.info(`今天还未刷取{boss.name},重置今日刷取次数`, boss.name);
boss.dailyRemainingCount = Math.min(boss.dailyLimitCount, boss.remainingCount);
boss.lastFarmTime = getToday();
}
if (boss.dailyRemainingCount < 1) {
log.info(`今日刷取{name}达到上限,跳过`, boss.name);
continue;
}
}
// --- 检查当前boss剩余需讨伐次数 ---
if (boss.remainingCount <= 0) {
log.info(`Boss "${boss.name}" 已完成全部${boss.totalCount}次讨伐。跳过`);
if (boss.remainingCount <= 0 && boss.farmMode === FARM_MODES.ONCE) {
log.info(`Boss "{name}" 已完成全部{totalCount}次讨伐。跳过`, boss.name, boss.totalCount);
continue;
};
// --- 切换队伍 ---
if (boss.team !== "不切换") {
log.info(`切换队伍『${boss.team}`);
log.info(`切换队伍『{team}』`, boss.team);
await genshin.switchParty(boss.team);
};
// --- 初始化自定战斗参数 ---
// let fightParam = new AutoFightParam(boss.fightParam.strategyName)
// fightParam.timeout = boss.fightParam.timeout;
let remainingCount
if (boss.farmMode === FARM_MODES.DAILY_LIMIT || boss.farmMode === FARM_MODES.DAILY) {
remainingCount = boss.dailyRemainingCount
} else if (boss.farmMode === FARM_MODES.ONCE) {
remainingCount = boss.remainingCount
}
// --- 根据剩余次数循环讨伐 ---
for (let round = 1; round <= boss.remainingCount; round++) {
for (let round = 1; round <= remainingCount; round++) {
let battleSuccess = false;
if (isClaimFailed) {
if (isInsufficientResin) {
break; // --- 体力不足,停止讨伐 ---
}
log.info(`📢当前进度:讨伐『${boss.name}』,第${round}/${boss.remainingCount}`);
log.info(`使用队伍:${boss.team},每轮回七天神像:${returnToStatueAfterEachRound ? '是' : '否'}`);
log.info(`📢当前进度:讨伐『{boss.name}』,第{round}/{remainingCount}次,今日限次:{dailyLimitCount}`,
boss.name,
round,
remainingCount,
boss.farmMode === FARM_MODES.ONCE ? boss.totalCount : boss.dailyLimitCount
);
log.info(`使用队伍:{team},每轮回七天神像:{text}`,
boss.team,
returnToStatueAfterEachRound ? '是' : '否'
);
for (let attempt = 1; attempt <= 2; attempt++) {
//体力不足和战斗成功后无需重试
if (isClaimFailed || battleSuccess) {
if (isInsufficientResin || battleSuccess) {
break;
};
if (goToBoss) {
log.info(`🏃前往『${boss.name}`);
log.info(`🏃前往『{name}』`,boss.name);
await pathingScript.runFile(`assets/Pathing/${boss.name}前往.json`);
};
try {
log.info(`⚔️开始第 ${attempt} 次讨伐尝试`);
log.info(`⚔️开始第 {round} 次讨伐的第 {attempt} 尝试`,round,attempt);
await dispatcher.runTask(new SoloTask("AutoFight"));
// await dispatcher.runAutoFightTask(fightParam);
await autoNavigateToReward();
isClaimFailed = await takeReward(isClaimFailed);
isInsufficientResin = await takeReward(isInsufficientResin);
battleSuccess = true;
goToBoss = false;
// === 更新 讨伐完成次数 与 剩余讨伐次数 ===
if (!isClaimFailed) {
boss.remainingCount--;
boss.completedCount++;
if (!isInsufficientResin) {
if (boss.farmMode === FARM_MODES.DAILY_LIMIT || boss.farmMode === FARM_MODES.ONCE) {
boss.remainingCount--;
}
if (boss.farmMode === FARM_MODES.DAILY_LIMIT || boss.farmMode === FARM_MODES.DAILY) {
boss.dailyRemainingCount--;
}
};
break;
@@ -146,7 +234,7 @@ eval(file.readTextSync("reward.js"));
}
if (!battleSuccess) {
log.error(`💀战斗失败次数超过2次跳过当前BOSS ${boss.name}`);
log.error(`💀战斗失败次数超过2次跳过当前BOSS ${name}`,boss.name);
break;
}
@@ -157,8 +245,8 @@ eval(file.readTextSync("reward.js"));
goToBoss = true;
};
if (!goToBoss && boss.remainingCount > 0 && !isClaimFailed) {
if (["歌裴莉娅的葬送", "科培琉司的劫罚", "纯水精灵"].includes(boss.name)) {
if (!goToBoss && boss.remainingCount > 0 && !isInsufficientResin) {
if (["歌裴莉娅的葬送", "科培琉司的劫罚", "纯水精灵","霜夜巡天灵主","重拳出击鸭"].includes(boss.name)) {
await pathingScript.runFile(`assets/Pathing/${boss.name}战斗后快速前往.json`);
} else {
log.debug("等待5s后BOSS刷新");
@@ -169,34 +257,45 @@ eval(file.readTextSync("reward.js"));
}
}
catch (error) {
log.error(`遍历Boss列表失败error: ${error}`);
log.error(`遍历Boss列表失败 ${error}`);
} finally {
log.info("📢脚本执行完毕,保存配置");
file.writeTextSync("assets/config/config.json", JSON.stringify(config, null, 4));
}
}
const content = file.readTextSync("assets/config/config.json");
let config = JSON.parse(content);
if (!Array.isArray(config)) {
let config;
try {
config = JSON.parse(file.readTextSync("assets/config/config.json"));
} catch (error) {
log.error(`读取配置文件失败: ${error}`);
log.info(`初始化配置`);
config = [];
}
if (!Array.isArray(config)) {
log.warn("配置文件格式不正确,已重置为空数组");
config = [];
}
const runMode = settings.runMode;
const modeHandlers = {
"追加指定Boss及相关配置": addBoss,
"删除同名Boss及相关配置": removeBoss,
"!!删除所有BOSS": clearAllBosses,
"运行": runMain,
// === 执行对应操作 ===
const RUN_MODES = {
ADD_BOSS: "追加指定Boss及相关配置",
REMOVE_BOSS: "删除同名Boss及相关配置",
CLEAR_ALL: "删除所有BOSS",
RUN: "运行"
};
// === 执行对应操作 ===
const handler = modeHandlers[runMode];
if (handler) {
await handler();
if (runMode === RUN_MODES.ADD_BOSS) {
addBoss();
} else if (runMode === RUN_MODES.REMOVE_BOSS) {
removeBoss();
} else if (runMode === RUN_MODES.CLEAR_ALL) {
clearAllBosses();
} else if (runMode === RUN_MODES.RUN) {
await runMain();
} else {
log.debug("❓️未知的运行模式:", runMode);
log.error("❓️未知的运行模式:", runMode);
}
// === 写回配置文件 ===

View File

@@ -1,8 +1,8 @@
{
"manifest_version": 1,
"name": "批量讨伐角色养成材料BOSS",
"version": "0.4",
"description": "一次性配置多个角色材料的boss体力不足时保存进度每次运行时断点续打。\n\n感谢boss地图追踪作者@柒叶子@Tool_tingsu,\n\n感谢 @柒叶子【首领讨伐一条龙 - 首领连续讨伐】的地脉花寻路的代码实现 \n\n感谢@wjdsg @Tool_tingsu【纪行周常-10个boss一条龙】循环讨伐的代码实现",
"version": "0.5",
"description": "一次性配置多个角色材料的boss体力不足时保存进度每次运行时断点续打",
"authors": [
{
"name": "无激情非少年",
@@ -10,5 +10,8 @@
}
],
"settings_ui": "settings.json",
"main": "main.js"
"main": "main.js",
"saved_files": [
"assets/config"
]
}

View File

@@ -48,7 +48,13 @@ async function autoNavigateToReward() {
await sleep(800);
keyUp("w");
}
if (iconRes.x >= 920 && iconRes.x <= 980 && iconRes.y <= 540) {
if (iconRes.isEmpty()) {
log.warn("未找到宝箱图标,重试");
moveMouseBy(200, 0);
await sleep(500);
continue;
}
else if (iconRes.x >= 920 && iconRes.x <= 980 && iconRes.y <= 540) {
advanceNum++;
log.info(`视野已调正,前进第${advanceNum}`);
break;
@@ -76,7 +82,7 @@ async function autoNavigateToReward() {
}
}
async function takeReward(isClaimFailed) {
async function takeReward(isInsufficientResin) {
try {
const mainUiRo = RecognitionObject.TemplateMatch(file.ReadImageMatSync("assets/RecognitionObject/mainUi.png"));
for (let attempt = 1; attempt <= 100; attempt++) {
@@ -88,7 +94,7 @@ async function takeReward(isClaimFailed) {
let rewardTextArea = captureRegion.DeriveCrop(1210, 515, 200, 50);
let rewardResult = rewardTextArea.find(RecognitionObject.ocrThis);
rewardTextArea.dispose();
if (rewardResult.text === "接触征讨之花" && isClaimFailed == false) {
if (rewardResult.text === "接触征讨之花" && isInsufficientResin == false) {
keyPress("F");
await sleep(1000);
captureRegion.dispose();
@@ -106,7 +112,7 @@ async function takeReward(isClaimFailed) {
await sleep(1000);
captureRegion.dispose();
captureRegion = captureGameRegion();
isClaimFailed = true;
isInsufficientResin = true;
}
else if (useResult.text.includes("使用")) {
log.info("使用脆弱树脂领取奖励");
@@ -133,7 +139,7 @@ async function takeReward(isClaimFailed) {
if (inMainUi.x > 0 && !useResult.text.includes("树脂")) {
log.debug("回到主界面");
captureRegion.dispose();
return isClaimFailed;
return isInsufficientResin;
}
captureRegion.dispose();
rewardTextArea.Dispose();

View File

@@ -14,7 +14,7 @@
{
"name": "bossSelection",
"type": "select",
"label": "选择讨伐BOSS(挂机打不过概不负责)",
"label": "选择讨伐BOSS \n - 以拼音首字母按英文字母表排序",
"options": [
"半永恒统辖矩阵",
"爆炎树",
@@ -37,6 +37,7 @@
"千年珍珠骏麟",
"熔岩辉龙像",
"深罪浸礼者",
"霜夜巡天灵主",
"深邃摹结株",
"实验性场力发生装置",
"水形幻人",
@@ -49,7 +50,8 @@
"无相之岩",
"遗迹巨蛇",
"隐山猊兽",
"兆载永劫龙兽"
"兆载永劫龙兽",
"重拳出击鸭"
]
},
{
@@ -58,16 +60,45 @@
"label": "要切换的队伍名(默认不切换)",
"default": "不切换"
},
{
"name": "timeout",
"type": "input-text",
"label": "战斗超时设置(秒)\n !!!暂时未生效等下版本BGI更新后更新!!!",
"default": 240
},
{
"name": "strategyName",
"type": "input-text",
"label": "战斗策略名\n !!!暂时未生效等下版本BGI更新后更新!!!\n - BGI本体策略文件夹下的策略名不含后缀 \n - 如在文件夹内需保留目录结构",
"default": "根据队伍自动选择"
},
{
"name": "returnToStatueBeforeStart",
"type": "checkbox",
"label": "是否开始前回七天神像(默认否)",
"default": false
"default": true
},
{
"name": "farmMode",
"type": "select",
"label": "刷取模式",
"options":[
"一次性",
"一次性-每日限量",
"每日重置"
],
"default": "一次性"
},
{
"name": "rounds",
"type": "input-text",
"label": "讨伐次数",
"default": "1"
},
{
"name": "dailyLimitCount",
"type": "input-text",
"label": "每日限量次数 \n - 仅在 【一次性-每日限量】 模式下有效",
"default": "1"
}
]

View File

@@ -0,0 +1,16 @@
// 获取今天的日期考虑4点前为昨天并格式化为YYYYMMDD
function getToday() {
const now = new Date();
const targetDate = now.getHours() < 4 ?
new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1) :
new Date(now.getFullYear(), now.getMonth(), now.getDate());
const year = targetDate.getFullYear();
const month = String(targetDate.getMonth() + 1).padStart(2, '0');
const day = String(targetDate.getDate()).padStart(2, '0');
return `${year}${month}${day}`;
}
// 判断给定日期是否为今天
function isToday(date) {
return date === getToday();
}