You need to enable JavaScript to run this app. discord.js开发Discord机器人,如何匹配用户输入带属性参数并赋值变量
优惠活动
大模型
产品
解决方案
定价
更多

discord.js开发Discord机器人,如何匹配用户输入带属性参数并赋值变量

实现方案

核心改造方向

  • 替换原有的硬编码顺序取参逻辑,实现通用参数解析器,支持任意顺序的标签式输入,兼容at: 5、at:5这类带/不带空格的写法
  • 给所有计算参数配置和原规则对齐的默认值,解决用户漏输参数导致计算出NaN的问题,不需要用户每次输全所有值
  • 单独维护纯开关参数集合,识别到无附带值的开关标签时,自动触发对应计算分支并入最终输出
  • 保留原有顺序输入的兼容性,不破坏老用户的使用习惯

参数解析逻辑设计

  1. 提前定义短标签和内部参数名的映射关系:at对应攻击数、sk对应命中技能、st对应力量值、t对应坚韧值、sv对应护甲豁免值
  2. 单独维护开关参数集合,包含fnp、res这类无值即可触发逻辑的标签
  3. 遍历所有输入参数逐段解析:
    • 遇到带冒号的参数时,拆分键值对,校验值为有效数字后更新对应内部参数
    • 遇到不带冒号、且属于开关集合的参数时,将对应开关标记设为触发状态
    • 检测到用户没有输入任何标签/开关参数时,自动回退到原有的顺序解析逻辑
  4. 输出拼接时可根据需求判断参数是否被用户覆盖,若需要排除缺失参数的对应计算内容,直接跳过对应段落的拼接即可
改造后完整可运行代码
const { Message } = require('discord.js')
// 短标签与内部参数映射表
const PARAM_TAG_MAP = {
  at: 'attack',
  sk: 'skill',
  st: 'strength',
  t: 'toughness',
  sv: 'save'
}
// 纯开关参数集合:出现即触发逻辑,无需附带值
const SWITCH_PARAMS = new Set(['fnp', 'res'])

module.exports = {
    name: 'odds',
    aliases: ['stats', 'probability'],
    usage: '支持两种输入格式:\n- 兼容旧版顺序输入: !odds [攻击数] [命中技能] [力量] [坚韧] [护甲豁免值]\n- 新版自定义标签输入: !odds at:数值 sk:数值 st:数值 t:数值 sv:数值 可追加开关参数(fnp/res)',
    description: '伤害概率均值计算器',

    execute(message, args) {
        // 初始化参数,配置和原规则对齐的默认值
        const params = {
            attack: 1,
            skill: 3,
            strength: 4,
            toughness: 4,
            save: 7,
            switchFlags: {
                fnp: false,
                res: false
            }
        }

        // 逐段解析输入参数
        let hasCustomInput = false
        args.forEach(rawArg => {
            const arg = rawArg.trim().toLowerCase()
            // 解析带冒号的键值标签参数
            if (arg.includes(':')) {
                const [tag, rawVal] = arg.split(':').map(s => s.trim())
                // 标签存在、值为有效数字时才更新参数,避免非法输入覆盖默认值
                if (PARAM_TAG_MAP[tag] && !isNaN(Number(rawVal))) {
                    params[PARAM_TAG_MAP[tag]] = Number(rawVal)
                    hasCustomInput = true
                }
            } 
            // 解析纯开关参数
            else if (SWITCH_PARAMS.has(arg)) {
                params.switchFlags[arg] = true
                hasCustomInput = true
            }
        })

        // 无自定义标签输入时,回退到旧版顺序解析逻辑
        if (!hasCustomInput && args.length > 0) {
            if (args[0]) params.attack = Number(args[0])
            if (args[1]) params.skill = Math.min(7, Number(args[1])) // 技能超过7按自动命中处理
            if (args[2]) params.strength = Number(args[2])
            if (args[3]) params.toughness = Number(args[3])
            if (args[4]) params.save = Math.max(2, Number(args[4])) // 豁免低于2按6+保护处理
        }

        // 计算逻辑与原实现完全对齐
        const hits = parseFloat((params.attack * ((7 - params.skill)/6)).toFixed(2))
        const hitSixes = parseFloat((params.attack * (1/6)).toFixed(2))
        
        let woundFactor = 6
        if (params.strength >= (2 * params.toughness)) woundFactor = 2
        else if (params.strength > params.toughness) woundFactor = 3
        else if (params.strength === params.toughness) woundFactor = 4
        else if (params.toughness >= (2 * params.strength)) woundFactor = 6
        else if (params.strength < params.toughness) woundFactor = 5

        const wounds = parseFloat((hits * ((7 - woundFactor)/6)).toFixed(2))
        const woundSixes = parseFloat((hits * (1/6)).toFixed(2))
        const unsavedWounds = parseFloat((wounds * (params.save <= 6 ? (7 - params.save)/6 : 0)).toFixed(2))

        // 接入开关参数的额外计算分支
        let extraResult = ''
        if (params.switchFlags.fnp) {
            // 按标准3+无痛感规则计算,可根据实际规则调整概率值
            const afterFnp = parseFloat((unsavedWounds * (4/6)).toFixed(2))
            extraResult += `\n经过3+无痛感(Feel No Pain)判定后,剩余平均伤害为 ${afterFnp}`
        }
        if (params.switchFlags.res) {
            // 按标准6+抗性规则计算
            const afterRes = parseFloat((unsavedWounds * (5/6)).toFixed(2))
            extraResult += `\n经过6+抗性(Resistant)判定后,剩余平均伤害为 ${afterRes}`
        }

        // 发送最终计算结果
        message.channel.send(`平均计算结果:\n${hits} 次成功命中(其中包含 ${hitSixes} 次自然6)\n${wounds} 次成功造伤(其中包含 ${woundSixes} 次自然6)\n最终平均造成 ${unsavedWounds} 点无豁免伤害${extraResult}`)
    }
}

兼容性说明

  • 标签识别不区分大小写,输入AT:5、At:5、at:5均可正常解析
  • 参数校验做了容错:如果用户输入的标签值不是有效数字,不会覆盖默认值,避免计算出错
  • 原有计算逻辑完全保留,不会因为参数解析改造改变原有输出结果

内容的提问来源于stack exchange,提问作者Rik Powell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.13 04:45:02