Одержимость от первого лица: руки как у игрока, серые, только у гуманоидов обычной комплекции
FpArms собирает руки для первого лица по шагам игры (baseRigFPPrefab + голая кожа basePartsFP, аниматор FPPlayerController), пол по зомби (BaseMale/BaseFemale), кожа серая через _Tint, без одежды. ~/ё работает только у списка гуманоидов; подсказка - только им. Коллайдеры рук выключены. Ударов пока нет. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
eb540bd500
commit
f5f4d92cef
@@ -0,0 +1,142 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NecromancerTome
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Руки одержимого в виде от первого лица (указание 13.10: «делаем так, как у игрока»). У персонажа игры две
|
||||||
|
/// модели: полное тело (его видят другие и он сам со стороны) и отдельные руки для первого лица (baseRigFP,
|
||||||
|
/// SDCSUtils.CreateVizFP) - рисуются только у себя. Здесь собираем такие же руки по тем же шагам игры:
|
||||||
|
/// скелет baseRigFPPrefab с аниматором FPPlayerController, голая кожа (basePartsFP), без одежды и волос
|
||||||
|
/// (указание: «одежду пока не показываем»). Пол - по зомби (IsMale): BaseMale или BaseFemale из
|
||||||
|
/// archetypes.xml. Кожа серая (указание: «руки вообще серые - типа зомби их так видит») - цвет _Tint у
|
||||||
|
/// материала кожи, как игра красит тон кожи.
|
||||||
|
///
|
||||||
|
/// Руки - под UFPSRoot камеры игрока, как у персонажа; камеру одержимости мы ставим в голову зомби, руки
|
||||||
|
/// едут вместе с ней. Слой HoldingItem - его камера игрока рисует только при ShowHoldingItemLayer(true).
|
||||||
|
///
|
||||||
|
/// Только гуманоиды обычной комплекции (Allows), указание 13.10.
|
||||||
|
///
|
||||||
|
/// ПАМЯТЬ. Одна модель рук на время вида от первого лица; Hide выгружает её (SDCSUtils.UnloadViz - материалы
|
||||||
|
/// и ссылки на ассеты освобождаются) - на переключении вида и на выходе из одержимости.
|
||||||
|
/// </summary>
|
||||||
|
public static class FpArms
|
||||||
|
{
|
||||||
|
/// <summary>Начала имён классов, у кого вид от первого лица (варианты Feral/Radiated/Charged/Infernal - тоже).</summary>
|
||||||
|
static readonly string[] Allowed =
|
||||||
|
{
|
||||||
|
"zombieArlene", "zombieBiker", "zombieBoe", "zombieBowler", "zombieBurnt", "zombieBusinessMan", "zombieDarlene",
|
||||||
|
"zombieInmate", "zombieJanitor", "zombieJoe", "zombieLab", "zombieLumberjack", "zombieMaleHazmat", "zombieMarlene",
|
||||||
|
"zombieMoe", "zombieNurse", "zombiePartyGirl", "zombieSkateboarder", "zombieSoldier", "zombieSteve", "zombieTomClark",
|
||||||
|
"zombieUtilityWorker", "zombieYo",
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly Color Tint = new Color(0.55f, 0.56f, 0.55f, 1f);
|
||||||
|
|
||||||
|
static GameObject _rig;
|
||||||
|
static SDCSUtils.TransformCatalog _bones;
|
||||||
|
static bool _layerWasShown;
|
||||||
|
|
||||||
|
public static bool Active => _rig != null;
|
||||||
|
|
||||||
|
public static bool Allows(EntityAlive _z)
|
||||||
|
{
|
||||||
|
if (_z == null || !EntityClass.list.TryGetValue(_z.entityClass, out EntityClass cls) || cls?.entityClassName == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
string name = cls.entityClassName;
|
||||||
|
if (name.Contains("Crawler"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
foreach (string a in Allowed)
|
||||||
|
{
|
||||||
|
if (name.StartsWith(a))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Show(EntityPlayerLocal _player, EntityAlive _z)
|
||||||
|
{
|
||||||
|
if (_rig != null || _player == null || _z == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Archetype arch = Archetype.GetArchetype(_z.IsMale ? "BaseMale" : "BaseFemale");
|
||||||
|
Transform cam = _player.cameraTransform;
|
||||||
|
if (arch == null || cam == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("[NecromancerTome] FpArms: нет архетипа или камеры - рук не будет");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Transform parent = cam.FindInChildren("UFPSRoot") ?? cam;
|
||||||
|
Archetype wasArch = SDCSUtils.tmpArchetype;
|
||||||
|
SDCSUtils.AssetRefs wasOwner = SDCSUtils.tmpAssetsOwner;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SDCSUtils.tmpArchetype = arch;
|
||||||
|
SDCSUtils.setupRig(ref _rig, ref _bones, SDCSUtils.baseRigFPPrefab, parent, SDCSUtils.FPAnimController);
|
||||||
|
SDCSUtils.tmpAssetsOwner = SDCSUtils.GetAssetOwnerForRig(_rig);
|
||||||
|
SDCSUtils.setupBase(_rig, _bones, SDCSUtils.basePartsFP, true);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
SDCSUtils.tmpArchetype = wasArch;
|
||||||
|
SDCSUtils.tmpAssetsOwner = wasOwner;
|
||||||
|
}
|
||||||
|
_rig.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
|
||||||
|
_rig.name = "necroZombieArmsFP";
|
||||||
|
int layer = LayerMask.NameToLayer("HoldingItem");
|
||||||
|
int tinted = 0;
|
||||||
|
foreach (SkinnedMeshRenderer smr in _rig.GetComponentsInChildren<SkinnedMeshRenderer>(true))
|
||||||
|
{
|
||||||
|
smr.gameObject.layer = layer;
|
||||||
|
// Материалы с _Tint игра уже размножила для этой модели (SDCSUtils.Stitch) - красим свои копии.
|
||||||
|
foreach (Material m in smr.sharedMaterials)
|
||||||
|
{
|
||||||
|
if (m != null && m.HasColor("_Tint"))
|
||||||
|
{
|
||||||
|
m.SetColor("_Tint", Tint);
|
||||||
|
tinted++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Коллайдеры рук (у женского скелета игра вешает капсулу на таз) - выключены: руки в голове зомби ловили бы
|
||||||
|
// луч прицела и толкали бы предметы.
|
||||||
|
foreach (Collider c in _rig.GetComponentsInChildren<Collider>(true))
|
||||||
|
{
|
||||||
|
c.enabled = false;
|
||||||
|
}
|
||||||
|
foreach (HingeJoint j in _rig.GetComponentsInChildren<HingeJoint>(true))
|
||||||
|
{
|
||||||
|
if (j.connectedBody == null)
|
||||||
|
{
|
||||||
|
j.gameObject.SetActive(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_layerWasShown = _player.playerCamera != null && (_player.playerCamera.cullingMask & (1 << layer)) != 0;
|
||||||
|
_player.ShowHoldingItemLayer(true);
|
||||||
|
Debug.Log("[NecromancerTome] FpArms: руки " + arch.Name + " для " + _z.EntityName + ", серых материалов " + tinted +
|
||||||
|
", родитель " + parent.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Hide(EntityPlayerLocal _player)
|
||||||
|
{
|
||||||
|
if (_rig == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!_layerWasShown)
|
||||||
|
{
|
||||||
|
_player?.ShowHoldingItemLayer(false);
|
||||||
|
}
|
||||||
|
SDCSUtils.UnloadViz(_rig);
|
||||||
|
_rig = null;
|
||||||
|
_bones = null;
|
||||||
|
Debug.Log("[NecromancerTome] FpArms: руки убраны");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -356,6 +356,7 @@ namespace NecromancerTome
|
|||||||
Active = false;
|
Active = false;
|
||||||
FirstPerson = false;
|
FirstPerson = false;
|
||||||
HideBody(null);
|
HideBody(null);
|
||||||
|
FpArms.Hide(_player);
|
||||||
RatLoot.CloseIfViewing();
|
RatLoot.CloseIfViewing();
|
||||||
WolfBag.CloseWindow();
|
WolfBag.CloseWindow();
|
||||||
RatPhase.Stop(GameManager.Instance?.World, Zombie, "выход из одержимости");
|
RatPhase.Stop(GameManager.Instance?.World, Zombie, "выход из одержимости");
|
||||||
@@ -574,13 +575,20 @@ namespace NecromancerTome
|
|||||||
// кнопка геймпада (тест 03.10: «подрыва нету»).
|
// кнопка геймпада (тест 03.10: «подрыва нету»).
|
||||||
detonate = input.Activate.WasPressed || input.PermanentActions.Activate.WasPressed;
|
detonate = input.Activate.WasPressed || input.PermanentActions.Activate.WasPressed;
|
||||||
}
|
}
|
||||||
if (input != null && !gui && (input.CameraChange.WasPressed || input.QuickMenu.WasPressed || input.PermanentActions.QuickMenu.WasPressed))
|
// Только гуманоиды обычной комплекции (указание 13.10, FpArms.Allows) - у остальных ~/ё ничего не делает.
|
||||||
|
if (input != null && !gui && FpArms.Allows(z) &&
|
||||||
|
(input.CameraChange.WasPressed || input.QuickMenu.WasPressed || input.PermanentActions.QuickMenu.WasPressed))
|
||||||
{
|
{
|
||||||
FirstPerson = !FirstPerson;
|
FirstPerson = !FirstPerson;
|
||||||
_fpEye = Vector3.zero;
|
_fpEye = Vector3.zero;
|
||||||
if (!FirstPerson)
|
if (FirstPerson)
|
||||||
|
{
|
||||||
|
FpArms.Show(_player, z);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
HideBody(null);
|
HideBody(null);
|
||||||
|
FpArms.Hide(_player);
|
||||||
}
|
}
|
||||||
Debug.Log("[NecromancerTome] Possession: вид от " + (FirstPerson ? "первого" : "третьего") + " лица");
|
Debug.Log("[NecromancerTome] Possession: вид от " + (FirstPerson ? "первого" : "третьего") + " лица");
|
||||||
}
|
}
|
||||||
@@ -1494,7 +1502,11 @@ namespace NecromancerTome
|
|||||||
/// <summary>Подсказка при вселении: что умеет этот зомби.</summary>
|
/// <summary>Подсказка при вселении: что умеет этот зомби.</summary>
|
||||||
static void Hint(EntityPlayerLocal _p, EntityAlive _z)
|
static void Hint(EntityPlayerLocal _p, EntityAlive _z)
|
||||||
{
|
{
|
||||||
string text = Localization.Get("necroPossessHintBase") + ", " + Localization.Get("necroPossessHintView");
|
string text = Localization.Get("necroPossessHintBase");
|
||||||
|
if (FpArms.Allows(_z))
|
||||||
|
{
|
||||||
|
text += ", " + Localization.Get("necroPossessHintView");
|
||||||
|
}
|
||||||
if (Flying)
|
if (Flying)
|
||||||
{
|
{
|
||||||
text += ", " + Localization.Get("necroPossessHintFly");
|
text += ", " + Localization.Get("necroPossessHintFly");
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user