diff --git a/HarmonySrc/HeldTweak.cs b/HarmonySrc/HeldTweak.cs
index ee0e7dd..11b058b 100644
--- a/HarmonySrc/HeldTweak.cs
+++ b/HarmonySrc/HeldTweak.cs
@@ -142,6 +142,10 @@ namespace NecromancerTome
case "scale" when Num(_params, 1, out float s) && s > 0f:
HeldTweak.Scale = s;
break;
+ case "tphold" when Num(_params, 1, out float th):
+ ThreadKnifeBody.TpHold = (int)th;
+ Out("хват тела для ножа-для-нитей: " + ThreadKnifeBody.TpHold + (ThreadKnifeBody.TpHold > 0 ? "" : " (выкл - как у рук)") + "; место в руке - при следующем доставании");
+ return;
case "hold" when Num(_params, 1, out float h):
Out(HeldTweak.SetHold((int)h));
return;
diff --git a/HarmonySrc/ThreadKnifeBody.cs b/HarmonySrc/ThreadKnifeBody.cs
new file mode 100644
index 0000000..4e33743
--- /dev/null
+++ b/HarmonySrc/ThreadKnifeBody.cs
@@ -0,0 +1,80 @@
+using HarmonyLib;
+using UnityEngine;
+
+namespace NecromancerTome
+{
+ ///
+ /// Тело (вид от третьего лица и для других игроков) держит нож-для-нитей обычным хватом ножа, а не луком (16.10, скрин
+ /// от третьего лица: «у персонажа запястье вывихнуто» - анимация деревянного лука тянет правую кисть с ножом). Хват
+ /// предмета один на все модели (HoldType 68 нужен рукам первого лица - основа позы HandPose.PresetThread), поэтому
+ /// подменяется только параметр аниматора WeaponHoldType/WeaponCarry у тел, кроме рук первого лица, и место ножа в
+ /// руке тела. Подбор на лету: necroheld tphold N (0 - выключить подмену).
+ ///
+ public static class ThreadKnifeBody
+ {
+ public static int TpHold = 36;
+
+ public static bool Applies(EntityAlive _e)
+ {
+ return TpHold > 0 && _e != null && _e.inventory?.holdingItem?.Name == CinerariumThreads.ThreadKnifeName;
+ }
+ }
+
+ [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController._setInt), new[] { typeof(int), typeof(int), typeof(bool) })]
+ public static class Patch_AvatarMultiBodyController_setInt_ThreadKnife
+ {
+ public static bool Prefix(AvatarMultiBodyController __instance, int _propertyHash, int _value)
+ {
+ bool hold = _propertyHash == AvatarController.weaponHoldTypeHash;
+ if (!hold && _propertyHash != AvatarController.weaponCarryHash || !ThreadKnifeBody.Applies(__instance.Entity))
+ {
+ return true;
+ }
+ BodyAnimator fp = (__instance as AvatarLocalPlayerController)?.FPSArms;
+ int tp = hold ? ThreadKnifeBody.TpHold : AnimationDelayData.AnimationDelay[ThreadKnifeBody.TpHold].Carry;
+ foreach (BodyAnimator b in __instance.BodyAnimators)
+ {
+ Animator a = b.Animator;
+ int v = b == fp ? _value : tp;
+ if (a != null && a.GetInteger(_propertyHash) != v)
+ {
+ a.SetInteger(_propertyHash, v);
+ }
+ }
+ return false; // без рассылки по сети: у других игроков мод ставит то же сам
+ }
+ }
+
+ /// Место ножа в руке тела - по хвату ножа (игра берёт смещение по HoldType предмета).
+ [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.SetInRightHand))]
+ public static class Patch_AvatarMultiBodyController_SetInRightHand_ThreadKnife
+ {
+ public static void Postfix(AvatarMultiBodyController __instance, Transform _transform)
+ {
+ EntityAlive e = __instance.Entity;
+ if (_transform == null || !ThreadKnifeBody.Applies(e) || e.emodel.IsFPV && !e.isEntityRemote)
+ {
+ return;
+ }
+ AnimationGunjointOffsetData.AnimationGunjointOffsets o = AnimationGunjointOffsetData.AnimationGunjointOffset[ThreadKnifeBody.TpHold];
+ _transform.localPosition = o.position;
+ _transform.localRotation = Quaternion.Euler(o.rotation);
+ }
+ }
+
+ [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.SwitchModelAndView))]
+ public static class Patch_AvatarMultiBodyController_SwitchModelAndView_ThreadKnife
+ {
+ public static void Postfix(AvatarMultiBodyController __instance, bool _bFPV)
+ {
+ Transform t = __instance.heldItemTransform;
+ if (t == null || _bFPV || !ThreadKnifeBody.Applies(__instance.Entity))
+ {
+ return;
+ }
+ AnimationGunjointOffsetData.AnimationGunjointOffsets o = AnimationGunjointOffsetData.AnimationGunjointOffset[ThreadKnifeBody.TpHold];
+ t.localPosition = o.position;
+ t.localEulerAngles = o.rotation;
+ }
+ }
+}