作者 主题: 关于细化士气机制的探讨  (阅读 828 次)

副标题:

离线 \星尘/

  • Chivary
  • *****
  • 帖子数: 1945
  • 苹果币: 6
  • 星尘
关于细化士气机制的探讨
« 于: 2024-03-17, 周日 09:50:59 »
5e dmg中有如下战斗选用项,而其他d20系规则如pf等,也有关于士气的规则。
引用
一些战斗人员可能会在一场战斗对自己不利时逃跑。你可以使用该选用规则来判定怪物和 NPC什么时候决定弃逃。
单个生物可能会在下列情况里选择逃跑:

该生物被突袭。
该生物在战斗中第一次被减少至一半或更少的生命值。
该生物无法在其自己的回合里伤害敌方人员。
一群生物可能会在以下情况里选择逃跑:

团体里所有生物都被突袭。
团体的领袖生命值被降至0,陷入失能,被俘虏或被从战斗中移除。
团体人员减少为原来的一半,而对方却没有人员损失。
为判定单个生物或一群生物是否决定逃走,你可以为该生物或该团体的领袖进行一次DC 10的感知豁免。如果对方势力碾压,则该豁免具有劣势,或者你也可以判定该豁免直接失败。如果团队的领袖因某些原因无法进行豁免,则团队中拥有最高魅力值的生物代为进行该豁免。

若豁免失败,则受影响的生物或团体依最快捷的路线逃跑。若无法实现逃离,则该生物或团体投降。已投降的生物或团体若受其投降方攻击,则双方战斗会重新展开,且此后不太可能再次作逃跑或投降的尝试。

这样的豁免失败在冒险者们看来不一定都是好事。例如,一个食人魔从战斗中逃跑,可能会导致地下城的其他地区敲响警报,或是它可能直接带着角色们要夺取的财宝逃之夭夭。

近期游玩《行商浪人》有所启发,这款采用战锤桌游规则游戏的战斗机制具有一个根据敌我状态或行动变动的士气机制,如果士气过高或过低,都可以发动对应的“英雄壮举”或者“背水一战”。

由此,本人草草撰写了一个简单的规则选用项,希望观者能给出意见。

需要预先说明的是,此规则选用项的使用场景为“配合融洽的长团”或“有一定默契的固桌”,其适用的跑团风格为“英雄奇幻”、“神话奇幻”、“史诗奇幻”或与之类似的故事,但并不适用于“暗黑奇幻”或“阴谋与悬疑”类型。

引用
一支互相熟悉的冒险者小队的战斗热情可以用士气来衡量,而它的积攒或丧失可以一定程度上影响战局。例如,全队齐心协力积攒的,可以扭转战局的绝招,或是背水一战的勇气,甚至是寻找逃离出路的敏锐目光。

身为主角的小队具有一个士气槽,士气的范围为0-30,dm可以适当调整这个范围阈值,以影响士气类技能触发的频率。在战斗开始时,士气的初始值为士气范围的中位数(即15)。

当一个生物的回合开始,且己方小队士气值达到最大时,可以使用极限技,如果低于某个阈值,则可以使用奋战技。dm也可以设置一些用反应触发的士气技能。

使用极限技或奋战技后,士气将回落至初始值重新积攒。

极限技与奋战技具体的效果可以由DM为每个角色量身定制,在本选用规则的末尾会给出一些范例。

一些英勇、取得胜果、控制敌人的行动会激励盟友,提高士气值。
将一个敌人的生命值降低至0(每回合一次,提高2),将敌人生命值降低至一半(每回合一次,提高1),对敌人成功施加状态表中的负面效果(每回合一次,提高1),在d20挑战的最终判定结果骰出20(提高1),一个生物的回合结束时在回合内造成过伤害(提高1),为盟友施加了增益效果(每回合一次,提高1)。

一些怯懦、战斗失利、被控制的行动会积蓄战斗的焦虑,降低士气值。
盟友的生命值被降低至0(每回合一次,降低2),盟友的生命值被降低至0(每回合一次,降低1),盟友被施加状态表中的负面效果(每回合一次,降低1),在d20挑战的最终判定结果骰出1(降低1),一个生物的回合结束时,在回合时进行的攻击检定半数失手(降低1),盟友被施加了减益效果(每回合一次,降低1)。

士气技能示例:

战斗怒吼 [极限技]
需求:士气值达到最大时
消耗:1附赠动作
你以战斗激励盟友,指定一个你能看到的目标,直到你的下一个回合开始前,你和你的盟友对所有能听见你的敌人进行的攻击检定具有优势,且优势始终被应用,无法被劣势抵消。

寻找出路 [奋战技]
需求:士气值低于3
消耗:1动作
鉴于战局不利,你开始寻找撤退的路线,你进行一次调查(智力)或察觉(感知)检定,其DC由dm设定,越难以逃脱的战斗环境,这个DC越高。如果你检定未成功,士气值不会回复,且再降低1,如果你检定成功,你与你的所有盟友可以立刻向远离敌人的方向移动等同于自己行动力的距离,且不会引发借机攻击。被受到速度降低效果影响,但仍保有神志的生物可以立即进行一次具有优势的检定以摆脱对应效应。
若盟友移动的距离路线上有陷入失能状态(但未被擒抱或束缚)的盟友,则可以将其拉走,与自身一起移动。

殉道者的干涉 [奋战技]
先决:拥有提供生命值回复的能力
需求:士气值低于7
触发:射程中的生物即将受到伤害导致其生命值减少至0
消耗:1反应
你的小队落入了危险的境地,你暗暗积蓄着治愈能量,让盟友不会倒地,尽管这会对你造成伤势。你用自己的生命能量保护一个陷入危机的生物,自己承担伤害来拯救它的生命。目标生命值减少至1,而不是0。该次伤害中被阻止的部分全部被转移给你。
作为反应的一部分,你还可以立即激活一次提供生命值回复的能力。如果这个能力是依靠消耗法术位运作的,那么它的有效法术环级等同于你的熟练加值。

这种规则会增加战斗的判定数据,但可以编写骰子插件,或FVTT的MOD来进行辅助。
劇透 -   :

海豹骰插件↓
代码: [选择]
// ==UserScript==
// @name         士气系统(星尘的DND房规
// @author       星尘
// @version      1.0.0
// @description  士气系统,默认士气为0-20,可用指令如下\n .bp setmax < 整数 > 设置最大士气\n .bp set < 整数 > 直接设定士气\n .bp < 变化 >(如 + 1、-1) 士气变化.bp re 重置士气 .bp 查看当前士气
// @timestamp    1710647207
// 2024-03-17
// @license      Apache-2
// @homepageURL  https://github.com/sealdice/javascript
// ==/UserScript==

// 编写一条自定义指令
// 先将扩展模块创建出来,如果已创建就直接使用
let ext = seal.ext.find('士气');
if (!ext) {
    ext = seal.ext.new('士气', '星尘', '1.0.0');
    seal.ext.register(ext);
}

// 创建指令 .seal
// 这个命令的功能为,显示「抓到一只海豹」的文案;
// 如果命令写 .seal ABC,那么文案中将海豹命名为「ABC」;
// 如果命令中没写名字,那么命名为默认值「氪豹」。
const cmdBp = seal.ext.newCmdItemInfo();
cmdBp.name = 'bp'; // 指令名字,可用中文
cmdBp.help = `士气系统,默认士气为0-20,可用指令如下\n
                .bp setmax <整数> 设置最大士气\n
                .bp set <整数> 直接设定士气\n
                .bp <变化>(如+1、-1) 士气变化
                .bp re 重置士气\n
                .bp help 查看帮助\n
                .bp 查看当前士气`;

let bpMin = 0;
let bp = 10;
let bpMax = 20;
let bpMedian = 10;
let bpMaxConfigMap = new Map();
let bpDataMap = new Map();
let bpMedianMap = new Map();
/* 士气值打印函数,参数为当前士气与最大士气,返回值为美观的士气值字符串 ,例如 (Min<===|========>Max)*/
function printBP(bp, bpMax) {
    let bpStr = '\(Min<';
    for (let i = bpMin; i < bp - 1; i = i + 2) {
        bpStr += '=';
    }
    bpStr += '|';
    for (let i = bp; i < bpMax; i = i + 2) {
        bpStr += '=';
    }
    bpStr += '>Max\)';
    return bpStr;
}




// 主函数,指令解析器会将指令信息解析,并储存在几个参数中
// ctx 主要是和当前环境以及用户相关的内容,如当前发指令用户,当前群组信息等
// msg 为原生态的指令内容,如指令文本,发送平台,发送时间等
// cmdArgs 为指令信息,会将用户发的信息进行分段,方便快速取用
cmdBp.solve = (ctx, msg, cmdArgs) => {
    // 获取第一个参数,例如 .seal A B C
    // 这里 cmdArgs.getArgN(1) 的结果即是 A,传参为 2 的话结果是 B
    let val = cmdArgs.getArgN(1);
    switch (val) {
        case 'help': {
            // 命令为 .seal help
            // 创建一个结果对象,并将 showHelp 标记为 true,这会自动给用户发送帮助
            const ret = seal.ext.newCmdExecuteResult(true);
            ret.showHelp = true;
            return ret;
        }
        case 'setmax': {
            // 检测该群组是否已设置最大士气值,没有则初始化
            if (!(bpMaxConfigMap.has(ctx.group.groupId)) && !(bpDataMap.has(ctx.group.groupId))) {
                bpMaxConfigMap.set(ctx.group.groupId, 20);
                bpDataMap.set(ctx.group.groupId, 10);
                bpMedianMap.set(ctx.group.groupId, 10);
            }
            bpMax = parseInt(cmdArgs.getArgN(2));
            bpMedian = Math.round(bpMax / 2);
            bpMaxConfigMap.set(ctx.group.groupId, bpMax);
            bpMedianMap.set(ctx.group.groupId, bpMedian);
            bpDataMap.set(ctx.group.groupId, bpMedian);
            seal.replyToSender(ctx, msg, `\(最大士气值已设置为${bpMax}\)`);
            return seal.ext.newCmdExecuteResult(true);
        }
        case 'maxset': {
            // 检测该群组是否已设置最大士气值,没有则初始化
            if (!(bpMaxConfigMap.has(ctx.group.groupId)) && !(bpDataMap.has(ctx.group.groupId))) {
                bpMaxConfigMap.set(ctx.group.groupId, 20);
                bpDataMap.set(ctx.group.groupId, 10);
                bpMedianMap.set(ctx.group.groupId, 10);
            }
            bpMax = parseInt(cmdArgs.getArgN(2));
            bpMaxConfigMap.set(ctx.group.groupId, bpMax);
            bpMedianMap.set(ctx.group.groupId, Math.round(bpMax / 2));
            seal.replyToSender(ctx, msg, `\(最大士气值已设置为${bpMax}\)`);
            return seal.ext.newCmdExecuteResult(true);
        }
        case 'set': {
            if (!(bpMaxConfigMap.has(ctx.group.groupId)) && !(bpDataMap.has(ctx.group.groupId))) {
                bpMaxConfigMap.set(ctx.group.groupId, 20);
                bpDataMap.set(ctx.group.groupId, 10);
                bpMedianMap.set(ctx.group.groupId, 10);
            }
            bpMax = bpMaxConfigMap.get(ctx.group.groupId);
            bp = parseInt(cmdArgs.getArgN(2));
            if (bp > bpMax || bp < 0) {
                seal.replyToSender(ctx, msg, `超出解限或为负数,最大士气为${bpMax}`);
                return seal.ext.newCmdExecuteResult(true);
            }

            bpDataMap.set(ctx.group.groupId, bp);
            seal.replyToSender(ctx, msg, printBP(bp, bpMax) + `\n\(士气值变化至${bp}\)`);
            if (parseInt(bp) === parseInt(bpMax)) {
                seal.replyToSender(ctx, msg, `(士气已经上升至最大!)`);
            }
            return seal.ext.newCmdExecuteResult(true);
        }
        case 're': {
            if (!(bpMaxConfigMap.has(ctx.group.groupId)) && !(bpDataMap.has(ctx.group.groupId))) {
                bpMaxConfigMap.set(ctx.group.groupId, 20);
                bpDataMap.set(ctx.group.groupId, 10);
                bpMedianMap.set(ctx.group.groupId, 10);
            }
            bpMax = bpMaxConfigMap.get(ctx.group.groupId);
            bp = bpMedianMap.get(ctx.group.groupId);
            bpDataMap.set(ctx.group.groupId, bp);
            seal.replyToSender(ctx, msg, printBP(bp, bpMax) + `\n\(士气值已重置\)`);
            return seal.ext.newCmdExecuteResult(true);
        }
        default: {
            if (!(bpMaxConfigMap.has(ctx.group.groupId)) && !(bpDataMap.has(ctx.group.groupId))) {
                bpMaxConfigMap.set(ctx.group.groupId, 20);
                bpDataMap.set(ctx.group.groupId, 10);
                bpMedianMap.set(ctx.group.groupId, 10);
            }
            bp = bpDataMap.get(ctx.group.groupId);
            bpMax = bpMaxConfigMap.get(ctx.group.groupId);
            // 如果是类似于-1 +1 *2 /2 这样的算式,就对bp的数值进行计算
            if (val.match(/^[\+\-\*\/]\d+$/)) {

                let op = val.charAt(0);
                let num = parseInt(val.substring(1));
                switch (op) {
                    case '+':
                        bp += num;
                        if (bp > bpMax) bp = bpMax;
                        break;
                    case '-':
                        bp -= num;
                        if (bp < 0) bp = 0;
                        break;
                    case '*':
                        bp *= num;
                        if (bp > bpMax) bp = bpMax;
                        break;
                    case '/':
                        bp /= num;
                        bp = Math.round(bp);
                        break;
                }
                bpDataMap.set(ctx.group.groupId, bp);
                seal.replyToSender(ctx, msg, printBP(bp, bpMax) + `\n\(士气值${op}${num},变化至${bp}\)`);
                if (parseInt(bp) === parseInt(bpMax)) {
                    seal.replyToSender(ctx, msg, `(士气已经上升至最大!)`);
                    return seal.ext.newCmdExecuteResult(true);
                }
                return seal.ext.newCmdExecuteResult(true);
            }
            // 如果为空则直接打印士气值
            if (val === '') {
                seal.replyToSender(ctx, msg, printBP(bp, bpMax) + `\n\(当前士气值为${bp}\)`);
                return seal.ext.newCmdExecuteResult(true);
            }

            // 命令为 .seal XXXX,取第一个参数为名字
            // if (!val) val = '氪豹';
            // // 进行回复,如果是群聊发送那么在群里回复,私聊发送则在私聊回复 (听起来是废话文学,但详细区别见暗骰例子)
            // seal.replyToSender(ctx, msg, `你抓到一只海豹!取名为${val}\n它的逃跑意愿为${Math.ceil(Math.random() * 100)}`);
            // return seal.ext.newCmdExecuteResult(true);
        }
    }
};

// 将命令注册到扩展中
ext.cmdMap['bp'] = cmdBp;
« 上次编辑: 2024-03-17, 周日 12:02:51 由 \星尘/ »
银色的龙儿记录着旅程中收集的故事,细心地收纳于云雾中的巢穴
已经结束的故事在这里沉睡,新的故事正被撰写。

欢迎访问持续维护的枭熊1地图镜像The Trove dnd与coc原文资源镜像站FVTT世界安装包资源站5e不全书在线chm3r全书在线chm3r扩展在线chmPF1大合集在线chm染色器果园角色卡展示生成器MD2BBCODE格式转换器

最新版5e不全书

离线 shenanigan

  • Adventurer
  • *
  • 帖子数: 64
  • 苹果币: -1
Re: 关于细化士气机制的探讨
« 回帖 #1 于: 2024-03-17, 周日 09:55:11 »
2e有morale相关检定建议

离线 Juiblex

  • Hero
  • ****
  • 帖子数: 814
  • 苹果币: 6
Re: 关于细化士气机制的探讨
« 回帖 #2 于: 2024-03-17, 周日 10:09:12 »
然后牧师有一个根据周围敌人人数成比例提升士气的技能,通过拿专长还能让周围的邪魔生物收到等同于士气提升的光耀伤害

即使在行商浪人里,战士也拥有名为终结技的动作如潮,无论到哪个游戏都是一样自信
城龙说 每一张人物卡都给你带来快乐和回忆,所以跑完团要把它们丢进垃圾桶里面 你要好好地珍惜它们
邪魔崇拜者的城市生态
维克纳兄弟电影公司的特效片指南

离线 调零

  • 史莱姆娘生态研究员
  • Hero
  • ****
  • 帖子数: 848
  • 苹果币: 1
  • 已经不是骰主了
Re: 关于细化士气机制的探讨
« 回帖 #3 于: 2024-03-17, 周日 10:51:13 »
引用
但可以编写骰子插件

离线 白戈

  • Chivary
  • *****
  • 帖子数: 1325
  • 苹果币: 4
Re: 关于细化士气机制的探讨
« 回帖 #4 于: 2024-03-17, 周日 13:21:17 »
如果高和低都是收益的话,玩家似乎并不需要刻意在意士气条? :em008

离线 \星尘/

  • Chivary
  • *****
  • 帖子数: 1945
  • 苹果币: 6
  • 星尘
Re: 关于细化士气机制的探讨
« 回帖 #5 于: 2024-03-17, 周日 15:34:09 »
如果高和低都是收益的话,玩家似乎并不需要刻意在意士气条? :em008

战局占优的话用于增加战斗参与感,战局劣势用于放水 :em001
银色的龙儿记录着旅程中收集的故事,细心地收纳于云雾中的巢穴
已经结束的故事在这里沉睡,新的故事正被撰写。

欢迎访问持续维护的枭熊1地图镜像The Trove dnd与coc原文资源镜像站FVTT世界安装包资源站5e不全书在线chm3r全书在线chm3r扩展在线chmPF1大合集在线chm染色器果园角色卡展示生成器MD2BBCODE格式转换器

最新版5e不全书

离线 弑君者伊恩

  • 但他举起了投枪!
  • Flawless
  • *******
  • 帖子数: 4153
  • 苹果币: 3
    • 卷轴之路TRPG
Re: 关于细化士气机制的探讨
« 回帖 #6 于: 2024-03-17, 周日 15:45:49 »
我觉得士气条作为一个要追踪的数值资源太复杂了,还是做一个三五个档位的士气档(高涨,普通,低落,动摇),在特定条件下进行士气检定改变档位,更易于追踪记录和设计扩展能力
始终如一的男人。

  规则链接点我。专区链接
关于PF1魔战士魔战士随笔

离线 shenanigan

  • Adventurer
  • *
  • 帖子数: 64
  • 苹果币: -1
Re: 关于细化士气机制的探讨
« 回帖 #7 于: 2024-03-17, 周日 17:49:55 »
我觉得士气条作为一个要追踪的数值资源太复杂了,还是做一个三五个档位的士气档(高涨,普通,低落,动摇),在特定条件下进行士气检定改变档位,更易于追踪记录和设计扩展能力
写个处理多部署的战阵规则

离线 paro

  • Knight
  • ***
  • 帖子数: 311
  • 苹果币: 5
Re: 关于细化士气机制的探讨
« 回帖 #8 于: 2024-03-17, 周日 18:02:21 »
2e有morale相关检定建议

tsr时代dnd的morale跟楼主想要的士气很明显不是一回事

离线 shenanigan

  • Adventurer
  • *
  • 帖子数: 64
  • 苹果币: -1
Re: 关于细化士气机制的探讨
« 回帖 #9 于: 2024-03-17, 周日 18:24:13 »
2e有morale相关检定建议

tsr时代dnd的morale跟楼主想要的士气很明显不是一回事
楼主引用的dmg可选也是对NPC战斗意愿的衡量,辅助决定他们是否会弃战投降或者逃跑,用于PC方有楼上说的持续buff的问题(而且2e规则书直接解释了为什么morale更适用于NPC而非PC:In almost all situations, players should be the ones who decide what their characters do. A DM should never tell a player, "Your character decides he doesn't want to get hurt and runs from the fight," unless that character is charmed and therefore controlled by the DM.
A suggestion that a character might want to retreat, advance, open a chest, or whatever, is all right, but a DM shouldn't force a player character to do something by simply insisting. Only under the most unusual circumstances—charm, magical fear, or other forced effects—should the DM dictate the actions of a player character.
Monsters and NPCs are an entirely different matter, however. The DM makes their decisions, trying to think like each creature or non-player character, in turn.)