
SparkleBanditTweaks
调整了盗贼的技能组。BanditSmokeBombSpeed — 盗贼烟雾弹重做
技能总览(v3.7.0)
- 主要技能:迸射 100%×5(500%)→80%×5(400%),触发系数 0.5→0.75;轰击 330%→380%。
- 次要技能:锯齿匕首、锯齿小刀 未暴击改为流血,暴击仍出血。
- 辅助技能:烟雾弹 伤害降低、移速 +40%→+150% 起,每 0.3 秒衰减 15%、3 秒归零。
- 特殊攻击:熄灯 600%→800%,击杀不再重置冷却,命中清除目标流血与出血层数并按层数结算伤害;亡命徒 600%→800%,每层增幅 +10%→+5% 且作用于主要技能。
以上数值均可配置(见下文的配置文件说明)。
当前状态:v3.7.0 已编译完成,用 r2modman 的「+ → Install from file」装进
BepInEx\plugins\SparkleBanditTweaks.dll后直接启动游戏即可生效。
效果
烟雾弹(Shift)
盗贼 Shift 技能「Smoke Bomb / 烟雾弹」进入隐身后,同时改三件事:
1. 移动速度(阶梯衰减)
- 起始 +150% 移速(最终移速是基础值的 2.5 倍)
- 每 0.3 秒减 15 个百分点
- 正好 3 秒减完(10 档 × 0.3 秒),与技能持续时间一致
- 隐身中断立刻归零(比如隐身期间用了攻击技能提前现身)
| 时间 | 0.0s | 0.3s | 0.6s | 0.9s | 1.2s | 1.5s | 1.8s | 2.1s | 2.4s | 2.7s | 3.0s |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 加成 | +150% | +135% | +120% | +105% | +90% | +75% | +60% | +45% | +30% | +15% | 0% |
把配置里的 DecayMode 改成 Relative 会切成按比例衰减(每档 ×0.85),
那就是 +150% → +127.5% → +108% → …,前段掉得快、后段拖尾,但不会减到 0。
2. 伤害从每段 200% 降到 120%
改的是 EntityStates.Bandit2.StealthMode.blastAttackDamageCoefficient,
进隐身和出隐身各炸一次(OnEnter / OnExit 都调 FireSmokebomb),两段都会受影响,
所以技能说明里才写「造成 120% 伤害……然后再次造成 120% 伤害」。
眩晕不受影响 —— 眩晕来自 damageType 里的 DamageType.Stun1s(值 32),
和伤害高低无关,所以现在是「120% 伤害 + 眩晕」,和原版一样会晕人。
3. 技能说明文本
用 R2API 的 LanguageAPI 覆盖 BANDIT2_UTILITY_DESCRIPTION,中英文都改成:
眩晕。造成 120%的伤害,进入 隐身,然后再次造成 120%的伤害。在此期间获得持续衰减的 +150%移动速度。
<style=cIsDamage> / <style=cIsUtility> 是游戏原生的富文本标记,
进游戏后会自动显示成对应的伤害色 / 功能色,和原版技能的排版一致。
不喜欢可以把配置里的 OverrideSkillDescription 设成 false 恢复原版文案。
两个 R 技能(亡命徒 / 熄灯)
- 亡命徒与熄灯的基础倍率都从 600% → 800%
- 亡命徒的叠层增伤 每层 +10% → 每层 +5%
- 叠层增伤现在对 M1 也生效 —— 迸射(霰弹)和轰击(步枪)都吃到同样的每层加成
实际倍率 = DesperadoDamagePercent × (1 + StackDamageBonus × 层数)。
举例 5 层时:亡命徒 800% × 1.25 = 1000%,M1 则是在自己基础倍率上 ×1.25。
原版只有亡命徒自己读
BanditSkullbuff(FireSidearmSkullRevolver.ModifyBullet), M1 完全不读,所以第三条是新增行为。
倍率改动为什么是"缩放"而不是"改字段":damageCoefficient 是实例字段
(IL 里是 ldfld 不是 ldsfld),值由 EntityStateConfiguration 按技能填进去,
没法像烟雾弹那样直接改静态字段。所以改成在 ModifyBullet 之后按比例缩放 damage。
两个 R 技能的类(亡命徒 FireSidearmSkullRevolver、熄灯 FireSidearmResetRevolver)
都在自己的 ModifyBullet 第一条指令就 call base.ModifyBullet,
因此补丁打在共用的基类 BaseFireSidearmRevolverState.ModifyBullet 上就能一次覆盖两个。
技能说明会按配置值自动生成,例如:
屠戮者。使用左轮手枪进行射击,造成 800%的伤害。击败敌人可以 叠加效果,使亡命徒与主武器的伤害提高 5%。
熄灯(默认 R 技能)重做
- 移除原版的「击败敌人可以重置所有能力的冷却时间」
- 新增:命中时清掉目标身上所有的出血与流血,并按移除的层数一次性结算伤害
- 每层 出血 = 2000% 基础伤害(出血 = 盗贼 M2 暴击造成的效果)
- 每层 流血 = 240% 基础伤害(流血 = 三尖匕首造成的效果)
- 这次伤害
procCoefficient = 0,不会触发任何道具效果 - 举例:目标身上 5 层出血 + 3 层流血 →
5 × 2000% + 3 × 240% = 10720%基础伤害
「出血」在游戏里的 DoT 类型是
DotController.DotIndex.SuperBleed, 「流血」是DotController.DotIndex.Bleed,两者都挂在目标的DotController上。
移除击杀重置冷却的原理:熄灯的 FireSidearmResetRevolver.ModifyBullet 会给子弹打上
bulletAttack.damageType |= DamageType.ResetCooldownsOnKill(枚举值 4),
击杀时游戏读到这个标记就清冷却。所以在子弹发射前把这个位清掉,效果就整体失效了。
两个 M2(锯齿匕首 / 锯齿小刀)
保留原版的「暴击造成出血」,新增「未暴击造成流血」:
- 锯齿匕首(360%,突进挥砍)
- 锯齿小刀(240%,隐匿掷刀)
两个技能都不自己施加 debuff,只在伤害上打标记
DamageType.SuperBleedOnCrit(值 134217728),暴击与否由GlobalEventManager统一处理。 所以只要在命中回调里补一句「带这个标记但没暴击 → 施加 Bleed」, 原版的暴击出血完全不受影响。
两个 M1(迸射 / 轰击)
| 技能 | 原版 | 改后 | 触发系数 |
|---|---|---|---|
| 迸射(霰弹枪) | 5 × 100% | 5 × 80%(满命中 400%) | 0.75 |
| 轰击(步枪) | 330% | 380% | 不变 |
damageCoefficient/procCoefficient都是实例字段,由EntityStateConfiguration按技能填值(IL 里看不到数字,语言文件写着 5x100% / 330%), 所以沿用亡命徒那套:在ModifyBullet之后按比例缩放bulletAttack.damage, 触发系数直接覆盖bulletAttack.procCoefficient。 霰弹的FireBullet按bulletCount循环调Fire(),整个过程是同一个BulletAttack对象,改一次对 5 颗弹丸都有效。
变更历史
-
3.7.0 两个 M1 调整:迸射每段 100% → 80% 且触发系数改为 0.75;轰击 330% → 380%(系数不变)。 新增
[Primary]配置段,说明文本按配置值生成。 -
3.6.1 调整两个 M2 的技能说明文案(「造成 N%的伤害并流血。暴击则造成出血。」)。
-
3.6.0 两个 M2 保留暴击出血的同时,未暴击改为造成流血(三尖匕首那种)。 新增
[BanditSecondary]配置段。 -
3.5.0 重做熄灯:移除「击杀重置冷却」,改为命中时清除目标所有出血 / 流血并按层数结算伤害 (出血每层 2000%、流血每层 240%,无触发系数);改用 MMHOOK 挂
BulletAttack.Fire与GlobalEventManager.OnHitEnemy,不再依赖 Harmony 的PatchAll()。 -
3.4.0 修掉 3.3.0 的致命问题:
PatchAll()一个补丁都没挂上(日志里本模组的补丁记录为 0 条), 改成显式harmony.Patch()并加挂载/生效日志;顺带按用户要求把熄灯也一起改成 800%。 -
3.3.0 新增亡命徒改动:倍率 600% → 800%、叠层 10% → 5%、叠层增伤扩展到 M1;技能文本按配置动态生成。
-
3.2.0 移速降到 +150% 起每档 −15 个百分点;伤害提到每段 120%;技能文本同步更新。
-
3.1.0 移除 v3.0.0 加的「隐身期间必定暴击」效果;新增技能说明文本覆盖。
-
3.0.0 移速改为 +200% 起每档 −20 个百分点;伤害 200% → 50%;加入必暴效果(已在 3.1.0 移除)。
-
2.0.0 首版衰减移速(+300% 起,每档 −30 个百分点)。
原理
- 盗贼进入隐身走
EntityStates.Bandit2.StealthMode,OnEnter里(服务端)给角色挂上RoR2Content.Buffs.Cloak和RoR2Content.Buffs.CloakSpeed。 - 移速:实际计算在
CharacterBody.RecalculateStats()里,带CloakSpeed时固定+0.4f。 本模组通过 R2API 的RecalculateStatsAPI.GetStatCoefficients补上当前加成 - 0.4的差额。 属性默认只在数据变脏时才重算,所以插件在Update()里盯着档位,跳档就调一次body.RecalculateStats(),玩家才看得到移速一档一档往下降。 - 伤害:这个
EntityState的静态字段没有静态构造函数,值由 EntityStateConfiguration 在关卡加载后才填入,所以每帧写一次比启动时写一次稳。 - 文本:
LanguageAPI.Add(token, text, langid),中英文都塞同一句中文, 这样不管游戏选什么语言都能看到对应描述。 - 两个 R 技能:叠层 buff 是
RoR2Content.Buffs.BanditSkull,由GlobalEventManager.OnCharacterDeath授予、由FireSidearmSkullRevolver.ModifyBullet消费(原版damage *= 1 + 0.1 × 层数)。 基础倍率在BaseFireSidearmRevolverState.damageCoefficient(实例字段)里, 开火链路是OnEnter(算 damage)→ModifyBullet→Fire()。 两个 M1 都继承Bandit2FirePrimaryBase且各自调用base.ModifyBullet, 因此补丁打在基类上就能同时覆盖迸射与轰击。
配置项
首次启动生成于 BepInEx\config\com.yourname.banditsmokebombspeed.cfg:
[Primary]
ShotgunDamagePercent = 80 ; 迸射每段伤害(原版 100),5 颗共 400%
VanillaShotgunDamagePercent = 100 ; 原版每段,仅用于换算比例
ShotgunProcCoefficient = 0.75 ; 迸射触发系数
RifleDamagePercent = 380 ; 轰击伤害(原版 330)
VanillaRifleDamagePercent = 330 ; 原版值,仅用于换算比例
OverridePrimaryDescription = true
[BanditSecondary]
BleedOnNonCrit = true ; 两个 M2 未暴击时造成流血
BleedDuration = 3 ; 流血持续秒数(3 = 与原版三尖匕首一致)
BleedDamageMultiplier = 1 ; 流血伤害倍率
ScaleByProcCoefficient = true ; 持续时间是否乘以技能触发系数
RequireBanditAttacker = true ; 只处理盗贼打出的命中
OverrideSecondaryDescription = true
[LightsOut]
RemoveKillResetCooldown = true ; 移除「击败敌人重置所有冷却」
DetonateBleedStacks = true ; 开启「清除出血/流血并按层数结算伤害」
HemorrhageDamagePercent = 2000 ; 每层出血的伤害百分比
BleedDamagePercent = 240 ; 每层流血的伤害百分比
RemoveStacksAfterDetonate = true ; 结算后是否真的移除层数(false = 层数保留白嫖伤害)
StrictSourceCheck = true ; 是否额外用 damageType 标记确认命中来自熄灯
OverrideLightsOutDescription = true
[Desperado]
DesperadoDamagePercent = 800 ; 亡命徒基础倍率,800 = 800%(原版 600)
StackDamageBonus = 0.05 ; 每层叠层加成,0.05 = +5%(原版 0.1 = +10%)
ApplyStackToPrimary = true ; 叠层增伤是否也作用于 M1(迸射 / 轰击)
OverrideDesperadoDescription = true
[Smoke Bomb]
InitialBonus = 1.5 ; 起始加成,1.5 = +150%
DecayInterval = 0.3 ; 多少秒衰减一档
DecayPerTick = 0.15 ; 每档减少多少,0.15 = 减 15 个百分点
Duration = 3 ; 加成总时长(秒),到点归零
DecayMode = Flat ; Flat = 按百分点减(默认);Relative = 按比例乘
OnlyAffectBandit = true
[Damage]
SmokeBombDamageCoefficient = 1.2 ; 每段伤害系数,1.2 = 120%(原版 2.0);0 = 无伤害但保留眩晕
[Description]
OverrideSkillDescription = true ; 是否覆盖技能说明文本
DecayPerTick 的含义随 DecayMode 变化:Flat 下是"减多少加成值"(0.15 = 减 15 个百分点),
Relative 下是"降低多少比例"(0.15 = 每档 ×0.85)。
改完重启游戏即可,不用重新编译。想完全还原原版就把 InitialBonus 设成 0.4、
SmokeBombDamageCoefficient 设成 2、OverrideSkillDescription 设成 false。
⚠️ 改了数值没生效? BepInEx 的配置文件一旦生成就不会被新默认值覆盖, 一直沿用文件里写死的值。所以光改源码默认值不够,要直接改
BepInEx\config\com.yourname.banditsmokebombspeed.cfg, 或者把这个文件删掉让它重新生成。
怎么确认改动真的生效了
打开 BepInEx\LogOutput.log,搜 BanditSmokeBombSpeed,应该能看到这几类日志:
| 日志 | 含义 |
|---|---|
补丁已挂载:BaseFireSidearmRevolverState.ModifyBullet ← RevolverPostfix() |
倍率补丁挂上了(共 3 条) |
左轮倍率补丁已生效:600% → 800% |
第一次开左轮枪时触发,说明真的跑到了 |
亡命徒叠层补丁已生效:每层 +10% → +5% |
亡命徒专属那条也跑到了 |
M1 叠层补丁已生效:当前 N 层,加成 ×1.25 |
M1 那条也跑到了,并显示当前层数 |
钩子已挂载:BulletAttack.Fire / GlobalEventManager.OnHitEnemy |
熄灯改动的两条 MMHOOK 钩子挂上了 |
熄灯:damageTypeCombined 是 ulong,标记位可用 |
命中来源判定用的是 damageType 标记 + 时间窗双保险 |
熄灯:已移除「击败敌人重置冷却」 |
第一次开熄灯时触发,标记位已清掉 |
熄灯引爆已生效:出血 N 层 × 2000% + 流血 M 层 × 240% = X 伤害 |
引爆逻辑真的跑到了 |
钩子已挂载:GlobalEventManager.OnHitEnemy(M2 未暴击流血) |
M2 流血的钩子挂上了 |
M2 未暴击流血已生效:3 秒 ×1 |
第一次用 M2 打非暴击时触发 |
补丁已挂载:Bandit2FirePrimaryBase.ModifyBullet ← PrimaryPostfix() |
M1 倍率/系数补丁挂上了 |
M1 迸射补丁已生效:100% → 80%(×5 颗),触发系数 0.75 |
第一次开霰弹枪时触发 |
M1 轰击补丁已生效:330% → 380%(触发系数不变) |
第一次开步枪时触发 |
只有"已挂载"没有"已生效"说明补丁挂上了但那条代码路径没走到;
连"已挂载"都没有说明 Harmony 那步就失败了。RoR2BepInExPack 也会把每个模组的补丁
打成 Harmony ... added by XXX.dll 的 Debug 日志,可以用来交叉核对。
编译
需要 .NET SDK 6/7/8(或 Visual Studio 2022):
dotnet build -c Release
会自动把 DLL 复制到 r2modman 的 plugins 目录。不想自动复制加 -p:DeployToProfile=false。
游戏或 r2modman 装在别处就改 BanditSmokeBombSpeed.csproj 里的
<RoR2GameDir> 和 <R2ModManProfileDir>。
发布成 Thunderstore 模组包
dist\BanditSmokeBombSpeed.zip 已是标准结构(manifest.json + plugins\*.dll),
可直接用 r2modman 的「Import local mod」导入。
已知限制
- 依赖 R2API(本机 R2API 5.3.0,兼容),用到了 RecalculateStats 与 Language 两个子模块。
- 联机时所有玩家都要装,否则各自看到的移速不一致。
- 隐身计时用
Time.time,游戏暂停时不会继续衰减。 - 不要用
Harmony().PatchAll()的特性自动发现:本机实测它一个补丁都没挂上 (日志里本模组的补丁记录为 0 条,而其他模组都有),必须显式harmony.Patch(target, postfix)。 - 亡命徒的技能文本是按配置值动态生成的,改配置重启后文本自动同步。
但烟雾弹的文本是源码里写死的字符串 —— 调了
InitialBonus的话要同步改SmokeBombSpeedPlugin.cs里的SkillDescription再重新编译。 - 依赖 Harmony(BepInEx 自带
0Harmony),亡命徒的两处改动都是 Postfix 补丁。 - 熄灯改动依赖 MMHOOK(
RiskofThunder-HookGenPatcher生成的MMHOOK_RoR2.dll), 编译时需要能引用到它;运行时它由 HookGenPatcher 自动加载,不用手动加依赖。 - 熄灯的"命中来源判定"是「开火后 0.25 秒内 + 同一个攻击者」(可选再加 damageType 标记)。
如果游戏里引爆没触发,先把
StrictSourceCheck设成false再看日志。