import _ from 'lodash'; import settings from '../lib/settings.js'; import { rulePrefix } from '../lib/common.js'; import { ZZZPlugin } from '../lib/plugin.js'; const USER_CONFIGS_KEY = 'ZZZ:REMIND:USER_CONFIGS'; // 计算到指定等级为止的S评级数量 function getSRankCountUpTo(allFloorDetail, maxLevel) { const sSet = new Set( allFloorDetail.filter(f => f.rating === 'S').map(f => f.layer_index) ); const minLevel = Math.min(...allFloorDetail.map(f => f.layer_index)); let sRankCount = 0; for (let level = 1; level <= maxLevel; level++) { if (sSet.has(level) || level < minLevel) { sRankCount++; } } return sRankCount; } export class Remind extends ZZZPlugin { constructor() { super({ name: '[ZZZ-Plugin]Remind', dsc: '式舆防卫战/危局强袭战未完成提醒', event: 'message', priority: _.get(settings.getConfig('priority'), 'remind', 70), rule: [ { reg: `${rulePrefix}(开启|关闭)挑战提醒$`, fnc: 'setSubscribeEnable', }, { reg: `${rulePrefix}(开启|启用|关闭|禁用)全局挑战提醒$`, fnc: 'setGlobalRemindEnable', permission: 'master', }, { reg: `${rulePrefix}设置(全局)?式舆阈值\\s*(\\d+)`, fnc: 'setAbyssThreshold', }, { reg: `${rulePrefix}设置(全局)?危局阈值\\s*(\\d+)`, fnc: 'setDeadlyThreshold', }, { reg: `${rulePrefix}查询挑战状态$`, fnc: 'checkNow', }, { reg: `${rulePrefix}设置个人提醒时间\\s*(每日\\d+时(?:(\\d+)分)?|每周.\\d+时(?:(\\d+)分)?)`, fnc: 'setMyRemindTime', }, { reg: `${rulePrefix}个人提醒时间$`, fnc: 'viewMyRemindTime', }, { reg: `${rulePrefix}(重置|删除|取消)个人提醒时间`, fnc: 'deleteMyRemindTime', }, { reg: `${rulePrefix}设置全局提醒时间\\s*(每日\\d+时(?:(\\d+)分)?|每周.\\d+时(?:(\\d+)分)?)`, fnc: 'setGlobalRemindTime', permission: 'master', }, { reg: `${rulePrefix}全局提醒时间$`, fnc: 'viewGlobalRemindTime', }, ], }); const globalRemindConfig = settings.getConfig('remind'); if (globalRemindConfig.enable) { this.task = { name: 'ZZZ-Plugin式舆防卫战/危局强袭战提醒任务', cron: '0 */10 * * * ?', fnc: () => this.runTask(), }; } } async getUserConfig(userId) { const userConfigJson = await redis.hGet(USER_CONFIGS_KEY, String(userId)); return userConfigJson ? JSON.parse(userConfigJson) : null; } async setUserConfig(userId, config) { await redis.hSet(USER_CONFIGS_KEY, String(userId), JSON.stringify(config)); } parseRemindTimeMessage(message) { const pattern = /提醒时间\s*(每日\d+时(?:(\d+)分)?|每周.\d+时(?:(\d+)分)?)/; const match = message.match(pattern); if (!match) return { remindTime: null, error: '时间格式错误' }; const remindTime = match[1]; const minute = Number(match[2]) || Number(match[3]) || 0; if (!(minute % 10 === 0 && minute >= 0 && minute < 60)) { return { remindTime: null, error: '分钟必须为整十分钟' }; } return { remindTime, error: null }; } isTimeMatch(remindTime, date) { if (!remindTime) return false; const currentDay = date.getDay(); // 0 = 周日, 1 = 周一, ..., 6 = 周六 const currentHour = date.getHours(); const currentMinute = date.getMinutes(); if (remindTime.includes('每日')) { const match = remindTime.match(/每日(\d+)时(?:(\d+)分)?/); if (match) { const hour = parseInt(match[1]); const minute = match[2] ? parseInt(match[2]) : 0; return currentHour === hour && currentMinute === minute; } } else if (remindTime.includes('每周')) { const dayMap = { '日': 0, '天': 0, '一': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6 }; const match = remindTime.match(/每周(.)(\d+)时(?:(\d+)分)?/); if (match) { const dayChar = match[1]; const day = dayMap[dayChar]; const hour = parseInt(match[2]); const minute = match[3] ? parseInt(match[3]) : 0; return currentDay === day && currentHour === hour && currentMinute === minute; } } return false; } checkEnableAndFriend() { if (!settings.getConfig('remind').enable) { this.reply('当前未启用防卫战/危局挑战提醒功能'); return false; } if (!(this.e.bot ?? Bot).fl.get(this.e.user_id)) { this.reply('请添加好友后重试'); return false; }; return true; } async setSubscribeEnable() { if (!this.checkEnableAndFriend()) return; const enable = /开启挑战提醒$/.test(this.e.msg); const uid = await this.getUID(); if (enable && !uid) { return this.reply('未绑定UID,请先绑定'); } let userConfig = await this.getUserConfig(this.e.user_id); const defaultConfig = settings.getConfig('remind'); if (!userConfig) { userConfig = { enable: false, abyssCheckLevel: defaultConfig.abyssCheckLevel, deadlyStars: defaultConfig.deadlyStars, }; } if (userConfig.enable === enable) { return this.reply(enable ? '提醒已开启,请勿重复操作' : '提醒功能尚未开启'); } userConfig.enable = enable; await this.setUserConfig(this.e.user_id, userConfig); await this.reply(`提醒功能已${enable ? '开启' : '关闭'}${enable ? `,将在${userConfig.remindTime || defaultConfig.globalRemindTime}对防卫战<${userConfig.abyssCheckLevel}层或危局<${userConfig.deadlyStars}星进行提醒` : ''}`); } async setGlobalRemindEnable() { if (!this.e.isMaster) { return this.reply('仅限主人设置', false, { at: true, recallMsg: 100 }); } const enable = /(开启|启用)全局挑战提醒$/.test(this.e.msg); if (settings.getConfig('remind').enable === enable) { return this.reply(enable ? '全局防卫战/危局挑战提醒功能已启用,请勿重复操作' : '全局防卫战/危局挑战提醒功能已禁用,请勿重复操作'); } settings.setSingleConfig('remind', 'enable', enable); await this.reply(`全局防卫战/危局挑战提醒功能已${enable ? '启用' : '禁用'}`); } async setAbyssThreshold() { const isGlobal = this.e.msg.includes('全局'); if (isGlobal && !this.e.isMaster) { return this.reply('仅限主人设置', false, { at: true, recallMsg: 100 }); } if (!isGlobal && !this.checkEnableAndFriend()) return; const match = this.e.msg.match(/设置(?:全局)?(?:式舆防卫战|式舆|深渊|防卫战|防卫)阈值\s*(\d+)/); if (!match) return; const threshold = Number(match[1]); if (threshold < 1 || threshold > 7) { return this.reply('防卫战阈值必须在1到7之间'); } if (isGlobal) { settings.setSingleConfig('remind', 'abyssCheckLevel', threshold); } else { let userConfig = await this.getUserConfig(this.e.user_id); if (!userConfig) { const defaultConfig = settings.getConfig('remind'); userConfig = { enable: false, abyssCheckLevel: defaultConfig.abyssCheckLevel, deadlyStars: defaultConfig.deadlyStars, }; } userConfig.abyssCheckLevel = threshold; await this.setUserConfig(this.e.user_id, userConfig); }; await this.reply(`${isGlobal ? '全局默认' : ''}式舆防卫战阈值已设为: <${threshold}层时提醒`); } async setDeadlyThreshold() { const isGlobal = this.e.msg.includes('全局'); if (isGlobal && !this.e.isMaster) { return this.reply('仅限主人设置', false, { at: true, recallMsg: 100 }); } if (!isGlobal && !this.checkEnableAndFriend()) return; const match = this.e.msg.match(/设置(?:全局)?(?:危局强袭战|危局|强袭|强袭战)阈值\s*(\d+)/); if (!match) return; const threshold = Number(match[1]); if (threshold < 1 || threshold > 9) { return this.reply('危局阈值必须在1到9之间'); } if (isGlobal) { settings.setSingleConfig('remind', 'deadlyStars', threshold); } else { let userConfig = await this.getUserConfig(this.e.user_id); if (!userConfig) { const defaultConfig = settings.getConfig('remind'); userConfig = { enable: false, abyssCheckLevel: defaultConfig.abyssCheckLevel, deadlyStars: defaultConfig.deadlyStars, }; } userConfig.deadlyStars = threshold; await this.setUserConfig(this.e.user_id, userConfig); } await this.reply(`${isGlobal ? '全局默认' : ''}危局强袭战阈值已设为: <${threshold}星时提醒`); } async checkNow() { const uid = await this.getUID(); if (!uid) return false; const targetUserId = this.e.user_id; let userConfig = await this.getUserConfig(targetUserId); if (!userConfig) { // 如果没有配置,使用默认配置 const defaultConfig = settings.getConfig('remind'); userConfig = { enable: false, // 不开启提醒,仅用于查询 abyssCheckLevel: defaultConfig.abyssCheckLevel, deadlyStars: defaultConfig.deadlyStars, }; } await this.reply('正在查询,请稍候...'); const messages = await this.checkUser(targetUserId, userConfig, true); // 主动查询,显示所有状态 if (messages.length > 0) { await this.reply(messages.join('\n')); } else { await this.reply('查询失败,请稍后再试'); } } getTimeRemaining({ year, month, day, hour, minute, second }) { const targetDate = new Date(year, month - 1, day, hour, minute, second); const now = new Date(); const timeDiff = targetDate - now; if (timeDiff <= 0) return { days: 0, hours: 0 }; const totalHours = Math.floor(timeDiff / (1000 * 60 * 60)); const days = Math.floor(totalHours / 24); const hours = totalHours % 24; return { days, hours }; } async checkUser(userId, userConfig, showAll = false, contextE = null) { let messages = []; const originalE = this.e; this.e = contextE || this.e; let api, deviceFp; try { // 获取 API 和玩家信息 ({ api, deviceFp } = await this.getAPI()); await this.getPlayerInfo(this.e); } catch (error) { logger.error(`[ZZZ-Plugin] 为用户 ${userId} 获取API或玩家信息失败: ${error}`); messages.push('查询失败,请稍后再试'); // 恢复原来的 this.e this.e = originalE; return messages; } const defaultConfig = settings.getConfig('remind'); // 检查式舆防卫战 try { const abyssRawData = await api.getFinalData('zzzChallenge', { deviceFp }); const len = messages.length; if (!abyssRawData || !abyssRawData.has_data) { messages.push('式舆防卫战S评级: 0/7'); } else { const abyssCheckLevel = userConfig.abyssCheckLevel ?? defaultConfig.abyssCheckLevel; const sCount = getSRankCountUpTo(abyssRawData.all_floor_detail, 7); const status = sCount >= abyssCheckLevel ? ' ✓' : ''; if (showAll || sCount < abyssCheckLevel) { messages.push(`式舆防卫战S评级: ${sCount}/7${status}`); } } if (len !== messages.length && abyssRawData?.hadal_begin_time && abyssRawData?.hadal_end_time) { const { hadal_begin_time, hadal_end_time } = abyssRawData; const { days, hours } = this.getTimeRemaining(hadal_end_time); messages.push(`统计周期:${hadal_begin_time.year}/${hadal_begin_time.month}/${hadal_begin_time.day} - ${hadal_end_time.year}/${hadal_end_time.month}/${hadal_end_time.day}`); messages.push(`刷新剩余: ${days}天${hours}小时`); } } catch (error) { logger.error(`[ZZZ-Plugin] 为用户 ${userId} 检查式舆防卫战失败: ${error}`); messages.push(`式舆防卫战查询失败: ${error}`); } // 检查危局强袭战 try { const deadlyRawData = await api.getFinalData('zzzDeadly', { deviceFp }); const len = messages.length; if (!deadlyRawData || !deadlyRawData.has_data) { messages.push('危局强袭战星数: 0/9'); } else { const deadlyStars = userConfig.deadlyStars ?? defaultConfig.deadlyStars; const totalStar = deadlyRawData.total_star || 0; const status = totalStar >= deadlyStars ? ' ✓' : ''; if (showAll || totalStar < deadlyStars) { messages.push(`危局强袭战星数: ${totalStar}/9${status}`); } } if (len !== messages.length && deadlyRawData?.start_time && deadlyRawData?.end_time) { const { start_time, end_time } = deadlyRawData; const { days, hours } = this.getTimeRemaining(end_time); messages.push(`统计周期:${start_time.year}/${start_time.month}/${start_time.day} - ${end_time.year}/${end_time.month}/${end_time.day}`); messages.push(`刷新剩余: ${days}天${hours}小时`); } } catch (error) { logger.error(`[ZZZ-Plugin] 为用户 ${userId} 检查危局强袭战失败: ${error}`); messages.push(`危局强袭战查询失败: ${error}`); } // 恢复原来的 this.e this.e = originalE; return messages; } async runTask() { const globalRemindConfig = settings.getConfig('remind'); if (!globalRemindConfig.enable) { return; } const allUserConfigs = await redis.hGetAll(USER_CONFIGS_KEY); if (Object.keys(allUserConfigs).length === 0) return; logger.debug('[ZZZ-Plugin] 开始执行式舆防卫战/危局强袭战提醒任务'); const now = new Date(); const globalRemindTime = globalRemindConfig.globalRemindTime || '每日20时'; for (const key in allUserConfigs) { const userConfig = JSON.parse(allUserConfigs[key]); if (!userConfig.enable) continue; const userId = +key; if (!Bot.fl.get(userId)) continue; const remindTime = userConfig.remindTime || globalRemindTime; if (this.isTimeMatch(remindTime, now)) { // 创建一个模拟的 e 对象,用于获取 API const mockE = { user_id: userId, game: 'zzz', reply: (msg) => logger.info(`[Remind Mock Reply] ${msg}`) }; const messages = await this.checkUser(userId, userConfig, false, mockE); if (messages.length > 0) { await Bot.pickFriend(userId).sendMsg('【式舆/危局挑战提醒】\n' + messages.join('\n')).catch(err => { logger.error(`[ZZZ-Plugin] 式舆/危局挑战提醒推送用户 ${userId} 失败`, err); }); } } } logger.debug('[ZZZ-Plugin] 式舆防卫战/危局强袭战提醒任务执行完毕'); } async setMyRemindTime() { if (!this.checkEnableAndFriend()) return; const { remindTime, error } = this.parseRemindTimeMessage(this.e.msg); if (!remindTime) return await this.reply(error); let userConfig = await this.getUserConfig(this.e.user_id); if (!userConfig) { const defaultConfig = settings.getConfig('remind'); userConfig = { enable: false, abyssCheckLevel: defaultConfig.abyssCheckLevel, deadlyStars: defaultConfig.deadlyStars, }; } userConfig.remindTime = remindTime; await this.setUserConfig(this.e.user_id, userConfig); await this.reply(`您的个人提醒时间已设置为: ${remindTime}`); } async viewMyRemindTime() { const userConfig = await this.getUserConfig(this.e.user_id); if (userConfig && userConfig.remindTime) { await this.reply(`当前个人提醒时间: ${userConfig.remindTime}`); } else { const remindConfig = settings.getConfig('remind'); const globalRemindTime = remindConfig.globalRemindTime || '每日20时'; await this.reply(`个人提醒时间未设置,默认使用全局时间: ${globalRemindTime}`); } } async deleteMyRemindTime() { if (!this.checkEnableAndFriend()) return; let userConfig = await this.getUserConfig(this.e.user_id); if (userConfig && userConfig.remindTime) { delete userConfig.remindTime; await this.setUserConfig(this.e.user_id, userConfig); await this.reply('个人提醒时间已重置为全局默认时间'); } else { await this.reply('个人提醒时间尚未设置'); } } async setGlobalRemindTime() { if (!this.e.isMaster) { return this.reply('仅限主人设置', false, { at: true, recallMsg: 100 }); } const { remindTime: globalRemindTime, error } = this.parseRemindTimeMessage(this.e.msg); if (!globalRemindTime) return await this.reply(error); settings.setSingleConfig('remind', 'globalRemindTime', globalRemindTime); await this.reply(`全局提醒时间已更新为: ${globalRemindTime}`); } async viewGlobalRemindTime() { const globalRemindTime = settings.getConfig('remind').globalRemindTime || '每日20时'; await this.reply(`当前全局提醒时间: ${globalRemindTime}`); } }