Одержимый зомби: оружие на поясе по ремеслу (#37), карта по M (#36)

- Пояс - нижний ряд сумки зомби; оружие ближнего боя в руку, если этот тип зомби
  им владеет (ZombieWeapons: таблица умений, утверждена 25.10). Удар как у персонажа:
  ItemActionAttack.Hit, урон предмета без перков зомби, износ, темп оружия.
  Модель на кость RightWeapon, хват WeaponHoldType; иконки и износ на поясе HUD.
  Неумелое или сломанное - кулаки и подсказка (13 языков). Выключатель
  necroarms weapon on|off; dev-команда necropossess для проверок без мыши.
- M в зомби и волке открывал сумку вместо карты (перехват windowpaging) - исправлено;
  туман карты и карта на одержимом - у любого одержимого зомби, как у стервятника.
- Глава «Одержимость» (EN/RU): пояс - оружие, M - карта.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
AlexCube
2026-10-25 14:26:55 +03:00
co-authored by Claude Opus 5.5
parent 5ebd09dacd
commit cf61d98bb7
8 changed files with 626 additions and 18 deletions
+73 -1
View File
@@ -68,6 +68,9 @@ namespace NecromancerTome
static GameObject _rig;
static SDCSUtils.TransformCatalog _bones;
/// <summary>Модель оружия с пояса в правой руке (#37) и чья она (тип предмета; -1 - кулаки).</summary>
static AssetManagement.InstanceHandle<GameObject> _weapon;
static int _weaponType = -1;
static bool _layerWasShown;
public static bool Active => _rig != null;
@@ -279,6 +282,65 @@ namespace NecromancerTome
}
}
/// <summary>Оружие с пояса в руках (#37): модель предмета на кость RightWeapon, как у персонажа от первого лица
/// (ItemInventoryData.SeatModel - без сдвига), и хват WeaponHoldType этого предмета; null - кулаки (хват 0).
/// Ставится каждый кадр, пересобирается только при смене предмета.</summary>
public static void SetWeapon(ItemValue _iv)
{
int type = _iv != null && !_iv.IsEmpty() ? _iv.type : -1;
if (_rig == null || type == _weaponType)
{
return;
}
DestroyWeapon();
_weaponType = type;
Animator a = Anim;
ItemClass ic = type >= 0 ? _iv.ItemClass : null;
Transform hand = _rig.transform.FindInChilds("RightWeapon");
if (ic != null && hand != null)
{
_weapon = ic.CloneModel(_iv, hand, BlockShape.MeshPurpose.Hold);
GameObject go = _weapon.Instance;
if (go != null)
{
go.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity);
if (!ic.GetCorrectionScale().Equals(Vector3.zero))
{
go.transform.localScale = ic.GetCorrectionScale();
}
int layer = LayerMask.NameToLayer("HoldingItem");
foreach (Transform t in go.GetComponentsInChildren<Transform>(true))
{
t.gameObject.layer = layer;
}
foreach (Collider c in go.GetComponentsInChildren<Collider>(true))
{
c.enabled = false;
}
go.SetActive(!ic.HoldingItemHidden);
}
}
if (a != null)
{
SetParam(a, "WeaponHoldType", ic != null ? ic.HoldType.Value : 0f);
SetParam(a, "ItemHasChangedTrigger", 1f);
}
Debug.Log("[NecromancerTome] FpArms: в руке " + (ic != null ? ic.Name + " (хват " + ic.HoldType.Value + (_weapon.Instance != null ? "" : ", БЕЗ модели") + ")" : "ничего - кулаки") +
(hand == null && ic != null ? " - кость RightWeapon не найдена" : ""));
}
static void DestroyWeapon()
{
if (_weapon.Instance != null)
{
_weapon.Instance.transform.SetParent(null, false);
_weapon.Instance.SetActive(false);
_weapon.Destroy();
}
_weapon = default(AssetManagement.InstanceHandle<GameObject>);
_weaponType = -1;
}
/// <summary>Анимация удара рук вошла в состояние удара (AnimatorMeleeAttackState у наших рук): через RaycastTime -
/// миг удара, как у персонажа (impactStart). Руки на это время уходят в нижнее положение (под прицел).</summary>
public static void OnSwingEnter(float _raycastTime)
@@ -421,6 +483,7 @@ namespace NecromancerTome
{
_player?.ShowHoldingItemLayer(false);
}
DestroyWeapon();
SDCSUtils.UnloadViz(_rig);
_rig = null;
_bones = null;
@@ -437,7 +500,7 @@ namespace NecromancerTome
public class ConsoleCmdNecroArms : ConsoleCmdAbstract
{
public override string[] getCommands() => new[] { "necroarms" };
public override string getDescription() => "NecromancerTome: руки одержимого от первого лица - [pos x y z | parent cam|ufps | anim | mat | set <param> <value> | trigger <name> | tint r g b | albedo on|off | punch <trigger> | fov <deg>]";
public override string getDescription() => "NecromancerTome: руки одержимого от первого лица - [pos x y z | parent cam|ufps | anim | mat | set <param> <value> | trigger <name> | tint r g b | albedo on|off | punch <trigger> | fov <deg> | weapon [on|off]]";
void Out(string _s)
{
@@ -477,6 +540,15 @@ namespace NecromancerTome
{
FpArms.ArmsFov = fov;
}
else if (cmd == "weapon")
{
if (_params.Count >= 2)
{
ZombieWeapons.Enabled = _params[1] != "off";
}
Out(Possession.Active && Possession.Zombie != null ? ZombieWeapons.Dump(Possession.Zombie) : "оружие " + (ZombieWeapons.Enabled ? "вкл" : "ВЫКЛ") + " (не в одержимости)");
return;
}
else if (cmd == "anim")
{
Out(FpArms.DumpAnim());