简易武器

创作者: s6652289
已更新:2026-09-26 23:26:39
40KB

关于此 MOD

[AI生成] 仅客户端武器调整:更快的装填(弩/抓钩),奔跑/跳跃/闪避时仍能保持装填,以及调整后的连锁闪电(武器触发几率 + ChainLightningRed 效果参数)。

简易武器

AI 生成声明:本模组由 AI 智能体(WorkBuddy)在用户的明确需求与逐项验收下编写; 功能设计、真机测试与发布决定均由用户主导。

武器手感。 纯客户端模组。

功能(3 项)

# 功能 默认 配置节
1 装填时间倍率 —— 弩 / 钩索 0.5(= 装填时间减半) 1 - 装填速度
2 装填不被打断 —— 奔跑 / 跳跃 / 闪避翻滚时不清掉装填 三项都开 2 - 不可中断装弹
3 连锁闪电强化 —— 武器触发率统一 + 连锁闪电红 特效参数 见 3 - 连锁闪电 节 3 - 闪电链

这两个需求在游戏里其实是同一套机制

反汇编确认(游戏 1.0.14,assembly_valheim.dll):

物品 本地化键 需要换弹 装填时间 装填动画 技能
钩索 抓钩 ⚠️ 游戏里就少一个 p 真 2.0 秒 装填弩箭 无(不吃技能)
弩(强弩 / 撕裂者×4 / 黄金×3 及其变体,共 8 把) $item_crossbow_* 真 3.5秒 重新装填弩箭 弩
闪电法杖(默认不动) 闪电法杖 真 1.9 秒 充能闪电法杖 元素魔法

两者共用 获取武器加载时间():

如果 (!m_requiresReload) 返回 1f; ← 该分支必须绕开 float skill = Player.m_localPlayer.GetSkillFactor(m_skillType); 返回 Mathf.Lerp(m_reloadTime, m_reloadTime * 0.5f, skill); ← 弩技能满级本来就已减半

所以「弩减半」和「钩索减半」是一个挂载点,不需要写两套。

配置

BepInEx/配置/简易武器.客户端.仅限.cfg

1 - 装填速度

键 默认 说明
已启用 真实 总开关
装填时间倍率 0.5 时间倍率:0.5 = 装填时间减半(更快)。⚠️ 填 2 是变慢
弩 真实 弩
抓钩 真 钩索
法杖 假 法杖(目前走装填的是闪电法杖,充能 1.9 s)
其他武器装填 假 其他“需要装填”的武器(游戏更新新增、本模组尚未识别的)。宁可不动,也不误伤
详细 真 首次遇到某件武器时记一条日志(含前后耗时),同一件只记一次

2 - 不可中断装填

键 默认 说明
已启用 真 总开关
奔跑 真 奔跑时不打断装填
跳跃 真 跳跃时不打断装填
闪避时 真 闪避翻滚时不打断装填
详细 真 每次新的装填动作被保护时记一条(同一个动作只记一次,不刷屏)

攻击仍然会打断装填 —— 那是原版设计,本模组不动。

3 - 连锁闪电

键 默认 说明
已启用 真 总开关(武器侧 + 特效侧一起管)
武器触发几率 0.66 所有「命中时生成连锁预制体」的攻击槽,主/副攻击统一用这个几率。原版主攻击 0.25 / 副攻击 0.20
红起手概率 1.0 闪电链红 的起始判定(原版 0.9)。⚠️ 判定是每帧一次(存活期间),不是“每次挥击的触发率”
每目标红色概率 0.66 每个候选目标被链上的几率(原版 0.3),各目标独立判定
红最小目标 4 一次连锁最少连锁几个目标(原版 2)
红色最大目标 6 一次连锁最多链接几个目标(原版4),实际个数在Min~Max之间随机
红色衰减 0.8 逐跳衰减(原版 0.6):下一跳几率 = 本跳几率 × 该值。填 1 = 不衰减
红延迟启动 0.18 特效生成后多久开始判定(秒)
红色半径 12 连锁判定半径(米),原版 8
红标题 -1(= 不改) 特效存活时长。-1 = 保持游戏默认(3 秒),本模组完全不碰这个字段;填正数(0.1~30)才覆盖。⚠️ 它同时是连锁的判定窗口,填小了会明显削弱
红色闪电伤害 90 每一跳的闪电伤害,原版 75
详细 真 打印每条改动的前后数值(便于自证生效)

⚠️ 本模组只改 闪电链红 —— 那是「雷血 / BloodLightning」那一族武器 ($item_*_gold_bloodlightning)用的连锁特效。 另一族 连锁闪电(闪电附魔 $item_*_lightning的参数不动,但那些武器的触发几率同样受 武器触发几率 影响。

⚠️ 改完必须重启游戏(BepInEx 只在插件 醒来 读一次配置)。

实现要点

功能 1:装填倍率

  • 挂载点:物品掉落.物品数据.获取武器装填时间() 的 后缀,返回值 × 倍率。
  • 这个方法是全程序集唯一调用点为 玩家.队列装弹动作() 的纯计算函数(asm_member_refs.py 实测),将返回值写入 时长 加载中 正在重新装填)。⇒ 影响范围被天然限定: 只影响本地玩家按下的那一次装填,不碰 NPC 的 攻击.开始 路径,也不改任何 prefab 数据。
  • ⚠️ 必须绕开 需要重新装填 的分支:那条路径原版返回常量 1f,对它乘倍率会破坏不装填武器的时长语义。代码里在分类之前就先判 需要装填。
  • 幂等纯计算、每次由原始值重算,无累计副作用 —— 所以不需要「记账 + 原值」那套(对比:改写 prefab 数据的模组必须记账)。
  • 分类标准用本地化键(共享数据.名称),不是显示名(会随语言变)、也不是类名 (游戏里没有 弩 / 抓钩类型,行为全挂在 攻击 + 掉落物品 顶部)。归一化:移除 $item_ 去 _/空格/-/. → 转小写。 弩与法杖用 开头是(变体多),钩索用精确等值(避免误伤名字相近的物品)。

功能 2:装填不被打断

原版有四个地方把整个动作队列清空(人形::ClearActionQueue 给出):

来源 位置 本模组
奔跑 玩家.检查奔跑(每帧) 拦
跳跃 玩家.跳跃时(第一条指令就是 调用虚方法 ClearActionQueue) 拦
闪避翻滚 玩家.更新闪避(偏移 0x0074) 拦
攻击 人形单位.开始攻击 不拦(保持原版)
  • 拦截点是 玩家.清空行动队列(覆盖,真正执行的那份),不是 人形单位.清空行动队列(基类是空实现,只有一句 返回;四个调用点写的都是 调用虚方法 Humanoid::ClearActionQueue,虚拟分发到 Player 的重写)。
  • 玩家.清空行动队列 的实现只有三条指令:加载参数0 / 加载字段m_actionQueue / 调用虚方法List::Clear / 返回, 没有任何其它副作用 ——所以「只清空非装填动作」与「整体清空」在其它方面完全等价。
  • 队列中的动作类型:玩家.次要动作数据.动作类型 = 装备(0) / 卸下装备(1) / 装填(2)。 本模组遍历 动作队列,移除除 装填 除外的所有条目,装填那条原地保留 ⇒ 装填进度(时间)不掉线、进度条不归零。
  • 动作队列 是私有字段,用 字段引用访问 反射取(解析失败会在启动自检里打 记录错误,不会静默失效)。
  • 来源判定用深度计数而非布尔值:布尔值一旦因异常卡住(前缀跑了、后缀没跑)就会永久误保护;计数配合 > 0 夹紧可以自愈。
  • 标记了 [和谐优先级(优先级.低)](数值越小越后执行)——让其他模组的判定优先执行。

功能3:连锁闪电强化

游戏里「闪电伤害」和「连锁闪电」是两件事 —— 不是所有带闪电伤害的武器都会连锁。反汇编 + prefab 数据核对(游戏 1.0.14)得到的完整链路:

武器命中 └─ Attack.SpawnOnHit(): if (m_spawnOnHitChance > 0 && m_spawnOnHit != null) if (Random.Range(0f,1f) < m_spawnOnHitChance) ← 功能 3 改这里 在命中点实例化 m_spawnOnHit(连锁特效预制体) └─ 特效上的 Aoe.CustomFixedUpdate(): ← 功能 3 也改这里 延迟 m_chainStartDelay 后,每帧判一次:Random.value < m_chainStartChance → 找目标,个数 = Random.Range(m_chainMinTargets, m_chainMaxTargets + 1) → 每个目标:Random.value < m_chainChancePerTarget → 生成下一个连锁对象,并把 m_chainChance × m_chainStartChanceFalloff 传下去
  • 武器侧挂载点:对象数据库.唤醒 的 后缀。遍历 物品数据库 → 物品掉落.物品数据.共享数据 的 攻击 / 副攻击。 ⚠️ 判定标准用与游戏完全相同的两个条件(命中时生成几率 > 0 且 m_spawnOnHit != null) 再加一道「目标预制体名以 连锁闪电 开头的过滤:前者保证只改“原版真的会触发”的槽(否则会把“不触发”改成“触发”),后者保证不误伤将来别的 hit-spawn 特效。不写死武器名单,游戏新增武器自动跟上。 当前版本命中 19 件武器(7 件闪电附魔 + 12 件雷血附魔)× 主/副槽。
  • 特效侧挂载点:ZNetScene.Awake 的 后缀。ZNetScene.Awake 开头就填 命名预制体(获取稳定哈希码 做键),所以在后缀时 获取预制体("ChainLightningRed") 可用; 而 ZNetScene 没有“运行时注册预制体”的方法 ⇒ 名字表在 Awake 之后固定不变,要改就得赶在实例化之前 —— 这个时机是唯一正确的窗口。取不到时再遍历 预制体 兜底(防止注册名与 GameObject 名不一致)。
  • 幂等全部是绝对值赋值(不是“原值 × 倍率”)⇒ 重复执行结果不变。对比功能 1 的纯计算写法,这里额外加了“已应用”标记,只为避免场景重建时重复刷日志。
  • 影响范围只改预制体静态数据,不碰任何运行时逻辑、不碰存档、不加网络同步。连锁的每一跳都是同一个预制体实例化出来的,所以自然继承以上全部参数。
  • ⚠️ 主机端权威性:伤害由攻击者本地计算后同步,所以装了本模组的一方打出的连锁伤害确实变高; 但别人屏幕上看到的连锁范围/存活时长仍按他们自己的 预制数据。

与其它模组的关系

本模组不依赖任何其它模组 —— 拦截点直接落在 玩家.清空动作队列,不借他人之手。

历史上 简易装备 曾有一项「跑步时也能切换武器 / 工具」会拦同一个清空,两者当时可共存(谁先返回 否 都能保住队列); 该功能已在 EasyGear 1.0.5 整体剔除,所以这段共存逻辑现在只在将来出现同类模组时才有意义 —— [和谐优先级(优先级.低)] 就是为此保留的(数值越小越后执行,让别人的判定先做)。

启动自检里同时打印 人形单位.清空行动队列(空实现)与 清除玩家行动队列 (实际执行的重写)的补丁数,两者一对比就能看出补丁是否打在真正会被执行的方法上(仅用于诊断,并非判定依据——EasyGear 1.0.2/1.0.3 正是栽在这一点上,详见其更新日志)。

联机

纯客户端。 主机、其他玩家都不需要装。

不声明 网络兼容性特性(= 未执行,不参与连接校验),不引用 Jotunn,不内嵌 ServerSync / CCS。

⚠️ 功能 3 改的是 预制静态数据 ⇒ 效果只体现在装了本模组的那一端: 连锁伤害由攻击者本地计算后同步(你打出的伤害确实更高), 但别人屏幕上看到的连锁范围 / 存活时长仍按他们自己的 预制数据。三项功能都互不依赖,也可以只开启其中一项。

真机验证怎么看日志

启动后 BepInEx/LogOutput.log 里面应该有:

[信息 : EasyWeapon] ---- 补丁挂载自检 ---- [信息 : EasyWeapon] ItemData.GetWeaponLoadingTime() 前缀=0 后缀=1 正常 [信息 : EasyWeapon] Player.CheckRun() 前缀=1 后缀=1 正常 [信息 : EasyWeapon] Player.OnJump() 前缀=1 后缀=1 正常 [信息 : EasyWeapon] Player.UpdateDodge() 前缀=1 后缀=1 正常 [信息 : EasyWeapon] Player.ClearActionQueue() 前缀=1 后缀=0 正常 [信息 : EasyWeapon] (若这一行下面还有「来自其它模组的 前缀:xxx」,说明那个模组的补丁 也挂在了**实际执行的重写**上;一条都没有则表示它的补丁挂在 Humanoid 的空实现上、运行时不会被执行 —— Harmony 不会把 「对虚方法的 patch」自动展开到派生重写。) [信息 : EasyWeapon] ObjectDB.Awake() 前缀=0 后缀=1 正常 [信息 : EasyWeapon] ZNetScene.Awake() 前缀=0 后缀=1 正常 [信息 : EasyWeapon] [诊断] Humanoid.ClearActionQueue()(空实现)前缀=?

游戏内装填一次后应出现(同一件武器只记一次):

[信息 : EasyWeapon] [装填] $item_crossbow_arbalest(弩):3.50秒 → 1.75秒(倍率 0.5) [信息 : EasyWeapon] [装填] $item_graplinghook(钩索):2.00秒 → 1.00秒(倍率 0.5)

装填途中奔跑 / 跳跃 / 翻滚时应有:

[信息 : EasyWeapon] [装填保护] 奔跑触发的清空:保留装填动作「$item_crossbow_arbalest」(进度 0.83秒 / 1.75秒),移除其它动作 0 个,队列现有 1 条。

若自检里出现 !!未挂上!! 或 反射不到 Player.m_actionQueue,说明游戏更新改了结构 —— 对应功能不会生效,需要重新核对。

功能 3 的启动日志(进世界时 对象数据库 / 网络场景 各唤醒一次):

[信息 : EasyWeapon] [ObjectDB.Awake] 武器连锁触发率 → 0.66(主/副攻击统一):命中 38 个攻击槽 / 19 件武器(共扫 N 件物品)。 [信息 : EasyWeapon] [ZNetScene.Awake] 连锁特效 ChainLightningRed 已改写: 起始判定 0.9 → 1 每目标几率 0.3 → 0.66 目标数 2~4 → 4~6 逐跳衰减 0.6 → 0.8 [信息 : EasyWeapon] 起始延迟 0.18 → 0.18 s|半径 8 → 12 m|每跳闪电伤害 75 → 90|存活 3 s(保持游戏默认,未改动)

若出现 找不到预制体 ChainLightningRed 或 没有 Aoe 组件,说明游戏更新改了名字/结构 —— 特效侧参数不会生效(武器侧仍正常),需要重新核对。

Valheim: 英灵神殿 的热门 MOD

探索适用于 Valheim: 英灵神殿 的最佳MOD,带来新功能、升级画面,以及令人兴奋的方式来改变您的游戏体验。

使用 Xmod 解锁 Valheim: 英灵神殿 的全部潜力 — 今天就探索这些顶级 MOD!