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);
}