diff --git a/repo/js/自动购买每天&3天&每周刷新商品/README.md b/repo/js/自动购买每天&3天&每周刷新商品/README.md index ba1b4e215..ddbaa4481 100644 --- a/repo/js/自动购买每天&3天&每周刷新商品/README.md +++ b/repo/js/自动购买每天&3天&每周刷新商品/README.md @@ -45,20 +45,16 @@ - 周一刷新商品 - 周四刷新商品 - **每月1号刷新商品**:不受此设置影响,刷新即购买 -4. **要禁用的商人**:不想购买的商人,用空格分隔 +4. **禁用标签功能**:可以输入要禁用的标签(空格分隔),如: ``` - 示例:阿扎莱 皮托 - ``` -5. **禁用标签功能**:可以输入要禁用的标签(空格分隔),如: - ``` - 示例:黑心商人 挪德卡莱 + 示例:黑心商人 挪德卡莱 卡琵莉亚 ``` 禁用后,脚本会跳过这些商人或带有指定标签的商人,不会前往购买。 可以使用国家/地区(如"蒙德"、"璃月")或其他标签(如商人信息总览中的标签) -6. **是否跳过调整时间动画**:开启后会啟用时瞬跳过调整时间动画 -7. **无视购买记录强制购买**:开启后会忽略购买记录,重新购买所有商品 -8. **调试模式**:开启后显示详细执行日志 +5. **是否跳过调整时间动画**:开启后会啟用时瞬跳过调整时间动画 +6. **无视购买记录强制购买**:开启后会忽略购买记录,重新购买所有商品 +7. **调试模式**:开启后显示详细执行日志 ### 购买记录系统说明 脚本会自动记录购买时间,避免重复购买: @@ -106,7 +102,7 @@ | 璃月-石门 | 老周叔 | 大碗茶 | - | - | 稀少商品 | | 璃月-轻策庄 | 小白 | - | 豆腐、杏仁、霓裳花 | - | 琉璃百合(每月刷新) | | 璃月-轻策庄 | 凯叔 | 大碗茶 | - | - | 稀少商品 | -| 璃月-遗珑埠 | 丰泰 | - | 沉玉仙茗、琉璃袋、绝云椒椒 | 蟹黄 | | +| 璃月-遗珑埠 | 丰泰 | 稻米、豆腐 | 清水玉、石珀、夜泊石、琉璃袋、霓裳花、绝云椒椒、沉玉仙茗 | 蟹黄 | | | 璃月-遗珑埠 | 连芳 | - | 沉玉仙茗 | - | | | 稻妻-离岛 | 小畑 | 螃蟹、鱼肉、虾仁 | 海灵芝 | - | | | 稻妻-离岛 | 秋月 | 铁块、白铁块、电气水晶 | - | - | | @@ -151,10 +147,11 @@ | 挪德卡莱-那夏镇 | 雷科 | - | - | 幸运儿之杯、幸运儿鹰羽、幸运儿银冠、幸运儿绿花、幸运儿沙漏 | 狗粮商人 | | 挪德卡莱-皮拉米达城 | 科菲策 | 牛奶、咖啡豆 | 微光角菌、琉鳞石 | - | 黑心商人 | -- **国家标签**:蒙德、璃月、稻妻、须弥、枫丹、纳塔、挪德卡莱 -- **地区标签**:风起地、清泉镇、蒙德城、璃月港、离岛、稻妻城、海祇岛等 -- **小地图标签**:天使的馈赠、兰巴德酒馆、德波大饭店、灰河、锈舵酒馆等 -- **商人标签**:克罗丽丝、神奇的霍普金斯、杜拉夫等(所有商人名) +### **以下为有效标签** +- **国家**:蒙德、璃月、稻妻、须弥、枫丹、纳塔、挪德卡莱 +- **地区**:风起地、清泉镇、蒙德城、璃月港、离岛、稻妻城、海祇岛等 +- **小地图**:天使的馈赠、兰巴德酒馆、德波大饭店、灰河、锈舵酒馆等 +- **商人**:克罗丽丝、神奇的霍普金斯、杜拉夫等(所有商人名) - **移动**:指商人会移动,有机会购买失败 - **稀少商品**:指稀少商品 - **独立地图**:指需要进入独立空间的特殊地图,这些地图部份路径无法使用地图追踪功能 diff --git a/repo/js/自动购买每天&3天&每周刷新商品/assets/images/清水玉.png b/repo/js/自动购买每天&3天&每周刷新商品/assets/images/清水玉.png new file mode 100644 index 000000000..c2a65f6b3 Binary files /dev/null and b/repo/js/自动购买每天&3天&每周刷新商品/assets/images/清水玉.png differ diff --git a/repo/js/自动购买每天&3天&每周刷新商品/assets/npcs.json b/repo/js/自动购买每天&3天&每周刷新商品/assets/npcs.json index ca3899e3e..2a9a64dc6 100644 --- a/repo/js/自动购买每天&3天&每周刷新商品/assets/npcs.json +++ b/repo/js/自动购买每天&3天&每周刷新商品/assets/npcs.json @@ -227,7 +227,8 @@ "page": 2, "time": "any", "path": "assets/path/璃月-遗珑埠-丰泰.json", - "_3d_foods": ["沉玉仙茗", "琉璃袋", "绝云椒椒"], + "_1d_foods": ["稻米","豆腐"], + "_3d_foods": [ "清水玉","石珀","夜泊石","琉璃袋", "霓裳花", "绝云椒椒","沉玉仙茗"], "_7d_foods": ["蟹黄"], "tags": ["璃月", "遗珑埠", "丰泰"] }, diff --git a/repo/js/自动购买每天&3天&每周刷新商品/assets/path/蒙德-蒙德城-天使的馈赠-查尔斯.json b/repo/js/自动购买每天&3天&每周刷新商品/assets/path/蒙德-蒙德城-天使的馈赠-查尔斯.json index 31cfb3f40..d0846c479 100644 --- a/repo/js/自动购买每天&3天&每周刷新商品/assets/path/蒙德-蒙德城-天使的馈赠-查尔斯.json +++ b/repo/js/自动购买每天&3天&每周刷新商品/assets/path/蒙德-蒙德城-天使的馈赠-查尔斯.json @@ -9,7 +9,7 @@ "bgi_version": "0.45.0", "description": "", "enable_monster_loot_split": false, - "last_modified_time": 1771248205039, + "last_modified_time": 1771299801495, "map_match_method": "", "map_name": "Teyvat", "name": "蒙德-蒙德城-天使的馈赠-查尔斯", @@ -49,6 +49,15 @@ "action": "", "action_params": "", "id": 4, + "move_mode": "walk", + "type": "path", + "x": -894.005859375, + "y": 2319.78125 + }, + { + "action": "", + "action_params": "", + "id": 5, "move_mode": "run", "type": "path", "x": -908.830078125, @@ -57,7 +66,7 @@ { "action": "", "action_params": "", - "id": 5, + "id": 6, "move_mode": "dash", "type": "path", "x": -921.044921875, @@ -66,7 +75,7 @@ { "action": "", "action_params": "", - "id": 6, + "id": 7, "move_mode": "walk", "type": "path", "x": -923.63671875, @@ -75,7 +84,7 @@ { "action": "", "action_params": "", - "id": 7, + "id": 8, "move_mode": "dash", "type": "path", "x": -930.8125, @@ -84,7 +93,7 @@ { "action": "", "action_params": "", - "id": 8, + "id": 9, "move_mode": "walk", "type": "path", "x": -934.296875, @@ -93,7 +102,7 @@ { "action": "", "action_params": "", - "id": 9, + "id": 10, "move_mode": "walk", "type": "path", "x": -933.291015625, @@ -102,7 +111,7 @@ { "action": "combat_script", "action_params": "wait(0.5),keypress(F),wait(0.2),keypress(F),wait(0.2),keypress(F),wait(7.5),keydown(a),keypress(SPACE),wait(0.5),keypress(SPACE),wait(0.5),keypress(SPACE),wait(0.5),keypress(SPACE),wait(0.5),keyup(a),wait(0.5),s(0.5),wait(0.5),d(2),wait(0.5),w(0.8),wait(0.5),a(0.5),wait(1.5)", - "id": 10, + "id": 11, "move_mode": "walk", "type": "target", "x": -929.392578125, diff --git a/repo/js/自动购买每天&3天&每周刷新商品/main.js b/repo/js/自动购买每天&3天&每周刷新商品/main.js index ec9e185ad..c17a947dd 100644 --- a/repo/js/自动购买每天&3天&每周刷新商品/main.js +++ b/repo/js/自动购买每天&3天&每周刷新商品/main.js @@ -111,6 +111,9 @@ let npcData = {}; // 存储用户要购买的商品名称集合(中文名) let userFoodsToBuy = new Set(); +let userTagsToBuy = new Set(); // 标签名 +let allTags = new Set(); // 所有可用标签(从 npcs.json 收集) +let requiredFoods = new Set(); // 所有需要加载图片的商品 async function loadExternalData() { try { @@ -119,26 +122,62 @@ async function loadExternalData() { npcData = JSON.parse(npcsContent); logConditional(`已加载商人数据: ${Object.keys(npcData).length} 个商人`); - // 解析用户要购买的商品列表(中文商品名,空格分隔) + // ========== 收集所有标签 ========== + for (let key in npcData) { + let npc = npcData[key]; + if (npc.tags && Array.isArray(npc.tags)) { + npc.tags.forEach(tag => allTags.add(tag)); + } + } + logConditional(`共收集到 ${allTags.size} 个标签`); + + // ========== 解析用户输入 ========== const foodsInput = (settings.foodsToBuy || "").trim(); if (foodsInput) { - const foodNames = foodsInput.split(/[,\s、]+/).filter(name => name.trim() !== ""); + const items = foodsInput.split(/[,\s、]+/).filter(item => item.trim() !== ""); const enabledFoodsList = []; - for (const foodName of foodNames) { - // 直接使用用户输入的商品名,不需要验证是否存在(由用户自行确保) - userFoodsToBuy.add(foodName); - enabledFoodsList.push(foodName); + const enabledTagsList = []; + + for (const item of items) { + if (allTags.has(item)) { + // 是标签 + userTagsToBuy.add(item); + enabledTagsList.push(item); + } else { + // 视为商品名 + userFoodsToBuy.add(item); + enabledFoodsList.push(item); + } + } + + // 输出用户启用的标签和商品 + if (enabledTagsList.length > 0) { + log.info(`用户启用了以下标签: ${enabledTagsList.join(", ")}`); } - // 输出用户启用的商品列表 if (enabledFoodsList.length > 0) { - log.info(`用户启用了下列商品: ${enabledFoodsList.join(", ")}`); - } else { - log.warn("用户未启用任何商品"); + log.info(`用户启用了以下商品: ${enabledFoodsList.join(", ")}`); + } + if (enabledTagsList.length === 0 && enabledFoodsList.length === 0) { + log.warn("用户未启用任何标签或商品"); } } else { - log.warn("用户未指定要购买的商品"); + log.warn("用户未指定要购买的商品或标签"); } + // 计算所有需要加载图片的商品 + requiredFoods = new Set(userFoodsToBuy); + for (let key in npcData) { + let npc = npcData[key]; + if (npc.tags && Array.isArray(npc.tags) && npc.tags.some(tag => userTagsToBuy.has(tag))) { + if (npc._1d_foods) npc._1d_foods.forEach(food => requiredFoods.add(food)); + if (npc._3d_foods) npc._3d_foods.forEach(food => requiredFoods.add(food)); + if (npc._7d_foods) npc._7d_foods.forEach(food => requiredFoods.add(food)); + if (npc._thu_foods) npc._thu_foods.forEach(food => requiredFoods.add(food)); + if (npc._month_foods) npc._month_foods.forEach(food => requiredFoods.add(food)); + } + } + logConditional(`需要加载图片的商品总数: ${requiredFoods.size}`); + return true; } catch (error) { log.error(`加载外部数据失败: ${error.message}`); @@ -146,6 +185,17 @@ async function loadExternalData() { } } +// ==================== 辅助函数:获取商人的所有商品 ==================== +function getAllNpcFoods(npc) { + const all = []; + if (npc._1d_foods) all.push(...npc._1d_foods); + if (npc._3d_foods) all.push(...npc._3d_foods); + if (npc._7d_foods) all.push(...npc._7d_foods); + if (npc._thu_foods) all.push(...npc._thu_foods); + if (npc._month_foods) all.push(...npc._month_foods); + return all; +} + // ==================== 辅助函数:过滤用户要购买的商品 ==================== function filterUserFoods(foodList) { if (!foodList || !Array.isArray(foodList)) { @@ -231,12 +281,6 @@ let userName = settings.userName || "默认账户"; const ignoreRecords = settings.ignoreRecords || false; const recordDebug = settings.recordDebug || false; -// 解析禁用的商人列表 -const disabledNpcs = (settings.disabledNpcs || "").split(/[,\s、]+/).filter(npc => npc.trim() !== ""); -if (disabledNpcs.length > 0) { - log.info(`已禁用商人: ${disabledNpcs.join(", ")}`); -} - // 解析禁用的标签列表 const disabledTags = (settings.disabledTags || "").split(/[,\s、]+/).filter(tag => tag.trim() !== ""); if (disabledTags.length > 0) { @@ -457,54 +501,71 @@ function shouldBuyFoods(npc, npcRecord, currentPeriod, forceRefresh = false) { "month": [] }; + // 首先检查禁用(此处假设之前已检查过,但为防止遗漏,可再加一道保险) + // 实际上禁用检查在更外层(initNpcData 和主循环)已经处理,这里可以省略 + if (forceRefresh) { - // 强制刷新:所有启用商品都尝试 - if (npc._1d_foods) foodsToBuy["1d"] = filterUserFoods(npc._1d_foods); - if (npc._3d_foods) foodsToBuy["3d"] = filterUserFoods(npc._3d_foods); - if (npc._7d_foods) foodsToBuy["7d"] = filterUserFoods(npc._7d_foods); - if (npc._thu_foods) foodsToBuy["thu"] = filterUserFoods(npc._thu_foods); - if (npc._month_foods) foodsToBuy["month"] = filterUserFoods(npc._month_foods); + // 强制刷新:决定使用完整列表还是具体商品列表 + // 先判断是否命中标签 + let useAll = false; + if (npc.tags && Array.isArray(npc.tags)) { + useAll = npc.tags.some(tag => userTagsToBuy.has(tag)); + } + if (useAll) { + // 标签商人:购买所有商品 + if (npc._1d_foods) foodsToBuy["1d"] = npc._1d_foods; + if (npc._3d_foods) foodsToBuy["3d"] = npc._3d_foods; + if (npc._7d_foods) foodsToBuy["7d"] = npc._7d_foods; + if (npc._thu_foods) foodsToBuy["thu"] = npc._thu_foods; + if (npc._month_foods) foodsToBuy["month"] = npc._month_foods; + } else { + // 非标签商人:只购买用户明确指定的商品 + if (npc._1d_foods) foodsToBuy["1d"] = filterUserFoods(npc._1d_foods); + if (npc._3d_foods) foodsToBuy["3d"] = filterUserFoods(npc._3d_foods); + if (npc._7d_foods) foodsToBuy["7d"] = filterUserFoods(npc._7d_foods); + if (npc._thu_foods) foodsToBuy["thu"] = filterUserFoods(npc._thu_foods); + if (npc._month_foods) foodsToBuy["month"] = filterUserFoods(npc._month_foods); + } return foodsToBuy; } - // 辅助函数:处理单个刷新类型 - function processType(type, enabledFoods, refreshLogic) { - if (!enabledFoods || enabledFoods.length === 0) return []; + // 辅助函数:处理单个类型,根据是否命中标签决定使用完整列表还是过滤列表 + function processType(type, fullList) { + if (!fullList || fullList.length === 0) return []; - // 获取已购买列表(如果记录存在) + // 判断该商人是否命中用户标签(只需判断一次,可在外层缓存结果) + // 此处简单处理:每次调用都判断,但实际可优化 + let useAll = false; + if (npc.tags && Array.isArray(npc.tags)) { + useAll = npc.tags.some(tag => userTagsToBuy.has(tag)); + } + + // 确定要购买的候选商品列表 + let candidateList = useAll ? fullList : filterUserFoods(fullList); + if (candidateList.length === 0) return []; + + // 获取已购买列表 const purchasedList = npcRecord && npcRecord[type] ? npcRecord[type] : []; // 找出未购买的商品 - const notPurchased = enabledFoods.filter(food => !purchasedList.includes(food)); + const notPurchased = candidateList.filter(food => !purchasedList.includes(food)); - // 如果没有记录或没有刷新时间,说明从未买过,全部尝试 if (!npcRecord || !npcRecord[`${type}_time`]) { - return enabledFoods; + return candidateList; // 从未买过,全部尝试 } const nextRefreshTime = new Date(npcRecord[`${type}_time`]); if (now >= nextRefreshTime) { - // 已到刷新时间:所有商品都应重新尝试(已购买和未购买的都可能再次出现) - return enabledFoods; + return candidateList; // 已刷新,全部尝试 } else { - // 未到刷新时间:只尝试从未购买过的商品 - return notPurchased; + return notPurchased; // 未刷新,只尝试未购买过的 } } - // 处理每天刷新商品 - foodsToBuy["1d"] = processType("1d", filterUserFoods(npc._1d_foods)); - - // 处理3天刷新商品 - foodsToBuy["3d"] = processType("3d", filterUserFoods(npc._3d_foods)); - - // 处理7天刷新商品(周一刷新) - foodsToBuy["7d"] = processType("7d", filterUserFoods(npc._7d_foods)); - - // 处理周四刷新商品 - foodsToBuy["thu"] = processType("thu", filterUserFoods(npc._thu_foods)); - - // 处理每月刷新商品 - foodsToBuy["month"] = processType("month", filterUserFoods(npc._month_foods)); + foodsToBuy["1d"] = processType("1d", npc._1d_foods); + foodsToBuy["3d"] = processType("3d", npc._3d_foods); + foodsToBuy["7d"] = processType("7d", npc._7d_foods); + foodsToBuy["thu"] = processType("thu", npc._thu_foods); + foodsToBuy["month"] = processType("month", npc._month_foods); return foodsToBuy; } @@ -719,8 +780,7 @@ let foodROMap = {}; // 键为商品名(中文),值为 RecognitionObject // 加载识别对象(只加载用户选择的商品) async function initRo() { try { - for (let foodName of userFoodsToBuy) { - // 图片文件路径:assets/images/商品名.png + for (let foodName of requiredFoods) { const imagePath = `assets/images/${foodName}.png`; try { const ro = RecognitionObject.TemplateMatch(file.ReadImageMatSync(imagePath)); @@ -732,13 +792,11 @@ async function initRo() { log.error(`加载商品图片失败: ${imagePath},请确保图片存在`); } } - // 加载其他识别对象(购买按钮等) for (let [key, item] of Object.entries(othrtRo)) { item.ro = RecognitionObject.TemplateMatch(file.ReadImageMatSync(item.file)); item.ro.Threshold = 0.85; } - - logConditional(`总共启用了 ${userFoodsToBuy.size} 种商品`); + logConditional(`总共启用了 ${requiredFoods.size} 种商品`); return true; } catch (error) { @@ -915,14 +973,6 @@ async function buyFoods(npcName, npcRecords, currentPeriod) { // 初始化商人商品 async function initNpcData(records) { for (let [key, npc] of Object.entries(npcData)) { - // 检查是否在禁用列表中 - if (disabledNpcs.includes(npc.name)) { - npc.enable = false; - const displayName = getDisplayNameFromPath(npc.path); - logConditional(`已禁用: ${displayName}`); - continue; - } - // 检查是否通过标签禁用 if (npc.tags && Array.isArray(npc.tags)) { const hasDisabledTag = npc.tags.some(tag => disabledTags.includes(tag)); diff --git a/repo/js/自动购买每天&3天&每周刷新商品/manifest.json b/repo/js/自动购买每天&3天&每周刷新商品/manifest.json index b16fa4ffc..e6ef9131a 100644 --- a/repo/js/自动购买每天&3天&每周刷新商品/manifest.json +++ b/repo/js/自动购买每天&3天&每周刷新商品/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 1, "name": "自动购买每天&3天&每周刷新商品", - "version": "3.2.2", + "version": "3.2.3", "description": "自动购买每天&3天&每周刷新商品\n每天刷新商品:自动购买商品\n3天刷新商品:未到刷新日不购买该商品\n每周刷新商品:可指定每周购买商品", "authors": [ { diff --git a/repo/js/自动购买每天&3天&每周刷新商品/settings.json b/repo/js/自动购买每天&3天&每周刷新商品/settings.json index 64c7ac100..9d68d2473 100644 --- a/repo/js/自动购买每天&3天&每周刷新商品/settings.json +++ b/repo/js/自动购买每天&3天&每周刷新商品/settings.json @@ -27,17 +27,11 @@ ], "default": "0" }, - { - "name": "disabledNpcs", - "type": "input-text", - "label": "要禁用的商人\n(多个商人用空格分隔)\n示例:阿扎莱 皮托", - "default": "阿扎莱 皮托" - }, { "name": "disabledTags", "type": "input-text", - "label": "禁用标签\n(多个标签以空格分隔,如:黑心商人 挪德卡莱)", - "default": "" + "label": "禁用标签\n(多个标签以空格分隔,如: 挪德卡莱 黑心商人 卡琵莉亚)", + "default": "卡琵莉亚" }, { "name": "skip", diff --git a/repo/js/自动购买每天&3天&每周刷新商品/商人与商品支持表.md b/repo/js/自动购买每天&3天&每周刷新商品/商人与商品支持表.md index 95b42762d..08bdd294f 100644 --- a/repo/js/自动购买每天&3天&每周刷新商品/商人与商品支持表.md +++ b/repo/js/自动购买每天&3天&每周刷新商品/商人与商品支持表.md @@ -29,7 +29,7 @@ | 璃月-石门 | 老周叔 | 大碗茶 | - | - | 稀少商品 | | 璃月-轻策庄 | 小白 | - | 豆腐、杏仁、霓裳花 | - | 琉璃百合(每月刷新) | | 璃月-轻策庄 | 凯叔 | 大碗茶 | - | - | 稀少商品 | -| 璃月-遗珑埠 | 丰泰 | - | 沉玉仙茗、琉璃袋、绝云椒椒 | 蟹黄 | | +| 璃月-遗珑埠 | 丰泰 | 稻米、豆腐 | 清水玉、石珀、夜泊石、琉璃袋、霓裳花、绝云椒椒、沉玉仙茗 | 蟹黄 | | | 璃月-遗珑埠 | 连芳 | - | 沉玉仙茗 | - | | | 稻妻-离岛 | 小畑 | 螃蟹、鱼肉、虾仁 | 海灵芝 | - | | | 稻妻-离岛 | 秋月 | 铁块、白铁块、电气水晶 | - | - | | @@ -74,10 +74,11 @@ | 挪德卡莱-那夏镇 | 雷科 | - | - | 幸运儿之杯、幸运儿鹰羽、幸运儿银冠、幸运儿绿花、幸运儿沙漏 | 狗粮商人 | | 挪德卡莱-皮拉米达城 | 科菲策 | 牛奶、咖啡豆 | 微光角菌、琉鳞石 | - | 黑心商人 | -- **国家标签**:蒙德、璃月、稻妻、须弥、枫丹、纳塔、挪德卡莱 -- **地区标签**:风起地、清泉镇、蒙德城、璃月港、离岛、稻妻城、海祇岛等 -- **小地图标签**:天使的馈赠、兰巴德酒馆、德波大饭店、灰河、锈舵酒馆等 -- **商人标签**:克罗丽丝、神奇的霍普金斯、杜拉夫等(所有商人名) +### **以下为有效标签** +- **国家**:蒙德、璃月、稻妻、须弥、枫丹、纳塔、挪德卡莱 +- **地区**:风起地、清泉镇、蒙德城、璃月港、离岛、稻妻城、海祇岛等 +- **小地图**:天使的馈赠、兰巴德酒馆、德波大饭店、灰河、锈舵酒馆等 +- **商人**:克罗丽丝、神奇的霍普金斯、杜拉夫等(所有商人名) - **移动**:指商人会移动,有机会购买失败 - **稀少商品**:指稀少商品 - **独立地图**:指需要进入独立空间的特殊地图,这些地图部份路径无法使用地图追踪功能