using HarmonyLib; using UnityEngine; namespace NecromancerTome { /// /// Тело (вид от третьего лица и для других игроков) держит нож-для-нитей обычным хватом ножа, а не луком (16.10, скрин /// от третьего лица: «у персонажа запястье вывихнуто» - анимация деревянного лука тянет правую кисть с ножом). Хват /// предмета один на все модели (HoldType 68 нужен рукам первого лица - основа позы HandPose.PresetThread), поэтому /// подменяется только параметр аниматора WeaponHoldType/WeaponCarry у тел, кроме рук первого лица, и место ножа в /// руке тела. Подбор на лету: necroheld tphold N (0 - выключить подмену). /// public static class ThreadKnifeBody { public static int TpHold = 36; public static bool Applies(EntityAlive _e) { return TpHold > 0 && _e != null && _e.inventory?.holdingItem?.Name == CinerariumThreads.ThreadKnifeName; } } [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController._setInt), new[] { typeof(int), typeof(int), typeof(bool) })] public static class Patch_AvatarMultiBodyController_setInt_ThreadKnife { public static bool Prefix(AvatarMultiBodyController __instance, int _propertyHash, int _value) { bool hold = _propertyHash == AvatarController.weaponHoldTypeHash; if (!hold && _propertyHash != AvatarController.weaponCarryHash || !ThreadKnifeBody.Applies(__instance.Entity)) { return true; } BodyAnimator fp = (__instance as AvatarLocalPlayerController)?.FPSArms; int tp = hold ? ThreadKnifeBody.TpHold : AnimationDelayData.AnimationDelay[ThreadKnifeBody.TpHold].Carry; foreach (BodyAnimator b in __instance.BodyAnimators) { Animator a = b.Animator; int v = b == fp ? _value : tp; if (a != null && a.GetInteger(_propertyHash) != v) { a.SetInteger(_propertyHash, v); } } return false; // без рассылки по сети: у других игроков мод ставит то же сам } } /// Место ножа в руке тела - по хвату ножа (игра берёт смещение по HoldType предмета). [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.SetInRightHand))] public static class Patch_AvatarMultiBodyController_SetInRightHand_ThreadKnife { public static void Postfix(AvatarMultiBodyController __instance, Transform _transform) { EntityAlive e = __instance.Entity; if (_transform == null || !ThreadKnifeBody.Applies(e) || e.emodel.IsFPV && !e.isEntityRemote) { return; } AnimationGunjointOffsetData.AnimationGunjointOffsets o = AnimationGunjointOffsetData.AnimationGunjointOffset[ThreadKnifeBody.TpHold]; _transform.localPosition = o.position; _transform.localRotation = Quaternion.Euler(o.rotation); } } [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.SwitchModelAndView))] public static class Patch_AvatarMultiBodyController_SwitchModelAndView_ThreadKnife { public static void Postfix(AvatarMultiBodyController __instance, bool _bFPV) { Transform t = __instance.heldItemTransform; if (t == null || _bFPV || !ThreadKnifeBody.Applies(__instance.Entity)) { return; } AnimationGunjointOffsetData.AnimationGunjointOffsets o = AnimationGunjointOffsetData.AnimationGunjointOffset[ThreadKnifeBody.TpHold]; t.localPosition = o.position; t.localEulerAngles = o.rotation; } } }