diff --git a/HarmonySrc/HandPosePose.cs b/HarmonySrc/HandPosePose.cs
index 38e8d88..9dd82fd 100644
--- a/HarmonySrc/HandPosePose.cs
+++ b/HarmonySrc/HandPosePose.cs
@@ -76,6 +76,8 @@ namespace NecromancerTome
/// положение ВСЕХ костей под Hips, и каждый кадр они возвращаются на место, а поверх - поза.
/// Снимок только в покое аниматора (ItemActionIndex = -1), иначе застыл бы кадр удара.
public static bool Freeze = true;
+ /// Замереть без своего хвата - на время осмотра со стороны (NecroView).
+ public static bool HoldStill;
static readonly List _frozen = new List();
static readonly List _frozenPos = new List();
static readonly List _frozenRot = new List();
@@ -87,6 +89,7 @@ namespace NecromancerTome
{
Enabled = false;
KnifeToLeft = false;
+ NecroView.Stop();
Overrides.Clear();
CamOverrides.Clear();
_jabStart = -1f;
@@ -143,10 +146,18 @@ namespace NecromancerTome
{
if (!Enabled || Overrides.Count == 0 && CamOverrides.Count == 0)
{
- if (_frozen.Count > 0)
+ if (HoldStill)
+ {
+ FreezeBones(); // осмотр со стороны (necroview): поза замирает и без своего хвата
+ }
+ else if (_frozen.Count > 0)
{
Unfreeze();
}
+ if (KnifeToLeft && Enabled)
+ {
+ ApplyKnifeToLeft();
+ }
return;
}
if (Freeze)
@@ -435,6 +446,7 @@ namespace NecromancerTome
HandHolds.Update();
HandPose.Apply();
HeldTweak.Apply();
+ NecroView.Update();
}
}
diff --git a/HarmonySrc/NecroView.cs b/HarmonySrc/NecroView.cs
new file mode 100644
index 0000000..45c6e85
--- /dev/null
+++ b/HarmonySrc/NecroView.cs
@@ -0,0 +1,146 @@
+using System.Collections.Generic;
+using System.Globalization;
+using UnityEngine;
+using UnityEngine.Scripting;
+
+namespace NecromancerTome
+{
+ ///
+ /// Осмотр рук от первого лица со стороны (16.10: «зафиксировать командой позу игрока и осматривать его камерой... хват
+ /// от первого лица не позволяет видеть всех нюансов»). Руки первого лица (baseRigFP) - отдельная модель под камерой
+ /// игрока, в виде от третьего лица их нет, а у тела свои анимации. Поэтому вид остаётся от первого лица, а поверх
+ /// рисует своя камера, которая облетает руки. Её место задано в осях камеры игрока: повернёшь голову - вид на руки
+ /// не меняется. Поза замирает (снимок всех костей, как у хватов мода).
+ /// Управление - цифровой блок: 4/6 вокруг, 8/2 выше/ниже, +/- ближе/дальше, 5 - сначала; или командой necroview.
+ ///
+ public static class NecroView
+ {
+ public static bool On;
+ public static float Yaw, Pitch, Dist = 0.6f;
+ /// Точка, вокруг которой летает камера (между кистями), - в осях камеры игрока.
+ static Vector3 _target;
+ static Camera _cam;
+ const float TurnSpeed = 60f, ZoomSpeed = 0.4f;
+
+ public static string Start(float _yaw, float _pitch, float _dist)
+ {
+ Transform pc = HandPose.Camera();
+ EntityPlayerLocal pl = GameManager.Instance?.World?.GetPrimaryPlayer();
+ if (pc == null || pl?.playerCamera == null)
+ {
+ return "нет камеры игрока";
+ }
+ Transform l = HandPose.Bone("LeftHand"), r = HandPose.Bone("RightHand");
+ Vector3 mid = l != null && r != null ? (l.position + r.position) * 0.5f : pc.position + pc.forward * 0.4f;
+ _target = pc.InverseTransformPoint(mid);
+ Yaw = _yaw;
+ Pitch = _pitch;
+ Dist = _dist;
+ if (_cam == null)
+ {
+ GameObject go = new GameObject("NecroViewCam");
+ Object.DontDestroyOnLoad(go);
+ _cam = go.AddComponent();
+ }
+ _cam.CopyFrom(pl.playerCamera);
+ _cam.depth = pl.playerCamera.depth + 50f;
+ _cam.nearClipPlane = 0.01f;
+ _cam.gameObject.SetActive(true);
+ HandPose.HoldStill = true;
+ On = true;
+ return "осмотр включён: вокруг " + Yaw + ", высота " + Pitch + ", расстояние " + Dist;
+ }
+
+ public static void Stop()
+ {
+ On = false;
+ HandPose.HoldStill = false;
+ if (_cam != null)
+ {
+ Object.Destroy(_cam.gameObject);
+ _cam = null;
+ }
+ }
+
+ /// Из HandPoseDriver.LateUpdate - после позы.
+ public static void Update()
+ {
+ if (!On)
+ {
+ return;
+ }
+ Transform pc = HandPose.Camera();
+ if (pc == null || _cam == null)
+ {
+ Stop();
+ return;
+ }
+ float dt = Time.unscaledDeltaTime;
+ if (Input.GetKey(KeyCode.Keypad4)) Yaw -= TurnSpeed * dt;
+ if (Input.GetKey(KeyCode.Keypad6)) Yaw += TurnSpeed * dt;
+ if (Input.GetKey(KeyCode.Keypad8)) Pitch = Mathf.Min(85f, Pitch + TurnSpeed * dt);
+ if (Input.GetKey(KeyCode.Keypad2)) Pitch = Mathf.Max(-85f, Pitch - TurnSpeed * dt);
+ if (Input.GetKey(KeyCode.KeypadPlus)) Dist = Mathf.Max(0.1f, Dist - ZoomSpeed * dt);
+ if (Input.GetKey(KeyCode.KeypadMinus)) Dist = Mathf.Min(3f, Dist + ZoomSpeed * dt);
+ if (Input.GetKeyDown(KeyCode.Keypad5))
+ {
+ Yaw = 0f;
+ Pitch = 0f;
+ Dist = 0.6f;
+ }
+ // Yaw 0, Pitch 0 - смотрим на руки со стороны глаз игрока (сзади), 180 - спереди.
+ Quaternion local = Quaternion.Euler(Pitch, Yaw, 0f);
+ Vector3 offset = local * new Vector3(0f, 0f, -Dist);
+ Vector3 t = pc.TransformPoint(_target);
+ _cam.transform.SetPositionAndRotation(t + pc.rotation * offset, pc.rotation * local);
+ }
+
+ public static string F(float _v) => _v.ToString("0.#", CultureInfo.InvariantCulture);
+ }
+
+ /// necroview on [вокруг высота расстояние] | off | set вокруг высота расстояние | show
+ [Preserve]
+ public class ConsoleCmdNecroView : ConsoleCmdAbstract
+ {
+ public override string[] getCommands() => new[] { "necroview" };
+ public override string getDescription() => "NecromancerTome: осмотр рук со стороны - on [вокруг высота расстояние]|off|set вокруг высота расстояние|show; цифровой блок 4/6 8/2 +/- 5";
+
+ static bool Num(List _p, int _i, out float _v)
+ {
+ _v = 0f;
+ return _p.Count > _i && float.TryParse(_p[_i].Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out _v);
+ }
+
+ void Out(string _s)
+ {
+ SdtdConsole.Instance.Output(_s);
+ Debug.Log("[NecromancerTome] necroview: " + _s);
+ }
+
+ public override void Execute(List _params, CommandSenderInfo _senderInfo)
+ {
+ string cmd = _params.Count > 0 ? _params[0] : "";
+ switch (cmd)
+ {
+ case "on":
+ Out(NecroView.Start(Num(_params, 1, out float y) ? y : 150f, Num(_params, 2, out float p) ? p : 10f, Num(_params, 3, out float d) ? d : 0.6f));
+ return;
+ case "off":
+ NecroView.Stop();
+ Out("осмотр выключен");
+ return;
+ case "set" when NecroView.On && Num(_params, 1, out float y2) && Num(_params, 2, out float p2) && Num(_params, 3, out float d2):
+ NecroView.Yaw = y2;
+ NecroView.Pitch = p2;
+ NecroView.Dist = d2;
+ break;
+ case "show":
+ break;
+ default:
+ Out(getDescription());
+ return;
+ }
+ Out(NecroView.On ? "вокруг " + NecroView.F(NecroView.Yaw) + ", высота " + NecroView.F(NecroView.Pitch) + ", расстояние " + NecroView.F(NecroView.Dist) : "осмотр выключен");
+ }
+ }
+}
diff --git a/NecromancerHarmony.dll b/NecromancerHarmony.dll
index e2e0662..fa44ea2 100644
Binary files a/NecromancerHarmony.dll and b/NecromancerHarmony.dll differ