Иконка ресурса

FREE FacePunch : 2.4.3 2.4.3

Нет прав для скачивания
C#:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using UnityEngine;

namespace Oxide.Plugins
{
	[Info("FacePunch", "Raul-Sorin Sorban", "2.4.3")]
	[Description("Punch players in the face (consensually).")]
	public class FacePunch : RustPlugin
	{
		private static readonly System.Random Random = new System.Random();

		public const string DefaultHitEffect = "assets/bundled/prefabs/fx/impacts/stab/wood/wood1.prefab";
		public const string DefaultBleedEffect = "assets/bundled/prefabs/fx/impacts/blunt/flesh/fleshbloodimpact.prefab";
		public const string DefaultWaterSplashEffect = "assets/bundled/prefabs/fx/impacts/slash/water/water.prefab";

		private Dictionary<BasePlayer, BaseEntity> ItemHoldCache { get; } = new Dictionary<BasePlayer, BaseEntity>();

		[PluginReference] Plugin StaticLootables;

		#region Overrides

#if !CARBON
		public DynamicConfigFile Config { get; } = new("oxide/config/FacePunch.json");
#else
		public DynamicConfigFile Config { get; } = new("FacePunch.json");
#endif

		private void Init()
		{
			InstallPermissions();
		}
		private void Loaded()
		{
			if (!Config.Exists())
			{
				ConfigInstance = new RootConfig();

				OnServerSave();
			}
			else
			{
				try
				{
					ConfigInstance = Config.ReadObject<RootConfig>();
				}
				catch (Exception exception)
				{
					Puts($"Broken configuration: {exception.Message}");

					ConfigInstance = new RootConfig();

					OnServerSave();
				}
			}
		}
		private void OnServerSave()
		{
			Config.WriteObject(ConfigInstance);
		}
		private void OnPlayerInput(BasePlayer initiatorPlayer, InputState input)
		{
			if (initiatorPlayer.IsDead() || initiatorPlayer.IsWounded() || initiatorPlayer.IsSleeping() || !HasPermission(initiatorPlayer, UsePerm)) return;

			var holdsAnyItem = initiatorPlayer.IsHoldingEntity<BaseEntity>();

			if (!ItemHoldCache.ContainsKey(initiatorPlayer)) ItemHoldCache[initiatorPlayer] = initiatorPlayer.GetHeldEntity();

			var previouslyHeldEntity = ItemHoldCache[initiatorPlayer];
			var newlyHeldEntity = initiatorPlayer.GetHeldEntity();
			if (newlyHeldEntity != previouslyHeldEntity)
			{
				if (newlyHeldEntity is Keycard) { if (!TriggerPunchCooldown(initiatorPlayer, 0.8f)) return; }
				else if (newlyHeldEntity is Hammer) if (!TriggerPunchCooldown(initiatorPlayer, 0.8f)) return;

				initiatorPlayer.Invoke(() => { ItemHoldCache[initiatorPlayer] = initiatorPlayer.GetHeldEntity(); }, 0.8f);
				return;
			}

			if (((newlyHeldEntity is Keycard) ||
				(newlyHeldEntity is Hammer)) &&
				 HasPermission(initiatorPlayer, UseSlicePerm))
			{
				if ((!input.IsDown(BUTTON.FIRE_PRIMARY))) return;
			}
			else
			{
				if ((ConfigInstance.HeldClickPunching ? !input.IsDown(BUTTON.FIRE_PRIMARY) : !input.WasJustPressed(BUTTON.FIRE_PRIMARY))) return;
			}

			if (!GamePhysics.Trace(initiatorPlayer.eyes.HeadRay(), 0.0f, out var hitInfo, 1.5f, ~0))
			{
				return;
			}

			if (holdsAnyItem)
			{
				if (initiatorPlayer.GetHeldEntity() is Keycard && HasPermission(initiatorPlayer, UseSlicePerm) && ConfigInstance.EnableSlice) Slice(initiatorPlayer, hitInfo.collider?.gameObject, hitInfo.point);
				else if (initiatorPlayer.GetHeldEntity() is Hammer && HasPermission(initiatorPlayer, UseHammerPerm) && ConfigInstance.EnableHammer) HammerHit(initiatorPlayer, hitInfo.collider?.gameObject, hitInfo.point);

				return;
			}

			Punch(initiatorPlayer, hitInfo);
		}

		#endregion

		#region Cooldown

		private Dictionary<ulong, long> PunchCooldownPool { get; } = new Dictionary<ulong, long>();
		private Dictionary<ulong, long> GutshotScreamCooldownPool { get; } = new Dictionary<ulong, long>();

		private bool TriggerPunchCooldown(BasePlayer player, float? cooldown = null)
		{
			if (cooldown == null) cooldown = ConfigInstance.PunchCooldown;

			if (PunchCooldownPool.ContainsKey(player.userID))
			{
				var previousDate = new DateTime(PunchCooldownPool[player.userID]);
				if (DateTime.Now.Subtract(previousDate).TotalSeconds < cooldown) { return true; }

				PunchCooldownPool[player.userID] = DateTime.Now.Ticks;
			}
			else { PunchCooldownPool.Add(player.userID, DateTime.Now.Ticks); }

			return false;
		}
		private bool TriggerGutshotScreamCooldown(BasePlayer player)
		{
			if (GutshotScreamCooldownPool.ContainsKey(player.userID))
			{
				var previousDate = new DateTime(GutshotScreamCooldownPool[player.userID]);
				if (DateTime.Now.Subtract(previousDate).TotalSeconds < ConfigInstance.GruntCooldown) { return true; }

				GutshotScreamCooldownPool[player.userID] = DateTime.Now.Ticks;
			}
			else { GutshotScreamCooldownPool.Add(player.userID, DateTime.Now.Ticks); }

			return false;
		}

		#endregion

		#region Methods

		public void Punch(BasePlayer initiatorPlayer, RaycastHit info)
		{
			var entity = info.GetEntity();

			if (entity != null)
			{
				var targetPlayer = entity as BasePlayer;
				var damageableEntity = targetPlayer != null ? null : entity as BaseCombatEntity;
				var damageRule = entity as NPCPlayer != null ? ConfigInstance.NpcDamage : ConfigInstance.PlayerDamage;
				var resourceEntity = damageableEntity != null ? null : entity as ResourceEntity;
				var terrainObject = resourceEntity == null ? entity.transform.root : null;
				if (terrainObject == null) terrainObject = entity.transform;

				if (targetPlayer != null && targetPlayer != initiatorPlayer)
				{
					var impactEffect = targetPlayer.impactEffect.isValid
						? targetPlayer.impactEffect.resourcePath
						: null;
					if (string.IsNullOrEmpty(impactEffect))
						impactEffect = "assets/bundled/prefabs/fx/player/fall-damage.prefab";
					if (TriggerPunchCooldown(initiatorPlayer)) return;
					if (!(initiatorPlayer.Distance(targetPlayer) <= damageRule.Distance)) return;

					Effect.server.Run("assets/bundled/prefabs/fx/player/swing_weapon.prefab",
						initiatorPlayer.transform.position, Vector3.zero);
					if (ConfigInstance.AnimateAttacker)
						initiatorPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, "hurry");
					ServerMgr.Instance.Invoke(() =>
					{
						Effect.server.Run(impactEffect, info.point, Vector3.zero);

						if (!ConfigInstance.OnePunchManMode)
						{
							damageRule.MakeBleed(initiatorPlayer);
							damageRule.MakeTargetBleed(targetPlayer, initiatorPlayer);
						}

						damageRule.MakeTargetHurt(targetPlayer, initiatorPlayer, ConfigInstance.OnePunchManMode);
						if (ConfigInstance.AnimatePlayerTargets)
							targetPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, "whoa");
					}, 0.2f);

					return;
				}
				else
				{
					if (damageableEntity != null)
					{
						var impactEffect = damageableEntity.impactEffect.isValid
							? damageableEntity.impactEffect.resourcePath
							: null;

						damageRule = null;
						if (damageableEntity is LootContainer) damageRule = ConfigInstance.LootContainerDamage;
						else if (damageableEntity is BradleyAPC) damageRule = ConfigInstance.BradleyDamage;
						else if (damageableEntity is BaseAnimalNPC) damageRule = ConfigInstance.AnimalDamage;
						else if (damageableEntity is RidableHorse) damageRule = ConfigInstance.HorseDamage;
						else if (damageableEntity is BuildingBlock) damageRule = ConfigInstance.BuildingBlocksDamage;

						if (damageRule == null) return;
						if (string.IsNullOrEmpty(impactEffect))
							impactEffect =
								damageRule.FistBleedAmount > 0 && !damageRule.HasHandsCovered(initiatorPlayer)
									? DefaultBleedEffect
									: DefaultHitEffect;

						if (TriggerPunchCooldown(initiatorPlayer)) return;
						if (initiatorPlayer.Distance(info.point) > damageRule.Distance) return;

						Effect.server.Run("assets/bundled/prefabs/fx/player/swing_weapon.prefab",
							initiatorPlayer.transform.position, Vector3.zero);
						if (ConfigInstance.AnimateAttacker)
							initiatorPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, "hurry");
						ServerMgr.Instance.Invoke(() =>
						{
							Effect.server.Run(impactEffect, info.point, Vector3.zero);

							if (!ConfigInstance.OnePunchManMode)
							{
								if (damageRule.MakeBleed(initiatorPlayer))
								{
									if (!TriggerGutshotScreamCooldown(initiatorPlayer))
									{
										ServerMgr.Instance.Invoke(
											() =>
											{
												Effect.server.Run(
													"assets/bundled/prefabs/fx/player/gutshot_scream.prefab",
													initiatorPlayer.transform.position, Vector3.zero);
											}, 0.2f);
									}
								}
							}

							damageRule.MakeTargetHurt(damageableEntity, initiatorPlayer, ConfigInstance.OnePunchManMode,
								damageableEntity is BradleyAPC ? Rust.DamageType.Explosion : Rust.DamageType.Slash);
						}, 0.2f);

						return;
					}

					if (resourceEntity != null)
					{
						var impactEffect = resourceEntity.impactEffect.isValid
							? resourceEntity.impactEffect.resourcePath
							: null;
						if (string.IsNullOrEmpty(impactEffect))
							impactEffect =
								ConfigInstance.ResourceDamage.FistBleedAmount > 0 &&
								!ConfigInstance.ResourceDamage.HasHandsCovered(initiatorPlayer)
									? DefaultBleedEffect
									: DefaultHitEffect;

						if (TriggerPunchCooldown(initiatorPlayer)) return;
						if (initiatorPlayer.Distance(info.point) > ConfigInstance.ResourceDamage.Distance) return;

						Effect.server.Run("assets/bundled/prefabs/fx/player/swing_weapon.prefab",
							initiatorPlayer.transform.position, Vector3.zero);
						if (ConfigInstance.AnimateAttacker)
							initiatorPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, "hurry");
						ServerMgr.Instance.Invoke(() =>
						{
							initiatorPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, null);
							Effect.server.Run(impactEffect, info.point, Vector3.zero);

							if (!ConfigInstance.OnePunchManMode)
							{
								if (ConfigInstance.ResourceDamage.MakeBleed(initiatorPlayer))
								{
									if (!TriggerGutshotScreamCooldown(initiatorPlayer))
									{
										ServerMgr.Instance.Invoke(
											() =>
											{
												Effect.server.Run(
													"assets/bundled/prefabs/fx/player/gutshot_scream.prefab",
													initiatorPlayer.transform.position, Vector3.zero);
											}, 0.2f);
									}
								}
							}
						}, 0.2f);

						return;
					}
					else if (terrainObject != null && initiatorPlayer.serverInput.IsDown(BUTTON.DUCK))
					{
						if (terrainObject.GetComponent<WaterBody>() != null) return;

						var impactEffect =
							ConfigInstance.TerrainDamage.FistBleedAmount > 0 &&
							!ConfigInstance.TerrainDamage.HasHandsCovered(initiatorPlayer)
								? DefaultBleedEffect
								: DefaultHitEffect;

						if (TriggerPunchCooldown(initiatorPlayer)) return;
						if (initiatorPlayer.Distance(info.point) > ConfigInstance.TerrainDamage.Distance) return;

						Effect.server.Run("assets/bundled/prefabs/fx/player/swing_weapon.prefab",
							initiatorPlayer.transform.position, Vector3.zero);
						if (ConfigInstance.AnimateAttacker)
							initiatorPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, "hurry");
						ServerMgr.Instance.Invoke(() =>
						{
							initiatorPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, null);
							Effect.server.Run(impactEffect, info.point, Vector3.zero);

							if (!ConfigInstance.OnePunchManMode)
							{
								if (ConfigInstance.TerrainDamage.MakeBleed(initiatorPlayer))
								{
									if (!TriggerGutshotScreamCooldown(initiatorPlayer))
									{
										ServerMgr.Instance.Invoke(
											() =>
											{
												Effect.server.Run(
													"assets/bundled/prefabs/fx/player/gutshot_scream.prefab",
													initiatorPlayer.transform.position, Vector3.zero);
											}, 0.2f);
									}
								}
							}
						}, 0.2f);

						return;
					}
				}
			}

			var water = GetWaterBody(info);

			if (water != null)
			{
				if (TriggerPunchCooldown(initiatorPlayer)) return;
				if (initiatorPlayer.Distance(info.point) > ConfigInstance.WaterDamage.Distance) return;

				Effect.server.Run("assets/bundled/prefabs/fx/player/swing_weapon.prefab",
					initiatorPlayer.transform.position, Vector3.zero);
				if (ConfigInstance.AnimateAttacker) initiatorPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, "hurry");
				ServerMgr.Instance.Invoke(() =>
				{
					initiatorPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, null);
					Effect.server.Run(DefaultWaterSplashEffect, info.point, Vector3.zero);

					if (!ConfigInstance.OnePunchManMode)
					{
						var isSaltWater = water.Type == WaterBodyType.Ocean;
						ConfigInstance.WaterDamage.MakeHeal(initiatorPlayer, isSaltWater);
						if (ConfigInstance.WaterDamage.GiveTrout(initiatorPlayer, isSaltWater))
						{
							if (!TriggerGutshotScreamCooldown(initiatorPlayer))
							{
								ServerMgr.Instance.Invoke(
									() =>
									{
										Effect.server.Run("assets/bundled/prefabs/fx/player/gutshot_scream.prefab",
											initiatorPlayer.transform.position, Vector3.zero);
									}, 0.2f);
							}
						}
					}
				}, 0.2f);
			}

			if (TriggerPunchCooldown(initiatorPlayer)) return;

			Effect.server.Run("assets/bundled/prefabs/fx/player/swing_weapon.prefab",
				initiatorPlayer.transform.position, Vector3.zero);
			if (ConfigInstance.AnimateAttacker) initiatorPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, "hurry");

			ServerMgr.Instance.Invoke(() =>
			{
				if (!TriggerGutshotScreamCooldown(initiatorPlayer))
				{
					ServerMgr.Instance.Invoke(
						() =>
						{
							Effect.server.Run(
								"assets/bundled/prefabs/fx/player/gutshot_scream.prefab",
								initiatorPlayer.transform.position, Vector3.zero);
						}, 0.2f);
				}

				ConfigInstance.StaticLootableDamage.MakeBleed(initiatorPlayer);

				initiatorPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, null);
				Effect.server.Run(DefaultBleedEffect, info.point, Vector3.zero);

				StaticLootables?.CallHook("EmulateAttack", initiatorPlayer, info.collider.gameObject, ConfigInstance.StaticLootableDamage.DamageMin, ConfigInstance.StaticLootableDamage.DamageMax);
			}, 0.2f);
		}

		public void Slice(BasePlayer initiatorPlayer, GameObject hitObject, Vector3 hitpoint)
		{
			var entity = hitObject?.transform?.GetComponentInParent<BaseEntity>();
			if (hitObject != null)
			{
				var targetPlayer = entity as BasePlayer;
				var damageableEntity = targetPlayer != null ? null : entity as BaseCombatEntity;
				var damageRule = entity as NPCPlayer != null ? ConfigInstance.NpcDamage : ConfigInstance.PlayerDamage;
				var resourceEntity = damageableEntity != null ? null : entity as ResourceEntity;
				var terrainObject = resourceEntity == null ? hitObject?.transform.root : null;
				if (terrainObject == null) terrainObject = hitObject?.transform;

				if (targetPlayer != null && targetPlayer != initiatorPlayer)
				{
					var impactEffect = targetPlayer.impactEffect.isValid ? targetPlayer.impactEffect.resourcePath : null;
					if (string.IsNullOrEmpty(impactEffect)) impactEffect = DefaultBleedEffect;
					if (TriggerPunchCooldown(initiatorPlayer, ConfigInstance.SliceCooldown)) return;
					if (!(initiatorPlayer.Distance(targetPlayer) <= damageRule.Distance)) return;

					ServerMgr.Instance.Invoke(() =>
					{
						Effect.server.Run(impactEffect, hitpoint, Vector3.zero);

						if (!ConfigInstance.OnePunchManMode)
						{
							damageRule.MakeBleed(initiatorPlayer);
							damageRule.MakeTargetBleed(targetPlayer, initiatorPlayer);
						}

						damageRule.MakeTargetHurt(targetPlayer, initiatorPlayer, ConfigInstance.OnePunchManMode);
						if (ConfigInstance.AnimatePlayerTargets) targetPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, "whoa");
					}, 0.2f);

					return;
				}
				else if (damageableEntity != null)
				{
					var impactEffect = damageableEntity.impactEffect.isValid ? damageableEntity.impactEffect.resourcePath : null;

					damageRule = null;
					if (damageableEntity is LootContainer) damageRule = ConfigInstance.LootContainerDamage;
					else if (damageableEntity is BradleyAPC) damageRule = ConfigInstance.BradleyDamage;
					else if (damageableEntity is BaseAnimalNPC) { damageRule = ConfigInstance.AnimalDamage; impactEffect = DefaultBleedEffect; }
					else if (damageableEntity is RidableHorse) { damageRule = ConfigInstance.HorseDamage; impactEffect = DefaultBleedEffect; }
					else if (damageableEntity is BuildingBlock) damageRule = ConfigInstance.BuildingBlocksDamage;

					if (damageRule == null) return;
					if (string.IsNullOrEmpty(impactEffect)) impactEffect = DefaultHitEffect;

					if (TriggerPunchCooldown(initiatorPlayer, ConfigInstance.SliceCooldown)) return;
					if (initiatorPlayer.Distance(hitpoint) > damageRule.Distance) return;

					ServerMgr.Instance.Invoke(() =>
					{
						Effect.server.Run(impactEffect, hitpoint, Vector3.zero);

						damageRule.MakeTargetHurt(damageableEntity, initiatorPlayer, ConfigInstance.OnePunchManMode, damageableEntity is BradleyAPC ? Rust.DamageType.Explosion : Rust.DamageType.Slash);
					}, 0.2f);

					return;
				}
				else if (resourceEntity != null)
				{
					var impactEffect = resourceEntity.impactEffect.isValid ? resourceEntity.impactEffect.resourcePath : null;
					if (string.IsNullOrEmpty(impactEffect)) impactEffect = DefaultHitEffect;

					if (TriggerPunchCooldown(initiatorPlayer, ConfigInstance.SliceCooldown)) return;
					if (initiatorPlayer.Distance(hitpoint) > ConfigInstance.ResourceDamage.Distance) return;

					ServerMgr.Instance.Invoke(() =>
					{
						Effect.server.Run(impactEffect, hitpoint, Vector3.zero);
					}, 0.2f);

					return;
				}
				else if (terrainObject != null && initiatorPlayer.serverInput.IsDown(BUTTON.DUCK))
				{
					if (terrainObject.GetComponent<WaterBody>() != null) return;

					var impactEffect = DefaultHitEffect;

					if (TriggerPunchCooldown(initiatorPlayer, ConfigInstance.SliceCooldown)) return;
					if (initiatorPlayer.Distance(hitpoint) > ConfigInstance.TerrainDamage.Distance) return;

					ServerMgr.Instance.Invoke(() =>
					{
						Effect.server.Run(impactEffect, hitpoint, Vector3.zero);
					}, 0.2f);

					return;
				}
			}

			var water = hitObject?.transform?.root?.GetComponent<WaterBody>();
			if (water != null)
			{
				if (TriggerPunchCooldown(initiatorPlayer)) return;
				if (initiatorPlayer.Distance(hitpoint) > ConfigInstance.WaterDamage.Distance) return;

				Effect.server.Run("assets/bundled/prefabs/fx/player/swing_weapon.prefab", initiatorPlayer.transform.position, Vector3.zero);
				ServerMgr.Instance.Invoke(() =>
				{
					initiatorPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, null);
					Effect.server.Run(DefaultWaterSplashEffect, hitpoint, Vector3.zero);

					if (!ConfigInstance.OnePunchManMode)
					{
						var isSaltWater = water.Type == WaterBodyType.Ocean;
						ConfigInstance.WaterDamage.MakeHeal(initiatorPlayer, isSaltWater);
						if (ConfigInstance.WaterDamage.GiveTrout(initiatorPlayer, isSaltWater))
						{
							if (!TriggerGutshotScreamCooldown(initiatorPlayer))
							{
								ServerMgr.Instance.Invoke(() => { Effect.server.Run("assets/bundled/prefabs/fx/player/gutshot_scream.prefab", initiatorPlayer.transform.position, Vector3.zero); }, 0.2f);
							}
						}
					}
				}, 0.2f);
			}
		}

		public void HammerHit(BasePlayer initiatorPlayer, GameObject hitObject, Vector3 hitpoint)
		{
			var entity = hitObject?.transform?.GetComponentInParent<BaseEntity>();
			if (hitObject != null)
			{

				var targetPlayer = entity as BasePlayer;
				var damageableEntity = targetPlayer != null ? null : entity as BaseCombatEntity;
				var damageRule = entity?.GetComponentInParent<NPCPlayer>() != null ? ConfigInstance.NpcDamage : ConfigInstance.PlayerDamage;
				var resourceEntity = damageableEntity != null ? null : entity as ResourceEntity;
				var terrainObject = resourceEntity == null ? hitObject?.transform.root : null;
				if (terrainObject == null) terrainObject = hitObject?.transform;

				if (targetPlayer != null && targetPlayer != initiatorPlayer)
				{
					var impactEffect = targetPlayer.impactEffect.isValid ? targetPlayer.impactEffect.resourcePath : null;
					if (string.IsNullOrEmpty(impactEffect)) impactEffect = "assets/bundled/prefabs/fx/player/fall-damage.prefab";
					if (TriggerPunchCooldown(initiatorPlayer, ConfigInstance.HammerCooldown)) return;
					if (!(initiatorPlayer.Distance(targetPlayer) <= damageRule.Distance)) return;

					ServerMgr.Instance.Invoke(() =>
					{
						Effect.server.Run(impactEffect, hitpoint, Vector3.zero);

						if (!ConfigInstance.OnePunchManMode)
						{
							damageRule.MakeBleed(initiatorPlayer);
							damageRule.MakeTargetBleed(targetPlayer, initiatorPlayer);
						}

						if (ConfigInstance.AnimatePlayerTargets) targetPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, "whoa");
					}, 0.2f);

					return;
				}
				else if (damageableEntity != null)
				{
					var impactEffect = damageableEntity.impactEffect.isValid ? damageableEntity.impactEffect.resourcePath : null;

					damageRule = null;
					if (damageableEntity is LootContainer) damageRule = ConfigInstance.LootContainerDamage;
					else if (damageableEntity is BradleyAPC) damageRule = ConfigInstance.BradleyDamage;
					else if (damageableEntity is BaseAnimalNPC) { damageRule = ConfigInstance.AnimalDamage; impactEffect = DefaultBleedEffect; }
					else if (damageableEntity is RidableHorse) { damageRule = ConfigInstance.HorseDamage; impactEffect = DefaultBleedEffect; }
					else if (damageableEntity is BuildingBlock) damageRule = ConfigInstance.BuildingBlocksDamage;

					if (damageRule == null) return;
					if (string.IsNullOrEmpty(impactEffect)) impactEffect = DefaultHitEffect;

					if (TriggerPunchCooldown(initiatorPlayer, ConfigInstance.HammerCooldown)) return;
					if (initiatorPlayer.Distance(hitpoint) > damageRule.Distance) return;

					ServerMgr.Instance.Invoke(() =>
					{
						if (!(damageableEntity is LootContainer)) Effect.server.Run(impactEffect, hitpoint, Vector3.zero);
						damageRule.MakeTargetHurt(damageableEntity, initiatorPlayer, ConfigInstance.OnePunchManMode, damageableEntity is BradleyAPC ? Rust.DamageType.Explosion : Rust.DamageType.Slash);
					}, 0.2f);

					return;
				}
				else if (resourceEntity != null)
				{
					var impactEffect = resourceEntity.impactEffect.isValid ? resourceEntity.impactEffect.resourcePath : null;
					if (string.IsNullOrEmpty(impactEffect)) impactEffect = DefaultHitEffect;

					if (TriggerPunchCooldown(initiatorPlayer, ConfigInstance.HammerCooldown)) return;
					if (initiatorPlayer.Distance(hitpoint) > ConfigInstance.ResourceDamage.Distance) return;

					ServerMgr.Instance.Invoke(() =>
					{
						Effect.server.Run(impactEffect, hitpoint, Vector3.zero);
					}, 0.2f);

					return;
				}
				else if (terrainObject != null && initiatorPlayer.serverInput.IsDown(BUTTON.DUCK))
				{
					if (terrainObject.GetComponent<WaterBody>() != null) return;

					var impactEffect = DefaultHitEffect;

					if (TriggerPunchCooldown(initiatorPlayer, ConfigInstance.HammerCooldown)) return;
					if (initiatorPlayer.Distance(hitpoint) > ConfigInstance.TerrainDamage.Distance) return;

					ServerMgr.Instance.Invoke(() =>
					{
						Effect.server.Run(impactEffect, hitpoint, Vector3.zero);
					}, 0.2f);

					return;
				}
			}

			var water = hitObject?.transform?.root?.GetComponent<WaterBody>();
			if (water != null)
			{
				if (TriggerPunchCooldown(initiatorPlayer, ConfigInstance.HammerCooldown)) return;
				if (initiatorPlayer.Distance(hitpoint) > ConfigInstance.WaterDamage.Distance) return;

				Effect.server.Run("assets/bundled/prefabs/fx/player/swing_weapon.prefab", initiatorPlayer.transform.position, Vector3.zero);
				if (ConfigInstance.AnimateAttacker) initiatorPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, "hurry");
				ServerMgr.Instance.Invoke(() =>
				{
					initiatorPlayer.SignalBroadcast(BaseEntity.Signal.Gesture, null);
					Effect.server.Run(DefaultWaterSplashEffect, hitpoint, Vector3.zero);

					if (!ConfigInstance.OnePunchManMode)
					{
						var isSaltWater = water.Type == WaterBodyType.Ocean;
						ConfigInstance.WaterDamage.MakeHeal(initiatorPlayer, isSaltWater);
						if (ConfigInstance.WaterDamage.GiveTrout(initiatorPlayer, isSaltWater))
						{
							if (!TriggerGutshotScreamCooldown(initiatorPlayer))
							{
								ServerMgr.Instance.Invoke(() => { Effect.server.Run("assets/bundled/prefabs/fx/player/gutshot_scream.prefab", initiatorPlayer.transform.position, Vector3.zero); }, 0.2f);
							}
						}
					}
				}, 0.2f);
			}
		}

		public static WaterBody GetWaterBody(RaycastHit hit)
		{
			if (hit.collider == null)
				return WaterSystem.Ocean;

			Transform transform = hit.collider.transform;
			WaterBody component;
			return transform.TryGetComponent<WaterBody>(out component) ? component : transform.parent != null ? transform.parent.GetComponentInChildren<WaterBody>() : null;
		}

		#endregion

		#region Permission

		public const string UsePerm = "facepunch.use";
		public const string UseSlicePerm = "facepunch.useslice";
		public const string UseHammerPerm = "facepunch.usehammer";

		private void InstallPermissions()
		{
			permission.RegisterPermission(UsePerm, this);
			permission.RegisterPermission(UseSlicePerm, this);
			permission.RegisterPermission(UseHammerPerm, this);
		}
		private bool HasPermission(BasePlayer player, string perm)
		{
			if (!permission.UserHasPermission(player.UserIDString, perm))
			{
				return false;
			}

			return true;
		}

		#endregion

		#region Input

		private RaycastHit[] buffer = new RaycastHit[5];

		private static bool TryGetPlayerView(BasePlayer player, out Quaternion viewAngle)
		{
			viewAngle = new Quaternion(0f, 0f, 0f, 0f);

			var input = player.serverInput;

			if (input == null)
				return false;
			if (input.current == null)
				return false;

			viewAngle = Quaternion.Euler(input.current.aimAngles);
			return true;
		}

		#endregion

		#region Extensions

		private static float Scale(float oldValue, float oldMin, float oldMax, float newMin, float newMax)
		{
			var oldRange = (oldMax - oldMin);
			var newRange = (newMax - newMin);
			var newValue = (((oldValue - oldMin) * newRange) / oldRange) + newMin;

			return newValue;
		}

		#endregion

		#region Config

		public new RootConfig ConfigInstance { get; set; } = new RootConfig();

		public class RootConfig
		{
			public bool OnePunchManMode { get; set; } = false;
			public bool EnableSlice { get; set; } = true;
			public bool EnableHammer { get; set; } = true;

			public float PunchCooldown { get; set; } = 0.75f;
			public float SliceCooldown { get; set; } = 0.86f;
			public float HammerCooldown { get; set; } = 0.4725f;
			public float GruntCooldown { get; set; } = 3f;
			public bool HeldClickPunching { get; set; } = true;
			public bool AnimateAttacker { get; set; } = true;
			public bool AnimatePlayerTargets { get; set; } = true;

			public DamageRule PlayerDamage { get; set; } = new DamageRule(0.4f, 1.5f, 5.0f);
			public DamageRule NpcDamage { get; set; } = new DamageRule(0.4f, 7.5f, 10.0f);
			public DamageRule AnimalDamage { get; set; } = new DamageRule(0.55f, 2.5f);
			public DamageRule HorseDamage { get; set; } = new DamageRule(0.55f, 2.5f, fistBleedAmount: 0.25f);
			public DamageRule LootContainerDamage { get; set; } = new DamageRule(0.25f, 2.5f, fistBleedAmount: 0.5f);
			public DamageRule BradleyDamage { get; set; } = new DamageRule(0.55f, 2.5f);
			public DamageRule BuildingBlocksDamage { get; set; } = new DamageRule(0.25f, 1.5f, 2.5f, fistBleedAmount: 0.6f);
			public DamageRule TerrainDamage { get; set; } = new DamageRule(0.15f, 0f, fistBleedAmount: 0.75f);
			public DamageRule ResourceDamage { get; set; } = new DamageRule(0.25f, 0f, fistBleedAmount: 0.75f);
			public DamageRule StaticLootableDamage { get; set; } = new DamageRule(1, 2.5f, 4.5f, fistBleedAmount: 0.4f);
			public WaterRule WaterDamage { get; set; } = new WaterRule(0.35f);

			public class DamageRule
			{
				public float Distance { get; set; }
				public float DamageMin { get; set; }
				public float DamageMax { get; set; }
				public float FistBleedAmount { get; set; }

				public DamageRule() { }
				public DamageRule(float distance, float damageMin, float damageMax = 0f, float fistBleedAmount = 0f)
				{
					Distance = distance;
					DamageMin = damageMin;
					DamageMax = damageMax;
					FistBleedAmount = fistBleedAmount;
				}

				public float GetTargetDamage()
				{
					if (DamageMax <= 0) return DamageMin;

					return Random.Next((int)(DamageMin * 100f), (int)(DamageMax * 100)) / 100;
				}
				public void MakeTargetHurt(BaseCombatEntity target, BasePlayer initiator, bool onePunchManMode, Rust.DamageType damageType = Rust.DamageType.Bleeding)
				{
					var amount = GetTargetDamage();
					target.Hurt(amount * (onePunchManMode ? 10000000 : 1), damageType, initiator);
				}
				public void MakeTargetBleed(BasePlayer target, BasePlayer initiator)
				{
					var amount = GetTargetDamage() * 2;
					target.metabolism.bleeding.Add(HasHandsCovered(initiator) ? amount / 3 : amount);
				}
				public bool MakeBleed(BasePlayer initiator)
				{
					if (FistBleedAmount <= 0f) return false;
					if (!HasHandsCovered(initiator)) { initiator.metabolism.bleeding.Add(FistBleedAmount); return true; }
					return false;
				}

				public bool HasHandsCovered(BasePlayer player)
				{
					return player.inventory.containerWear.itemList.Any(x =>
						x.info.shortname == "burlap.gloves.new" ||
						x.info.shortname == "burlap.gloves" ||
						x.info.shortname == "roadsign.gloves" ||
						x.info.shortname == "tactical.gloves" ||
						x.info.shortname == "scientistsuit_heavy" ||
						x.info.shortname == "hazmatsuit_scientist" ||
						x.info.shortname == "hazmatsuit_scientist_peacekeeper" ||
						x.info.shortname == "barrelcostume" ||
						x.info.shortname == "cratecostume" ||
						x.info.shortname == "ghostsheet" ||
						x.info.shortname == "hazmatsuit");
				}
			}
			public class WaterRule
			{
				public float Distance { get; set; }
				public WaterType Salt { get; set; } = new WaterType(healingAmount: 0.25f, fistBleedHealingAmount: 0.5f, smallTroutGatherChanceAmount: 20, smallTroutGatherChanceTimes: 1);
				public WaterType Pure { get; set; } = new WaterType();

				public WaterRule() { }
				public WaterRule(float distance)
				{
					Distance = distance;
				}

				public bool MakeHeal(BasePlayer initiator, bool isSaltWater)
				{
					var fistBleedHealingAmount = isSaltWater ? Salt.FistBleedHealingAmount : Pure.FistBleedHealingAmount;
					var healingAmount = isSaltWater ? Salt.HealingAmount : Pure.HealingAmount;

					if (fistBleedHealingAmount <= 0f || initiator.metabolism.bleeding.value <= 0) return false;

					if (!HasHandsCovered(initiator))
					{
						initiator.Heal(healingAmount);
						initiator.metabolism.bleeding.Subtract(fistBleedHealingAmount); return true;
					}
					return false;
				}
				public bool GiveTrout(BasePlayer initiator, bool isSaltWater)
				{
					var water = isSaltWater ? Salt : Pure;
					if (Random.Next(0, water.SmallTroutGatherChanceAmount) > water.SmallTroutGatherChanceTimes - 1) return false;

					var troutItem = ItemManager.CreateByName("fish.troutsmall", 1);
					initiator.GiveItem(troutItem, BaseEntity.GiveItemReason.ResourceHarvested);
					return true;
				}

				public bool HasHandsCovered(BasePlayer player)
				{
					return player.inventory.containerWear.itemList.Any(x =>
						x.info.shortname == "burlap.gloves.new" ||
						x.info.shortname == "burlap.gloves" ||
						x.info.shortname == "roadsign.gloves" ||
						x.info.shortname == "tactical.gloves" ||
						x.info.shortname == "scientistsuit_heavy" ||
						x.info.shortname == "hazmatsuit_scientist" ||
						x.info.shortname == "hazmatsuit_scientist_peacekeeper" ||
						x.info.shortname == "barrelcostume" ||
						x.info.shortname == "cratecostume" ||
						x.info.shortname == "ghostsheet" ||
						x.info.shortname == "hazmatsuit");
				}

				public class WaterType
				{
					[JsonProperty("HealingAmount (Heals player only if bleeding)")]
					public float HealingAmount { get; set; }
					public float FistBleedHealingAmount { get; set; }
					public int SmallTroutGatherChanceAmount { get; set; } = 10;
					public int SmallTroutGatherChanceTimes { get; set; } = -1;

					public WaterType() { }
					public WaterType(
						float healingAmount,
						float fistBleedHealingAmount,
						int smallTroutGatherChanceAmount,
						int smallTroutGatherChanceTimes)
					{
						HealingAmount = healingAmount;
						FistBleedHealingAmount = fistBleedHealingAmount;
						SmallTroutGatherChanceAmount = smallTroutGatherChanceAmount;
						SmallTroutGatherChanceTimes = smallTroutGatherChanceTimes;
					}
				}
			}
		}

		#endregion
	}
}

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху