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
}
}