From ed4015ecee513e12b8180b85a9f28f04f6e7f5c2 Mon Sep 17 00:00:00 2001 From: AlexCube Date: Fri, 16 Oct 2026 22:58:28 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A5=D0=B2=D0=B0=D1=82=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20=D0=BD=D0=B8=D1=82=D0=B5=D0=B9:=20=D0=BE=D1=81=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=2068,=20=D0=BF=D0=BE=D0=B7=D0=B0=20=D1=80=D1=83?= =?UTF-8?q?=D0=BA=20=D0=BC=D0=BE=D0=B4=D0=B0,=20=D0=BD=D0=BE=D0=B6=20?= =?UTF-8?q?=D0=B2=20=D0=BB=D0=B5=D0=B2=D0=BE=D0=B9=20=D1=80=D1=83=D0=BA?= =?UTF-8?q?=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- Config/items.xml | 5 +- HarmonySrc/HandHolds.cs | 21 ++++++- HarmonySrc/HandPosePose.cs | 111 +++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 3 deletions(-) diff --git a/Config/items.xml b/Config/items.xml index 96727b3..ea7cf23 100644 --- a/Config/items.xml +++ b/Config/items.xml @@ -2028,8 +2028,9 @@ - + + diff --git a/HarmonySrc/HandHolds.cs b/HarmonySrc/HandHolds.cs index 9ae2222..49928f0 100644 --- a/HarmonySrc/HandHolds.cs +++ b/HarmonySrc/HandHolds.cs @@ -23,7 +23,10 @@ namespace NecromancerTome public static class HandHolds { public const string HandItem = "meleeHandPlayer"; - public const int None = 0, Deny = 1, PifPaf = 2; + public const int None = 0, Deny = 1, PifPaf = 2, Thread = 3; + /// Хват для нитей - не сразу: снимок замороженных костей должен быть в покое хвата 68, после доставания. + const float ThreadDelay = 0.6f; + static float _threadSince = -1f; /// Дальность и конус выбора зомби для «отрицания». public const float DenyRange = 25f; @@ -59,6 +62,17 @@ namespace NecromancerTome public static int Current(EntityPlayerLocal _player) { + if (_player != null && _player.inventory?.holdingItem?.Name == CinerariumThreads.ThreadKnifeName && + !SnakeMode.Active && !MindPalace.Active && !Possession.Active && !_player.IsDead()) + { + if (_threadSince < 0f) + { + _threadSince = Time.time; + } + bool ready = Time.time - _threadSince >= ThreadDelay && !(_player.Hand != null && _player.Hand.isSwitching); + return ready ? Thread : None; + } + _threadSince = -1f; if (_player == null || _player.Buffs == null || !IsHand(_player.inventory?.holdingItem) || SnakeMode.Active || MindPalace.Active || Possession.Active || _player.IsDead()) { @@ -104,9 +118,14 @@ namespace NecromancerTome { HandPose.PresetPifPaf(); } + else if (want == Thread) + { + HandPose.PresetThread(); + } else { HandPose.Enabled = false; + HandPose.KnifeToLeft = false; } } diff --git a/HarmonySrc/HandPosePose.cs b/HarmonySrc/HandPosePose.cs index da3825d..38e8d88 100644 --- a/HarmonySrc/HandPosePose.cs +++ b/HarmonySrc/HandPosePose.cs @@ -86,6 +86,7 @@ namespace NecromancerTome public static void ResetAll() { Enabled = false; + KnifeToLeft = false; Overrides.Clear(); CamOverrides.Clear(); _jabStart = -1f; @@ -160,6 +161,10 @@ namespace NecromancerTome b.localRotation = Quaternion.Euler(kv.Value); } } + if (KnifeToLeft) + { + ApplyKnifeToLeft(); + } Transform cam = CamOverrides.Count > 0 || _jabStart >= 0f ? Camera() : null; ApplyJab(cam); if (cam != null) @@ -265,6 +270,7 @@ namespace NecromancerTome /// (сгиб - как у поджатых пальцев «пиф-пафа»), указательный и мизинец прямые. public static void PresetDeny() { + KnifeToLeft = false; Overrides.Clear(); CamOverrides.Clear(); Overrides["RightArm"] = new Vector3(345.8f, 34.9f, 24.3f); @@ -291,6 +297,7 @@ namespace NecromancerTome /// сомкнуты и смотрят к прицелу, безымянный и мизинец поджаты, большой вверх. Кисть - от камеры. public static void PresetPifPaf() { + KnifeToLeft = false; Overrides.Clear(); CamOverrides.Clear(); Overrides["RightArm"] = new Vector3(330.8f, 34.9f, 24.3f); @@ -313,6 +320,110 @@ namespace NecromancerTome Enabled = true; } + /// Нож в левой кисти (хват для нитей): корень модели в руке ставится каждый кадр от LeftHand. Смещение - + /// снимок хвата 68 (деревянный лук) 16.10, где нож лежал в левой руке («Нож в левой руке»). + public static bool KnifeToLeft; + static readonly Vector3 KnifeLeftPos = new Vector3(-0.0832f, -0.0354f, 0.0186f); + static readonly Quaternion KnifeLeftRot = new Quaternion(0.56471f, -0.62192f, -0.41297f, 0.35182f); + + static void ApplyKnifeToLeft() + { + Transform lh = Bone("LeftHand"); + Transform m = HeldTweak.Model(); + if (lh != null && m != null) + { + m.SetPositionAndRotation(lh.TransformPoint(KnifeLeftPos), lh.rotation * KnifeLeftRot); + } + } + + /// Хват для нитей (16.10, подбор с пользователем: «Нож в левую руку, а правую сделай как в том хвате, где + /// ты говорил что она перебирает нити»): основа - HoldType 68 (деревянный лук, items.xml); левая рука поднята и + /// отведена влево, нож в ней; правая - раскрытая ладонь хвата 64 (бинт), пересчитанная под плечо хвата 68 так, + /// чтобы кисть стояла там же относительно камеры (scratchpad ik.py). + public static void PresetThread() + { + Overrides.Clear(); + CamOverrides.Clear(); + Overrides["RightShoulder"] = new Vector3(0.0f, 180.0f, 180.0f); + Overrides["Right_sup_shoulder_01"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["Right_sup_shoulder_02"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["Right_sup_trap_01"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["RightArm"] = new Vector3(311.4f, 24.9f, 39.2f); + Overrides["Right_sup_arm_01"] = new Vector3(0.0f, 0.0f, 358.2f); + Overrides["RightArmRoll"] = new Vector3(357.9f, 0.0f, 0.0f); + Overrides["RightForeArm"] = new Vector3(0.0f, 79.9f, 0.0f); + Overrides["Right_sup_elbow_00"] = new Vector3(0.0f, 332.8f, 0.0f); + Overrides["RightForeArmRoll"] = new Vector3(8.7f, 0.0f, 0.0f); + Overrides["RightHand"] = new Vector3(7.2f, 346.5f, 5.4f); + Overrides["RightHandIndex0"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["Right_sup_index_00"] = new Vector3(0.0f, 0.0f, 17.3f); + Overrides["Right_sup_index_00_palm"] = new Vector3(0.0f, 0.0f, 15.6f); + Overrides["RightHandIndex1"] = new Vector3(2.6f, 2.9f, 31.3f); + Overrides["Right_sup_index_01_under"] = new Vector3(0.0f, 0.0f, 3.5f); + Overrides["RightHandIndex2"] = new Vector3(0.0f, 0.0f, 52.8f); + Overrides["Right_sup_index_02"] = new Vector3(0.0f, 0.0f, 333.6f); + Overrides["Right_sup_index_02_under"] = new Vector3(0.0f, 0.0f, 5.1f); + Overrides["RightHandIndex3"] = new Vector3(0.0f, 0.0f, 77.0f); + Overrides["Right_sup_index_03"] = new Vector3(0.0f, 0.0f, 321.5f); + Overrides["RightHandIndex4"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["RightHandMiddle0"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["Right_sup_middle_00"] = new Vector3(0.0f, 0.0f, 32.1f); + Overrides["Right_sup_middle_00_palm"] = new Vector3(0.0f, 0.0f, 28.8f); + Overrides["RightHandMiddle1"] = new Vector3(0.0f, 0.0f, 57.7f); + Overrides["Right_sup_middle_01_under"] = new Vector3(0.0f, 0.0f, 5.7f); + Overrides["RightHandMiddle2"] = new Vector3(0.0f, 0.0f, 85.0f); + Overrides["Right_sup_middle_02"] = new Vector3(0.0f, 0.0f, 317.5f); + Overrides["Right_sup_middle_02_under"] = new Vector3(0.0f, 0.0f, 5.1f); + Overrides["RightHandMiddle3"] = new Vector3(0.0f, 0.0f, 77.0f); + Overrides["Right_sup_middle_03"] = new Vector3(0.0f, 0.0f, 321.5f); + Overrides["RightHandMiddle4"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["RightHandPinky0"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["Right_sup_pinky_00"] = new Vector3(0.0f, 0.0f, 45.0f); + Overrides["Right_sup_pinky_00_palm"] = new Vector3(0.0f, 0.0f, 45.0f); + Overrides["RightHandPinky1"] = new Vector3(0.2f, 353.1f, 92.0f); + Overrides["Right_sup_pinky_01_under"] = new Vector3(0.0f, 0.0f, 5.6f); + Overrides["RightHandPinky2"] = new Vector3(0.0f, 0.0f, 84.0f); + Overrides["Right_sup_pinky_02"] = new Vector3(0.0f, 0.0f, 318.0f); + Overrides["Right_sup_pinky_02_under"] = new Vector3(0.0f, 0.0f, 5.2f); + Overrides["RightHandPinky3"] = new Vector3(0.0f, 0.0f, 78.0f); + Overrides["Right_sup_pinky_03"] = new Vector3(0.0f, 0.0f, 321.0f); + Overrides["RightHandPinky4"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["RightHandRing0"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["Right_sup_ring_00"] = new Vector3(0.0f, 0.0f, 33.0f); + Overrides["Right_sup_ring_00_palm"] = new Vector3(0.0f, 0.0f, 33.0f); + Overrides["RightHandRing1"] = new Vector3(358.6f, 355.2f, 66.1f); + Overrides["Right_sup_ring_01_under"] = new Vector3(0.0f, 0.0f, 5.5f); + Overrides["RightHandRing2"] = new Vector3(0.0f, 0.0f, 83.0f); + Overrides["Right_sup_ring_02"] = new Vector3(0.0f, 0.0f, 318.5f); + Overrides["Right_sup_ring_02_under"] = new Vector3(0.0f, 0.0f, 5.1f); + Overrides["RightHandRing3"] = new Vector3(0.0f, 0.0f, 77.0f); + Overrides["Right_sup_ring_03"] = new Vector3(0.0f, 0.0f, 321.5f); + Overrides["RightHandRing4"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["RightHandThumb1"] = new Vector3(27.9f, 75.4f, 33.2f); + Overrides["RightHandThumb2"] = new Vector3(0.0f, 0.0f, 15.8f); + Overrides["Right_sup_thumb_01"] = new Vector3(0.0f, 0.0f, 352.1f); + Overrides["Right_sup_thumb_01_under"] = new Vector3(0.0f, 0.0f, 1.2f); + Overrides["RightHandThumb3"] = new Vector3(0.0f, 0.0f, 17.9f); + Overrides["Right_sup_thumb_02"] = new Vector3(0.0f, 0.0f, 351.0f); + Overrides["RightHandThumb4"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["necroKnifePrefab(Clone)"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["boneShiv_LOD0"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["boneShiv_LOD1"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["boneShiv_LOD2"] = new Vector3(0.0f, 0.0f, 0.0f); + Overrides["RightForeArmRoll1"] = new Vector3(3.5f, 0.0f, 0.0f); + Overrides["RightForeArmRoll2"] = new Vector3(7.0f, 0.0f, 0.0f); + Overrides["RightForeArmRoll3"] = new Vector3(10.5f, 0.0f, 0.0f); + Overrides["RightForeArmRoll4"] = new Vector3(14.0f, 0.0f, 0.0f); + Overrides["Right_sup_wrist_00"] = new Vector3(0.0f, 0.0f, 357.5f); + Overrides["Right_sup_wrist_01"] = new Vector3(0.0f, 347.6f, 0.0f); + Overrides["Right_sup_wrist_02"] = new Vector3(0.0f, 0.0f, 356.8f); + Overrides["Right_sup_wrist_03"] = new Vector3(0.0f, 347.6f, 0.0f); + Overrides["LeftArm"] = new Vector3(329.6f, 42.5f, 8.5f); + KnifeToLeft = true; + Unfreeze(); + Enabled = true; + } + public static string F(float _v) => _v.ToString("0.#", CultureInfo.InvariantCulture); public static string F(Vector3 _v) => F(_v.x) + " " + F(_v.y) + " " + F(_v.z); }