diff --git a/HarmonySrc/CinerariumGenie.cs b/HarmonySrc/CinerariumGenie.cs index c980cc1..c6ce7ff 100644 --- a/HarmonySrc/CinerariumGenie.cs +++ b/HarmonySrc/CinerariumGenie.cs @@ -51,18 +51,11 @@ namespace NecromancerTome } return (pl.GetPosition() - Origin.position - _scenePos).sqrMagnitude > SleepDistance * SleepDistance; } - /// Руки (16.10: «Т-поза бесит»): плечо от вертикали вбок и вперёд, локоть согнут вперёд, градусы. - /// Модель в позе покоя, аниматора нет - кости ставятся один раз при появлении. - public static float ArmOut = 3f; // 17.10 в игре: «По стойке смирно» - руки прямо вдоль тела (necrogenie arms 3 0 0) - public static float ArmFwd = 0f; + /// Руки в жесте: плечо от вертикали вбок, локоть согнут вперёд, градусы. Покой - «смирно» (18.10: «Всё Смирно и + /// будет позой для бездельничающих некротехов») запечён в позу покоя модели (pose_attention.json при выгрузке FBX), + /// аниматора нет - без жеста кости не трогаются. + public static float ArmOut = 3f; public static float Elbow = 0f; - /// Покой - поза покойника (17.10): плечо вниз-вперёд на CrossFwd, предплечье вверх наискось, кисть к плечу другой - /// стороны, вынесенному вперёд на CrossDepth ширины плеч; левая рука поверх правой - ещё на CrossLift. Жест - из этой позы - /// и назад. - public static bool Cross = false; // 17.10: пока поза покойника подбирается в Blender - резервная «смирно» (Arm*) - public static float CrossFwd = 25f; - public static float CrossLift = 0.15f; - public static float CrossDepth = 0.3f; static GameObject _prefab; static bool _tried; @@ -301,15 +294,15 @@ namespace NecromancerTome Quaternion[] _armRest; static bool _armLogged; - /// Опустить руки из позы покоя: направление плеча и предплечья задаётся в осях модели (вперёд - +Z), - /// поворот - от текущего направления кости к нужному, так что оси самих костей значения не имеют. + /// Покой - руки в позе модели («смирно»). public void Pose() { - Pose(CinerariumGenie.ArmFwd, CinerariumGenie.Elbow, CinerariumGenie.Elbow, CinerariumGenie.Cross ? 1f : 0f); + Pose(0f, CinerariumGenie.Elbow, CinerariumGenie.Elbow); } - /// _cross - доля скрещённой позы (1 - руки на груди, 0 - опущены/жест), направления смешиваются. - void Pose(float _fwd, float _elbowL, float _elbowR, float _cross) + /// Жест долей _w от покоя: плечо вперёд на GestureFwd, направление плеча и предплечья задаётся в осях модели + /// (вперёд - +Z), поворот - от текущего направления кости к нужному, так что оси самих костей значения не имеют. + void Pose(float _w, float _elbowL, float _elbowR) { if (_arm == null) { @@ -337,7 +330,6 @@ namespace NecromancerTome } Debug.Log("[NecromancerTome] CinerariumGenie: кости рук " + sb); } - CloseFingers(); } for (int i = 0; i < _arm.Length; i++) { @@ -346,6 +338,10 @@ namespace NecromancerTome _arm[i].localRotation = _armRest[i]; } } + if (_w <= 0f) + { + return; + } for (int side = 0; side < 2; side++) { Transform up = _arm[side * 3], fore = _arm[side * 3 + 1], hand = _arm[side * 3 + 2]; @@ -354,74 +350,11 @@ namespace NecromancerTome continue; } float sign = Mathf.Sign(transform.InverseTransformPoint(up.position).x); - float o = CinerariumGenie.ArmOut * Mathf.Deg2Rad, f = _fwd * Mathf.Deg2Rad; + float o = CinerariumGenie.ArmOut * Mathf.Deg2Rad, f = GestureFwd * Mathf.Deg2Rad; Vector3 upDir = new Vector3(sign * Mathf.Sin(o), -Mathf.Cos(o) * Mathf.Cos(f), Mathf.Sin(f)).normalized; Vector3 foreDir = Vector3.RotateTowards(upDir, Vector3.forward, (side == 0 ? _elbowL : _elbowR) * Mathf.Deg2Rad, 0f); - if (_cross > 0f) - { - float cf = CinerariumGenie.CrossFwd * Mathf.Deg2Rad; - upDir = Vector3.Slerp(upDir, new Vector3(0f, -Mathf.Cos(cf), Mathf.Sin(cf)), _cross).normalized; - } - up.rotation = Quaternion.FromToRotation(fore.position - up.position, transform.TransformDirection(upDir)) * up.rotation; - Transform otherUp = _arm[(1 - side) * 3]; - if (_cross > 0f && otherUp != null) - { - // Кисть - к плечу другой стороны (17.10: «Ладонь правой руки прижимается к левому плечу. Левая рука идёт - // поверх правой и прижимает ладонь к правому плечу»): цель - сустав другого плеча, вынесенный вперёд на - // толщину груди; левая (side 0) - ещё на CrossLift вперёд, поверх правой. Доли - от ширины плеч. - float width = Vector3.Distance(up.position, otherUp.position); - Vector3 target = otherUp.position + transform.forward * width * (CinerariumGenie.CrossDepth + (side == 0 ? CinerariumGenie.CrossLift : 0f)); - Vector3 want = transform.InverseTransformDirection(target - fore.position).normalized; - foreDir = Vector3.Slerp(foreDir, want, _cross).normalized; - } - fore.rotation = Quaternion.FromToRotation(hand.position - fore.position, transform.TransformDirection(foreDir)) * fore.rotation; - } - } - - /// Пальцы (17.10: «Пальцы можешь не растопыривать?»): в модели они веером. Указательный, безымянный и мизинец - /// поворачиваются к направлению среднего на долю FingersTogether, большой - на треть её. Пальцы - дети кисти, позы рук их - /// не трогают, поэтому ставятся один раз. - public static float FingersTogether = 0.85f; - - void CloseFingers() - { - Transform[] all = GetComponentsInChildren(true); - Dictionary bones = new Dictionary(); - foreach (string side in new[] { "Left", "Right" }) - { - foreach (string finger in new[] { "Index", "Middle", "Ring", "Pinky", "Thumb" }) - { - for (int j = 1; j <= 2; j++) - { - string key = side + "Hand" + finger + j; - foreach (Transform t in all) - { - if (t.name.EndsWith(key)) - { - bones[key] = t; - break; - } - } - } - } - } - foreach (string side in new[] { "Left", "Right" }) - { - if (!bones.TryGetValue(side + "HandMiddle1", out Transform m1) || !bones.TryGetValue(side + "HandMiddle2", out Transform m2)) - { - continue; - } - Vector3 mid = m2.position - m1.position; - foreach (string finger in new[] { "Index", "Ring", "Pinky", "Thumb" }) - { - if (!bones.TryGetValue(side + "Hand" + finger + "1", out Transform f1) || !bones.TryGetValue(side + "Hand" + finger + "2", out Transform f2)) - { - continue; - } - Vector3 cur = f2.position - f1.position; - float k = finger == "Thumb" ? FingersTogether / 3f : FingersTogether; - f1.rotation = Quaternion.FromToRotation(cur, Vector3.Slerp(cur, mid, k)) * f1.rotation; - } + up.rotation = Quaternion.Slerp(Quaternion.identity, Quaternion.FromToRotation(fore.position - up.position, transform.TransformDirection(upDir)), _w) * up.rotation; + fore.rotation = Quaternion.Slerp(Quaternion.identity, Quaternion.FromToRotation(hand.position - fore.position, transform.TransformDirection(foreDir)), _w) * fore.rotation; } } @@ -476,9 +409,8 @@ namespace NecromancerTome { if (_w > 0f) { - float wave = Mathf.Sin(_t * Mathf.PI * 2f * 1.5f) * GestureWave * _w; - Pose(Mathf.Lerp(CinerariumGenie.ArmFwd, GestureFwd, _w), CinerariumGenie.Elbow + 15f * _w + wave, CinerariumGenie.Elbow + 15f * _w - wave, - CinerariumGenie.Cross ? 1f - _w : 0f); + float wave = Mathf.Sin(_t * Mathf.PI * 2f * 1.5f) * GestureWave; + Pose(_w, CinerariumGenie.Elbow + 15f + wave, CinerariumGenie.Elbow + 15f - wave); _gesturing = true; } else if (_gesturing) @@ -643,8 +575,7 @@ namespace NecromancerTome "necrogenie alpha <0-1> - body brightness (the body adds light, it is not alpha-blended)\n" + "necrogenie glow <0-1> - body's own glow (visible at night)\n" + "necrogenie tint - body colour\n" + - "necrogenie arms - arm pose, degrees: upper arm from vertical sideways and forward, elbow bend\n" + - "necrogenie cross <0|1> [fwd] [lift] [depth] - rest pose: hands on the opposite shoulders, left over right (1) or hanging (0); upper arm forward, degrees; left forearm over the right and chest depth, shares of shoulder width\n" + + "necrogenie arms [elbow] - gesture arms, degrees: upper arm from vertical sideways, elbow bend (rest pose 'attention' is the model's own)\n" + "necrogenie solid <0|1> - TEMPORARY: opaque body (1) to see the pose, or the ghostly glow (0)\n" + "necrogenie sleep - spirits and threads freeze when the player is farther (work goes on)\n" + "necrogenie hide|show - hide all spirits (weak PCs, video), work goes on"; @@ -690,42 +621,15 @@ namespace NecromancerTome break; case "arms": CinerariumGenie.ArmOut = v; - if (_params.Count >= 3 && float.TryParse(_params[2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float af)) - { - CinerariumGenie.ArmFwd = af; - } - if (_params.Count >= 4 && float.TryParse(_params[3], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float ae)) + if (_params.Count >= 3 && float.TryParse(_params[2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float ae)) { CinerariumGenie.Elbow = ae; } - foreach (CinerariumGenieMotion m in CinerariumGenie.Live) - { - m.Pose(); - } break; case "solid": CinerariumGenie.Solid = v != 0f; CinerariumGenie.ApplyAlpha(); break; - case "cross": - CinerariumGenie.Cross = v != 0f; - if (_params.Count >= 3 && float.TryParse(_params[2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float cf)) - { - CinerariumGenie.CrossFwd = cf; - } - if (_params.Count >= 4 && float.TryParse(_params[3], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float cl)) - { - CinerariumGenie.CrossLift = cl; - } - if (_params.Count >= 5 && float.TryParse(_params[4], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float cd)) - { - CinerariumGenie.CrossDepth = cd; - } - foreach (CinerariumGenieMotion m in CinerariumGenie.Live) - { - m.Pose(); - } - break; case "tint": if (_params.Count >= 4 && float.TryParse(_params[2], System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out float g) && @@ -744,7 +648,7 @@ namespace NecromancerTome ", bob " + CinerariumGenie.BobHeight.ToString("F2") + " / " + CinerariumGenie.BobPeriod.ToString("F1") + " s, alpha " + CinerariumGenie.Alpha.ToString("F2") + ", glow " + CinerariumGenie.Glow.ToString("F2") + ", tint " + CinerariumGenie.Tint.r.ToString("F2") + " " + CinerariumGenie.Tint.g.ToString("F2") + " " + CinerariumGenie.Tint.b.ToString("F2") + ", arms " + CinerariumGenie.ArmOut.ToString("F0") + " " + - CinerariumGenie.ArmFwd.ToString("F0") + " " + CinerariumGenie.Elbow.ToString("F0") + ", sleep " + CinerariumGenie.SleepDistance.ToString("F0") + " m" + (CinerariumGenie.Hidden ? ", HIDDEN" : "") + "; spirits on screen: " + CinerariumGenie.Live.Count); + CinerariumGenie.Elbow.ToString("F0") + ", sleep " + CinerariumGenie.SleepDistance.ToString("F0") + " m" + (CinerariumGenie.Hidden ? ", HIDDEN" : "") + "; spirits on screen: " + CinerariumGenie.Live.Count); } } } diff --git a/NecromancerHarmony.dll b/NecromancerHarmony.dll index 507a3cc..06eb8a4 100644 Binary files a/NecromancerHarmony.dll and b/NecromancerHarmony.dll differ diff --git a/NecromancerHarmony.pdb b/NecromancerHarmony.pdb index d17627b..2095a2b 100644 Binary files a/NecromancerHarmony.pdb and b/NecromancerHarmony.pdb differ diff --git a/Resources/necrotechnologist b/Resources/necrotechnologist index f7588b5..44fa6d1 100644 Binary files a/Resources/necrotechnologist and b/Resources/necrotechnologist differ