EasyWeapon
[AI-generated] Client-only weapon tweaks: faster reload (crossbows/grappling hook), reloads that survive run/jump/dodge, and a tuned chain lightning (weapon proc chance + ChainLightningRed effect para
模組介紹 作者原文
EasyWeapon
AI 生成聲明:本模組由 AI 智能體(WorkBuddy)在用戶的明確需求與逐項驗收下編寫;
功能設計、真機測試與發佈決定均由用戶主導。
武器手感。 純客戶端模組。
功能(3 項)
| # | 功能 | 默認 | 配置節 |
| --- | --- | --- | --- |
| 1 | 裝填時間倍率 —— 弩 / 鉤索 | 0.5(= 裝填時間減半) | 1 - Reload Speed |
| 2 | 裝填不被打斷 —— 奔跑 / 跳躍 / 閃避翻滾時不清掉裝填 | 三項都開 | 2 - Uninterruptible Reload |
| 3 | 連鎖閃電強化 —— 武器觸發率統一 + ChainLightningRed 特效參數 | 見 3 - Chain Lightning 節 | 3 - Chain Lightning |
這兩個需求在遊戲裏其實是同一套機制
反彙編確認(遊戲 1.0.14,assembly_valheim.dll):
| 物品 | 本地化鍵 | m_requiresReload | m_reloadTime | 裝填動畫 | 技能 |
|---|---|---|---|---|---|
| 鉤索 | $item_graplinghook ⚠️ 遊戲裏就少一個 p | true | 2.0 s | reload_crossbow | 無(不喫技能) |
| 弩(Arbalest / Ripper×4 / Gold×3 及其變體,共 8 把) | $item_crossbow_* | true | 3.5 s | reload_crossbow | Crossbows |
| 閃電法杖(默認不動) | $item_staff_lightning | true | 1.9 s | recharge_lightningstaff | ElementalMagic |
兩者共用 ItemData.GetWeaponLoadingTime():
if (!m_requiresReload) return 1f; ← 該分支必須繞開
float skill = Player.m_localPlayer.GetSkillFactor(m_skillType);
return Mathf.Lerp(m_reloadTime, m_reloadTime * 0.5f, skill); ← 弩技能滿級本來就已減半
所以「弩減半」和「鉤索減半」是一個掛載點,不需要寫兩套。
配置
BepInEx/config/easyweapon.client.only.cfg
1 - Reload Speed
| 鍵 | 默認 | 說明 |
| --- | --- | --- |
| Enabled | true | 總開關 |
| ReloadTimeMultiplier | 0.5 | 時間倍率:0.5 = 裝填時間減半(更快)。⚠️ 填 2 是變慢 |
| Crossbows | true | 弩 |
| GrapplingHook | true | 鉤索 |
| Staves | false | 法杖(目前走裝填的是閃電法杖,充能 1.9 s) |
| OtherReloadWeapons | false | 其它「需要裝填」的武器(遊戲更新新增、本模組還不認識的)。寧可不動,也不誤傷 |
| Verbose | true | 首次遇到某件武器時記一條日誌(含前後耗時),同一件只記一次 |
2 - Uninterruptible Reload
| 鍵 | 默認 | 說明 |
| --- | --- | --- |
| Enabled | true | 總開關 |
| OnRun | true | 奔跑時不打斷裝填 |
| OnJump | true | 跳躍時不打斷裝填 |
| OnDodge | true | 閃避翻滾時不打斷裝填 |
| Verbose | true | 每次新的裝填動作被保護時記一條(同一個動作只記一次,不刷屏) |
攻擊仍然會打斷裝填 —— 那是原版設計,本模組不動。
3 - Chain Lightning
| 鍵 | 默認 | 說明 |
| --- | --- | --- |
| Enabled | true | 總開關(武器側 + 特效側一起管) |
| WeaponProcChance | 0.66 | 所有「命中時生成連鎖預製體」的攻擊槽,主/副攻擊統一用這個幾率。原版主攻擊 0.25 / 副攻擊 0.20 |
| RedStartChance | 1.0 | ChainLightningRed 的起始判定(原版 0.9)。⚠️ 判定是每幀一次(存活期間),不是"每次揮擊的觸發率" |
| RedChancePerTarget | 0.66 | 每個候選目標被鏈上的幾率(原版 0.3),各目標獨立判定 |
| RedMinTargets | 4 | 一次連鎖最少鏈幾個目標(原版 2) |
| RedMaxTargets | 6 | 一次連鎖最多鏈幾個目標(原版 4),實際個數在 Min~Max 之間隨機 |
| RedFalloff | 0.8 | 逐跳衰減(原版 0.6):下一跳幾率 = 本跳幾率 × 該值。填 1 = 不衰減 |
| RedStartDelay | 0.18 | 特效生成後多久開始判定(秒) |
| RedRadius | 12 | 連鎖判定半徑(米),原版 8 |
| RedTtl | -1(= 不改) | 特效存活時長。-1 = 保持遊戲默認(3 秒),本模組完全不碰這個字段;填正數(0.1~30)才覆蓋。⚠️ 它同時是連鎖的判定窗口,填小了會明顯削弱 |
| RedLightningDamage | 90 | 每一跳的閃電傷害,原版 75 |
| Verbose | true | 打印每條改動的前後數值(便於自證生效) |
⚠️ 本模組只改 ChainLightningRed —— 那是「雷血 / BloodLightning」那一族武器
($item_*_gold_bloodlightning)用的連鎖特效。
另一族 ChainLightning(閃電附魔 $item_*_lightning)的參數不動,
但那些武器的觸發幾率同樣受 WeaponProcChance 影響。
⚠️ 改完必須重啓遊戲(BepInEx 只在插件 Awake 讀一次配置)。
實現要點
功能 1:裝填倍率
- 掛載點:ItemDrop.ItemData.GetWeaponLoadingTime() 的 postfix,返回值 × 倍率。
- 這個方法是全程序集唯一調用點爲 Player.QueueReloadAction() 的純計算函數
(asm_member_refs.py 實測),返回值寫進 MinorActionData.m_duration
(進度條文案 $hud_reloading)。⇒ 影響面被天然圈死:
隻影響本地玩家按下的那一次裝填,不碰 NPC 的 Attack.Start 路徑,也不改任何 prefab 數據。
- ⚠️ 必須繞開!m_requiresReload 的分支:那條路徑原版返回常量 1f,
對它乘倍率會破壞不裝填武器的時長語義。代碼裏在分類之前就先判 m_requiresReload。
- 冪等:純計算、每次由原始值重算,無累計副作用 ——
所以不需要「記賬 + 原值」那套(對比:改寫 prefab 數據的模組必須記賬)。
- 分類判據用本地化鍵(SharedData.m_name),不是顯示名(會隨語言變)、也不是類名
(遊戲裏沒有 Crossbow / GrapplingHook 類型,行爲全掛在 Attack + ItemDrop 上)。
歸一化:去 $item_ 前綴 → 去 _/空格/-/. → 轉小寫。
弩與法杖用 StartsWith(變體多),鉤索用精確等值(避免誤傷名字相近的物品)。
功能 2:裝填不被打斷
原版有四個地方把整個動作隊列清空(asm_member_refs.py Humanoid::ClearActionQueue 給出):
| 來源 | 位置 | 本模組 |
| --- | --- | --- |
| 奔跑 | Player.CheckRun(每幀) | 攔 |
| 跳躍 | Player.OnJump(第一條指令就是 callvirt ClearActionQueue) | 攔 |
| 閃避翻滾 | Player.UpdateDodge(偏移 0x0074) | 攔 |
| 攻擊 | Humanoid.StartAttack | 不攔(保持原版) |
- 攔截點是 Player.ClearActionQueue(override,真正執行的那份),不是
Humanoid.ClearActionQueue(基類是空實現,只有一句 ret;四個調用點寫的都是
callvirt Humanoid::ClearActionQueue,虛擬分發到 Player 的重寫)。
- Player.ClearActionQueue 的實現只有三條指令:ldarg.0 / ldfld m_actionQueue / callvirt List::Clear / ret,
沒有任何其它副作用 —— 所以「只清空非裝填動作」與「整體清空」在其它方面完全等價。
- 隊列裏的動作類型:Playe
安裝與使用 安裝:BepInEx 外掛
- 本站下載的壓縮包就是模組本體,通常是 BepInEx 外掛(解壓後得到 .dll 或外掛資料夾)。
- 建議流程:用社群模組管理器(如 r2modman)選中本遊戲後匯入該模組,管理器會自動裝好 BepInEx 前置並處理依賴。
- 手動流程:先在遊戲目錄裝好 BepInEx 載入器,再把解壓出的 .dll 或外掛資料夾放進 BepInEx/plugins/。
- 啟動遊戲,BepInEx 控制台會列印載入日誌;確認這個模組出現在日誌裡即為安裝成功。
帶「前置依賴」的模組需要一併安裝,否則不會載入。功能開關通常在遊戲內或外掛自帶的設定檔裡調整。 多人連線時,主機與所有用戶端需要安裝一致的模組。
下面這些內容需要先安裝,否則該模組不會生效: