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

FREE WeaponKillDamageBonus : 1.0.0 1.0.0

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

namespace Oxide.Plugins
{
    [Info("Weapon Kill Damage Bonus", "sonza", "1.0.0")]
    [Description("Tracks kills per weapon and increases damage by 2% for every 1000 kills with that weapon.")]
    public class WeaponKillDamageBonus : RustPlugin
    {
        private const string PermAdmin = "weaponkilldamagebonus.admin";

        private PluginConfig _config;
        private StoredData _data;

        #region Config

        private class PluginConfig
        {
            [JsonProperty("Kills required per damage tier")]
            public int KillsPerTier = 1000;

            [JsonProperty("Damage bonus per tier (0.02 = 2%)")]
            public float DamageBonusPerTier = 0.02f;

            [JsonProperty("Maximum damage bonus tiers (0 = unlimited)")]
            public int MaxTiers = 0;

            [JsonProperty("Only count player vs player kills")]
            public bool PlayerKillsOnly = true;

            [JsonProperty("Count scientist kills toward weapon bonuses")]
            public bool TrackScientistKills = true;

            [JsonProperty("Weapon shortnames excluded from tracking (optional)")]
            public List<string> ExcludedWeapons = new List<string>();

            [JsonProperty("Discord webhook enabled")]
            public bool DiscordWebhookEnabled = true;

            [JsonProperty("Discord webhook URL")]
            public string DiscordWebhookUrl = "";

            [JsonProperty("Discord webhook username")]
            public string DiscordWebhookUsername = "Weapon Kill Tracker";

            [JsonProperty("Discord embed color (decimal)")]
            public int DiscordEmbedColor = 3447003;

            [JsonProperty("Notify player in chat when milestone is reached")]
            public bool NotifyPlayerInChat = true;
        }

        protected override void LoadDefaultConfig()
        {
            _config = new PluginConfig();
            SaveConfig();
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                _config = Config.ReadObject<PluginConfig>();
                if (_config == null)
                {
                    throw new JsonException("Config file was empty.");
                }
            }
            catch
            {
                PrintWarning("Config invalid or missing. Creating a new default config.");
                LoadDefaultConfig();
            }
        }

        protected override void SaveConfig() => Config.WriteObject(_config, true);

        #endregion

        #region Data

        private class StoredData
        {
            public Dictionary<ulong, Dictionary<string, int>> PlayerWeaponKills = new Dictionary<ulong, Dictionary<string, int>>();
        }

        private void LoadData()
        {
            try
            {
                _data = Interface.Oxide.DataFileSystem.ReadObject<StoredData>(Name) ?? new StoredData();
            }
            catch
            {
                _data = new StoredData();
            }
        }

        private void SaveData() => Interface.Oxide.DataFileSystem.WriteObject(Name, _data);

        private int GetKillCount(ulong playerId, string weaponShortname)
        {
            if (!_data.PlayerWeaponKills.TryGetValue(playerId, out Dictionary<string, int> weapons))
            {
                return 0;
            }

            return weapons.TryGetValue(weaponShortname, out int kills) ? kills : 0;
        }

        private int AddKill(ulong playerId, string weaponShortname)
        {
            if (string.IsNullOrEmpty(weaponShortname))
            {
                return 0;
            }

            if (!_data.PlayerWeaponKills.TryGetValue(playerId, out Dictionary<string, int> weapons))
            {
                weapons = new Dictionary<string, int>();
                _data.PlayerWeaponKills[playerId] = weapons;
            }

            if (!weapons.TryGetValue(weaponShortname, out int kills))
            {
                kills = 0;
            }

            kills++;
            weapons[weaponShortname] = kills;
            SaveData();
            return kills;
        }

        #endregion

        #region Hooks

        private void Init()
        {
            permission.RegisterPermission(PermAdmin, this);
            LoadData();
        }

        private void Unload() => SaveData();

        private void OnServerSave() => SaveData();

        private void OnEntityDeath(BaseCombatEntity entity, HitInfo info)
        {
            if (entity == null || info == null)
            {
                return;
            }

            if (!ShouldCountKill(entity))
            {
                return;
            }

            BasePlayer attacker = info.InitiatorPlayer;
            if (attacker == null || attacker.IsNpc)
            {
                return;
            }

            BasePlayer victimPlayer = entity as BasePlayer;
            if (victimPlayer != null && attacker == victimPlayer)
            {
                return;
            }

            ItemDefinition weaponDef = GetWeaponDefinition(info);
            if (weaponDef == null || !ShouldTrackWeapon(weaponDef))
            {
                return;
            }

            int newKillCount = AddKill(attacker.userID, weaponDef.shortname);
            if (newKillCount > 0 && newKillCount % _config.KillsPerTier == 0)
            {
                int tier = newKillCount / _config.KillsPerTier;
                if (_config.MaxTiers > 0)
                {
                    tier = Math.Min(tier, _config.MaxTiers);
                }

                HandleKillMilestone(attacker, weaponDef, newKillCount, tier);
            }
        }

        private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
        {
            if (entity == null || info == null)
            {
                return;
            }

            BasePlayer attacker = info.InitiatorPlayer;
            if (attacker == null)
            {
                return;
            }

            ItemDefinition weaponDef = GetWeaponDefinition(info);
            if (weaponDef == null || !ShouldTrackWeapon(weaponDef))
            {
                return;
            }

            float multiplier = GetDamageMultiplier(attacker.userID, weaponDef.shortname);
            if (multiplier <= 1f)
            {
                return;
            }

            info.damageTypes.ScaleAll(multiplier);
        }

        #endregion

        #region Helpers

        private ItemDefinition GetWeaponDefinition(HitInfo info)
        {
            Item weaponItem = info.Weapon?.GetItem();
            if (weaponItem?.info != null)
            {
                return weaponItem.info;
            }

            AttackEntity attackEntity = info.Weapon;
            if (attackEntity == null)
            {
                return null;
            }

            BasePlayer holder = attackEntity.GetOwnerPlayer();
            Item heldItem = holder?.GetActiveItem();
            return heldItem?.info;
        }

        private bool ShouldCountKill(BaseCombatEntity entity)
        {
            BasePlayer victim = entity as BasePlayer;

            if (victim != null && !victim.IsNpc)
            {
                return true;
            }

            if (_config.TrackScientistKills && IsScientist(entity))
            {
                return true;
            }

            if (_config.PlayerKillsOnly)
            {
                return false;
            }

            return victim != null || IsScientist(entity);
        }

        private bool IsScientist(BaseCombatEntity entity)
        {
            if (entity == null)
            {
                return false;
            }

            if (entity is ScientistNPC)
            {
                return true;
            }

            string prefabName = entity.ShortPrefabName;
            return !string.IsNullOrEmpty(prefabName)
                && prefabName.IndexOf("scientist", StringComparison.OrdinalIgnoreCase) >= 0;
        }

        private bool ShouldTrackWeapon(ItemDefinition weaponDef)
        {
            if (weaponDef == null)
            {
                return false;
            }

            if (_config.ExcludedWeapons != null && _config.ExcludedWeapons.Contains(weaponDef.shortname))
            {
                return false;
            }

            return weaponDef.category == ItemCategory.Weapon;
        }

        private float GetDamageMultiplier(ulong playerId, string weaponShortname)
        {
            int kills = GetKillCount(playerId, weaponShortname);
            if (kills < _config.KillsPerTier)
            {
                return 1f;
            }

            int tiers = kills / _config.KillsPerTier;
            if (_config.MaxTiers > 0)
            {
                tiers = Math.Min(tiers, _config.MaxTiers);
            }

            return 1f + (tiers * _config.DamageBonusPerTier);
        }

        private string FormatBonusLine(string weaponShortname, int kills)
        {
            int tiers = kills / _config.KillsPerTier;
            float bonusPercent = tiers * _config.DamageBonusPerTier * 100f;
            int killsToNext = tiers > 0
                ? _config.KillsPerTier - (kills % _config.KillsPerTier)
                : _config.KillsPerTier - kills;

            if (killsToNext == _config.KillsPerTier && kills > 0)
            {
                killsToNext = 0;
            }

            string nextTierText = killsToNext == 0
                ? "max tier reached for current kills"
                : $"{killsToNext} kills to next +{_config.DamageBonusPerTier * 100f:0.#}%";

            return $"{weaponShortname}: {kills} kills | +{bonusPercent:0.#}% damage | {nextTierText}";
        }

        private void HandleKillMilestone(BasePlayer player, ItemDefinition weaponDef, int killCount, int tier)
        {
            float bonusPercent = tier * _config.DamageBonusPerTier * 100f;
            string weaponName = weaponDef.displayName.english;

            if (_config.NotifyPlayerInChat)
            {
                player.ChatMessage(
                    $"Milestone reached: {killCount} kills with {weaponName}. Damage bonus is now +{bonusPercent:0.#}%.");
            }

            SendDiscordWebhook(player, weaponDef.shortname, weaponName, killCount, tier, bonusPercent);
        }

        private void SendDiscordWebhook(
            BasePlayer player,
            string weaponShortname,
            string weaponName,
            int killCount,
            int tier,
            float bonusPercent)
        {
            if (!_config.DiscordWebhookEnabled || string.IsNullOrWhiteSpace(_config.DiscordWebhookUrl))
            {
                return;
            }

            Dictionary<string, object> embed = new Dictionary<string, object>
            {
                ["title"] = "Weapon Kill Milestone",
                ["color"] = _config.DiscordEmbedColor,
                ["fields"] = new List<Dictionary<string, object>>
                {
                    new Dictionary<string, object>
                    {
                        ["name"] = "Player",
                        ["value"] = $"{player.displayName}\n`{player.UserIDString}`",
                        ["inline"] = true
                    },
                    new Dictionary<string, object>
                    {
                        ["name"] = "Weapon",
                        ["value"] = $"{weaponName}\n`{weaponShortname}`",
                        ["inline"] = true
                    },
                    new Dictionary<string, object>
                    {
                        ["name"] = "Milestone",
                        ["value"] = $"{killCount} kills\nTier {tier}",
                        ["inline"] = true
                    },
                    new Dictionary<string, object>
                    {
                        ["name"] = "New Damage Bonus",
                        ["value"] = $"+{bonusPercent:0.#}%",
                        ["inline"] = false
                    }
                },
                ["footer"] = new Dictionary<string, object>
                {
                    ["text"] = $"Every {_config.KillsPerTier} kills = +{_config.DamageBonusPerTier * 100f:0.#}% damage"
                },
                ["timestamp"] = DateTime.UtcNow.ToString("o")
            };

            Dictionary<string, object> payload = new Dictionary<string, object>
            {
                ["username"] = _config.DiscordWebhookUsername,
                ["embeds"] = new List<Dictionary<string, object>> { embed }
            };

            string body = JsonConvert.SerializeObject(payload);
            Dictionary<string, string> headers = new Dictionary<string, string>
            {
                ["Content-Type"] = "application/json"
            };

            webrequest.Enqueue(
                _config.DiscordWebhookUrl.Trim(),
                body,
                (code, response) =>
                {
                    if (code != 200 && code != 204)
                    {
                        PrintWarning($"Discord webhook failed ({code}): {response}");
                    }
                },
                this,
                RequestMethod.POST,
                headers);
        }

        #endregion

        #region Commands

        [ChatCommand("weaponkills")]
        private void CmdWeaponKills(BasePlayer player, string command, string[] args)
        {
            BasePlayer target = player;

            if (args.Length > 0)
            {
                if (!permission.UserHasPermission(player.UserIDString, PermAdmin))
                {
                    player.ChatMessage("You do not have permission to view another player's stats.");
                    return;
                }

                target = BasePlayer.FindAwakeOrSleeping(args[0]) ?? BasePlayer.FindByID(Convert.ToUInt64(args[0]));
                if (target == null)
                {
                    player.ChatMessage("Player not found.");
                    return;
                }
            }

            if (!_data.PlayerWeaponKills.TryGetValue(target.userID, out Dictionary<string, int> weapons) || weapons.Count == 0)
            {
                player.ChatMessage(target == player
                    ? "You have no tracked weapon kills yet."
                    : $"{target.displayName} has no tracked weapon kills yet.");
                return;
            }

            StringBuilder sb = new StringBuilder();
            sb.AppendLine(target == player
                ? "Your weapon kill bonuses:"
                : $"{target.displayName}'s weapon kill bonuses:");

            foreach (KeyValuePair<string, int> entry in weapons.OrderByDescending(x => x.Value).Take(8))
            {
                sb.AppendLine(FormatBonusLine(entry.Key, entry.Value));
            }

            player.ChatMessage(sb.ToString().TrimEnd());
        }

        [ConsoleCommand("weaponkills.wipe")]
        private void CmdWeaponKillsWipe(ConsoleSystem.Arg arg)
        {
            if (arg.Connection != null && !permission.UserHasPermission(arg.Connection.userid.ToString(), PermAdmin))
            {
                arg.ReplyWith("You do not have permission to use this command.");
                return;
            }

            if (arg.Args == null || arg.Args.Length == 0)
            {
                arg.ReplyWith("Usage: weaponkills.wipe <steamid|all>");
                return;
            }

            if (arg.Args[0].Equals("all", StringComparison.OrdinalIgnoreCase))
            {
                _data.PlayerWeaponKills.Clear();
                SaveData();
                arg.ReplyWith("Cleared all weapon kill data.");
                return;
            }

            if (!ulong.TryParse(arg.Args[0], out ulong userId))
            {
                arg.ReplyWith("Invalid SteamID.");
                return;
            }

            _data.PlayerWeaponKills.Remove(userId);
            SaveData();
            arg.ReplyWith($"Cleared weapon kill data for {userId}.");
        }

        #endregion
    }
}

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