Одержимость: вид от первого лица по ~/ё
Клавиша QuickMenu (~/ё, как переключение вида у персонажа) переключает вид; каждое вселение начинается от третьего лица. Камера в голове со сглаживанием, голова сжата почти в точку, прицел без запаса на свою спину. Подсказка на 13 языках. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
361948193a
commit
7c0a48eec6
@@ -143,6 +143,14 @@ namespace NecromancerTome
|
||||
|
||||
/// <summary>Камера - позади и выше головы зомби.</summary>
|
||||
public const float CamBack = 2.6f;
|
||||
/// <summary>Вид от первого лица (указание 13.10): клавиша ~/ё - как переключение вида у персонажа в игре
|
||||
/// (QuickMenu, по умолчанию Backquote; и CameraChange геймпада), каждое вселение начинается от третьего лица. Камера - в голове, голова сжата
|
||||
/// (HideHead), положение глаз сглажено (FpSmooth) - голова зомби на ходу мотается.</summary>
|
||||
public static bool FirstPerson;
|
||||
public const float FpForward = 0.12f, FpSmooth = 12f;
|
||||
static Vector3 _fpEye;
|
||||
static Transform _hiddenHead;
|
||||
static Vector3 _hiddenHeadScale;
|
||||
public const float CamUp = 0.6f;
|
||||
/// <summary>Как далеко зомби замечают одержимого: зрение зомби - 30 м (entityclasses.xml SightRange).</summary>
|
||||
public const float TauntRange = 30f;
|
||||
@@ -296,6 +304,7 @@ namespace NecromancerTome
|
||||
_nextTaunt = 0f;
|
||||
_nextScream = 0f;
|
||||
_loggedCamera = false;
|
||||
FirstPerson = false;
|
||||
// Пояс одержимому питомцу ни к чему (указание 06.10); открыться заново не даёт
|
||||
// Patch_GUIWindowManager_openInternal_SnakeToolbelt, после выхода игра откроет его сама.
|
||||
if (_pet)
|
||||
@@ -344,6 +353,8 @@ namespace NecromancerTome
|
||||
return;
|
||||
}
|
||||
Active = false;
|
||||
FirstPerson = false;
|
||||
HideHead(null);
|
||||
RatLoot.CloseIfViewing();
|
||||
WolfBag.CloseWindow();
|
||||
RatPhase.Stop(GameManager.Instance?.World, Zombie, "выход из одержимости");
|
||||
@@ -562,6 +573,16 @@ namespace NecromancerTome
|
||||
// кнопка геймпада (тест 03.10: «подрыва нету»).
|
||||
detonate = input.Activate.WasPressed || input.PermanentActions.Activate.WasPressed;
|
||||
}
|
||||
if (input != null && !gui && (input.CameraChange.WasPressed || input.QuickMenu.WasPressed || input.PermanentActions.QuickMenu.WasPressed))
|
||||
{
|
||||
FirstPerson = !FirstPerson;
|
||||
_fpEye = Vector3.zero;
|
||||
if (!FirstPerson)
|
||||
{
|
||||
HideHead(null);
|
||||
}
|
||||
Debug.Log("[NecromancerTome] Possession: вид от " + (FirstPerson ? "первого" : "третьего") + " лица");
|
||||
}
|
||||
if (input != null && !gui && input.ToggleCrouch.WasPressed)
|
||||
{
|
||||
_crouchToggled = !_crouchToggled;
|
||||
@@ -1449,7 +1470,7 @@ namespace NecromancerTome
|
||||
/// <summary>Подсказка при вселении: что умеет этот зомби.</summary>
|
||||
static void Hint(EntityPlayerLocal _p, EntityAlive _z)
|
||||
{
|
||||
string text = Localization.Get("necroPossessHintBase");
|
||||
string text = Localization.Get("necroPossessHintBase") + ", " + Localization.Get("necroPossessHintView");
|
||||
if (Flying)
|
||||
{
|
||||
text += ", " + Localization.Get("necroPossessHintFly");
|
||||
@@ -1570,7 +1591,7 @@ namespace NecromancerTome
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
RaycastHit hit = _aimHits[i];
|
||||
if (hit.distance <= CamBack + 0.5f || hit.distance >= best ||
|
||||
if (hit.distance <= (FirstPerson ? 0.1f : CamBack + 0.5f) || hit.distance >= best ||
|
||||
self != null && (hit.transform == self || hit.transform.IsChildOf(self)))
|
||||
{
|
||||
continue;
|
||||
@@ -2003,6 +2024,28 @@ namespace NecromancerTome
|
||||
_flyZoomHeld = false;
|
||||
}
|
||||
|
||||
/// <summary>Голова одержимого сжата почти в точку, пока вид от первого лица, - иначе камера внутри черепа
|
||||
/// (у зомби модель цельная, отдельных рук, как у персонажа, нет). Ставится каждый кадр после аниматора;
|
||||
/// null - вернуть прежний масштаб.</summary>
|
||||
static void HideHead(Transform _head)
|
||||
{
|
||||
if (_hiddenHead != null && _hiddenHead != _head)
|
||||
{
|
||||
_hiddenHead.localScale = _hiddenHeadScale;
|
||||
_hiddenHead = null;
|
||||
}
|
||||
if (_head == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_hiddenHead == null)
|
||||
{
|
||||
_hiddenHead = _head;
|
||||
_hiddenHeadScale = _head.localScale;
|
||||
}
|
||||
_head.localScale = Vector3.one * 0.001f;
|
||||
}
|
||||
|
||||
/// <summary>Из постфикса vp_FPCamera.LateUpdate: камера позади и выше головы зомби, не сквозь стены.</summary>
|
||||
public static void PlaceCamera(Transform _camera)
|
||||
{
|
||||
@@ -2020,6 +2063,18 @@ namespace NecromancerTome
|
||||
Transform head = z.emodel != null ? z.emodel.GetHeadTransform() : null;
|
||||
Vector3 anchor = head != null ? head.position : z.position - Origin.position + Vector3.up * 1.6f;
|
||||
Quaternion rot = Quaternion.Euler(-_pitch, _yaw, 0f);
|
||||
if (FirstPerson)
|
||||
{
|
||||
// Положение головы - уже после аниматора (мы в LateUpdate камеры), до сжатия: сжатие масштаба
|
||||
// самой кости её положения не меняет.
|
||||
Vector3 want = anchor + rot * Vector3.forward * FpForward;
|
||||
_fpEye = _fpEye == Vector3.zero || (want - _fpEye).sqrMagnitude > 4f
|
||||
? want
|
||||
: Vector3.Lerp(_fpEye, want, 1f - Mathf.Exp(-FpSmooth * Time.deltaTime));
|
||||
HideHead(head);
|
||||
_camera.SetPositionAndRotation(_fpEye, rot);
|
||||
return;
|
||||
}
|
||||
Vector3 eye = anchor + Vector3.up * CamUp - rot * Vector3.forward * CamBack;
|
||||
Vector3 to = eye - anchor;
|
||||
if (Physics.Raycast(anchor, to.normalized, out RaycastHit hit, to.magnitude + 0.2f, SnakeControl.WallMask, QueryTriggerInteraction.Ignore))
|
||||
|
||||
Reference in New Issue
Block a user