Jump to content

Fixed

Pending 1.4.3

HAB
HAB

Posted

using System;
using Newtonsoft.Json;
using Oxide.Core;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Oxide.Core.Plugins;

namespace Oxide.Plugins
{
    [Info("The Door Knocker", "Cannabis", "1.4.4")]
    [Description("Allows players to shoot multiple rockets at once with configurable settings")]
    class TheDoorKnocker : RustPlugin
    {
        #region Declarations

        private const string useperm = "thedoorknocker.use";
        private SavedData data;

        #endregion

        #region Oxide Hooks

        void Init()
        {
            // Register permissions
            foreach (var kvp in config.maxRocketPermission)
            {
                permission.RegisterPermission(kvp.Key, this);
            }
            permission.RegisterPermission(useperm, this);

            // Register language messages and command
            lang.RegisterMessages(_messages, this);
            cmd.AddChatCommand(config.rocketamtcmd, this, nameof(CmdHandleRockets));

            // Load data
            data = SavedData.Load();

            // Clean old data if enabled
            if (config.cleanOldData)
            {
                timer.Once(5f, () =>
                {
                    foreach (var userID in data.playerData.Keys.ToList())
                    {
                        if (data.playerData[userID]?.lastSeen == null) continue;
                        TimeSpan timeDifference = DateTime.UtcNow - data.playerData[userID].lastSeen;
                        if (timeDifference.TotalDays >= config.daysSinceLastSeenToClean)
                        {
                            data.playerData.Remove(userID);
                        }
                    }
                    data.Save();
                });
            }
        }

        void OnPlayerConnected(BasePlayer player)
        {
            if (player == null || !permission.UserHasPermission(player.UserIDString, useperm) || data.playerData.ContainsKey(player.userID)) return;

            InitializePlayerData(player.userID);
        }

        void OnUserPermissionGranted(string id, string permName)
        {
            if (!ulong.TryParse(id, out ulong userID) || (permName != useperm && !config.maxRocketPermission.ContainsKey(permName))) return;
            
            if (!data.playerData.ContainsKey(userID))
            {
                InitializePlayerData(userID);
            }
        }

        void OnUserGroupAdded(string playerId, string groupName)
        {
            if (!ulong.TryParse(playerId, out ulong userID)) return;
            
            string[] permissions = permission.GetGroupPermissions(groupName);
            if (!permissions.Contains(useperm) || data.playerData.ContainsKey(userID)) return;

            InitializePlayerData(userID);
        }

        void OnNewSave(string filename)
        {
            if (config.wipeOnWipe)
            {
                data = new SavedData();
                data.Save();
            }
        }

        void OnPlayerDisconnected(BasePlayer player, string reason)
        {
            if (player != null && data.playerData.ContainsKey(player.userID))
            {
                data.playerData[player.userID].lastSeen = DateTime.UtcNow;
                data.Save();
            }
        }

        void OnUserPermissionRevoked(string id, string permName)
        {
            if (!ulong.TryParse(id, out ulong userID)) return;
            BasePlayer player = BasePlayer.FindByID(userID);
            if (player == null) return;

            if (permName == useperm && data.playerData.ContainsKey(userID))
            {
                data.playerData.Remove(userID);
                data.Save();
            }
            else if (config.maxRocketPermission.ContainsKey(permName) && permission.UserHasPermission(id, useperm) && data.playerData.ContainsKey(userID))
            {
                data.playerData[userID].playerRockets = config.defaultPlayerData.amount;
                data.Save();
            }
        }

        void OnRocketLaunched(BasePlayer player, BaseEntity entity)
        {
            if (player == null || !permission.UserHasPermission(player.UserIDString, useperm) || !data.playerData.ContainsKey(player.userID) || !data.playerData[player.userID].rocketsEnabled) return;

            Item heldItem = player.GetActiveItem();
            if (heldItem?.info?.shortname != "rocket.launcher") return;

            BaseProjectile.Magazine rocketMagazine = player.GetHeldEntity()?.GetComponent<BaseProjectile>()?.primaryMagazine;
            if (rocketMagazine == null) return;

            int rocketsSent = Math.Min(data.playerData[player.userID].playerRockets, GetMaxRockets(player));
            if (rocketsSent < 1) return;

            int rocketType;
            string ammoType = rocketMagazine.ammoType?.shortname ?? string.Empty;

            switch (ammoType)
            {
                case "ammo.rocket.basic":
                    if (config.blockTypes.Contains("basic") || !data.playerData[player.userID].playerPreferences.basicRocket) return;
                    rocketType = 1;
                    break;
                case "ammo.rocket.hv":
                    if (config.blockTypes.Contains("hv") || !data.playerData[player.userID].playerPreferences.hvRocket) return;
                    rocketType = 2;
                    break;
                case "ammo.rocket.fire":
                    if (config.blockTypes.Contains("fire") || !data.playerData[player.userID].playerPreferences.fireRocket) return;
                    rocketType = 3;
                    break;
                case "ammo.rocket.smoke":
                    if (config.blockTypes.Contains("smoke") || !data.playerData[player.userID].playerPreferences.smokeRocket) return;
                    rocketType = 4;
                    break;
                default:
                    if (!data.playerData[player.userID].playerPreferences.basicRocket) return;
                    rocketType = 1;
                    break;
            }

            SpawnRockets(player, rocketsSent, rocketType);
        }

        void Unload()
        {
            data.Save();
        }

        #endregion

        #region Commands

        private void CmdHandleRockets(BasePlayer player, string command, string[] args)
        {
            if (player == null || !permission.UserHasPermission(player.UserIDString, useperm))
            {
                PrintToChat(player, lang.GetMessage("NoPermission", this, player.UserIDString));
                return;
            }

            if (!data.playerData.ContainsKey(player.userID))
            {
                InitializePlayerData(player.userID);
            }

            if (args.Length == 0 || args.Length > 2)
            {
                PrintToChat(player, lang.GetMessage("NoArgs", this, player.UserIDString));
                return;
            }

            int maxRockets = GetMaxRockets(player);
            if (maxRockets == 0)
            {
                PrintToChat(player, lang.GetMessage("InvalidRockets", this, player.UserIDString));
                return;
            }

            if (int.TryParse(args[0], out int amount))
            {
                if (amount > maxRockets)
                {
                    PrintToChat(player, string.Format(lang.GetMessage("TooMany", this, player.UserIDString), maxRockets));
                    return;
                }

                if (amount <= 0)
                {
                    PrintToChat(player, lang.GetMessage("NoZero", this, player.UserIDString));
                    return;
                }

                data.UpdateAmount(player.userID, amount);
                PrintToChat(player, string.Format(lang.GetMessage("ChangeRockets", this, player.UserIDString), amount));
                return;
            }

            if (bool.TryParse(args[0], out bool enabled))
            {
                data.UpdateEnabled(player.userID, enabled);
                PrintToChat(player, lang.GetMessage(enabled ? "TurnedOn" : "TurnedOff", this, player.UserIDString));
                return;
            }

            if (args[0].ToLower() == "toggle" && args.Length == 2)
            {
                string type = args[1].ToLower();
                if (config.blockTypes.Contains(type))
                {
                    PrintToChat(player, string.Format(lang.GetMessage("TypeDisabledTryToggle", this, player.UserIDString), type));
                    return;
                }

                bool newState;
                string displayName = type;
                switch (type)
                {
                    case "basic":
                        newState = !data.playerData[player.userID].playerPreferences.basicRocket;
                        data.playerData[player.userID].playerPreferences.basicRocket = newState;
                        break;
                    case "hv":
                        newState = !data.playerData[player.userID].playerPreferences.hvRocket;
                        data.playerData[player.userID].playerPreferences.hvRocket = newState;
                        break;
                    case "fire":
                        newState = !data.playerData[player.userID].playerPreferences.fireRocket;
                        data.playerData[player.userID].playerPreferences.fireRocket = newState;
                        displayName = "incendiary";
                        break;
                    case "smoke":
                        newState = !data.playerData[player.userID].playerPreferences.smokeRocket;
                        data.playerData[player.userID].playerPreferences.smokeRocket = newState;
                        break;
                    default:
                        PrintToChat(player, lang.GetMessage("InvalidTypeToggle", this, player.UserIDString));
                        return;
                }

                PrintToChat(player, string.Format(lang.GetMessage("TypeToggled", this, player.UserIDString), newState ? "enabled" : "disabled", displayName));
                data.Save();
            }
        }

        #endregion

        #region Helpers

        private void InitializePlayerData(ulong userID)
        {
            data.playerData.Add(userID, new TheDoorKnockerData
            {
                lastSeen = DateTime.UtcNow,
                playerPreferences = new TheDoorKnockerPlayerPreferences
                {
                    basicRocket = true,
                    hvRocket = true,
                    fireRocket = false,
                    smokeRocket = false
                },
                playerRockets = config.defaultPlayerData.amount,
                rocketsEnabled = config.defaultPlayerData.enabled
            });
            data.Save();
        }

        private int GetMaxRockets(BasePlayer player)
        {
            int max = config.defaultPlayerData.amount;
            foreach (var kvp in config.maxRocketPermission)
            {
                if (permission.UserHasPermission(player.UserIDString, kvp.Key))
                {
                    max = Math.Max(max, kvp.Value);
                }
            }
            return max;
        }

        private void SpawnRockets(BasePlayer player, int amount, int type)
        {
            if (amount <= 1) return;

            Item item = player.GetActiveItem();
            if (item?.info?.shortname != "rocket.launcher" || item.condition <= 0) return;

            string rocketPrefab;
            int rocketId;
            float velocity;

            switch (type)
            {
                case 1:
                    rocketPrefab = "assets/prefabs/ammo/rocket/rocket_basic.prefab";
                    rocketId = -742865266;
                    velocity = config.rocketSpeeds.basicVelocity;
                    break;
                case 2:
                    rocketPrefab = "assets/prefabs/ammo/rocket/rocket_hv.prefab";
                    rocketId = -1841918730;
                    velocity = config.rocketSpeeds.hvVelocity;
                    break;
                case 3:
                    rocketPrefab = "assets/prefabs/ammo/rocket/rocket_fire.prefab";
                    rocketId = 1638322904;
                    velocity = config.rocketSpeeds.fireVelocity;
                    break;
                case 4:
                    rocketPrefab = "assets/prefabs/ammo/rocket/rocket_smoke.prefab";
                    rocketId = -17123659;
                    velocity = config.rocketSpeeds.smokeVelocity;
                    break;
                default:
                    return;
            }

            for (int i = 0; i < amount - 1; i++)
            {
                if (config.takeDurability)
                {
                    item.LoseCondition(config.durabilityAmount);
                    if (item.condition <= 0) return;
                }

                Vector3 aimDirection = Quaternion.Euler(player.serverInput.current.aimAngles) * Vector3.forward;
                aimDirection = Quaternion.Euler(
                    UnityEngine.Random.Range(-config.aimCone, config.aimCone),
                    UnityEngine.Random.Range(-config.aimCone, config.aimCone),
                    0) * aimDirection;

                Quaternion rocketRotation = Quaternion.Euler(player.serverInput.current.aimAngles);

                TimedExplosive rocket = GameManager.server.CreateEntity(rocketPrefab, player.eyes.position + aimDirection * 1.5f, rocketRotation) as TimedExplosive;
                if (rocket == null) continue;

                rocket.creatorEntity = player;
                ServerProjectile rocketProjectile = rocket.GetComponent<ServerProjectile>();
                if (rocketProjectile != null)
                {
                    rocketProjectile.InitializeVelocity(aimDirection * velocity);
                }

                rocket.Spawn();
            }
        }

        #endregion

        #region Configuration

        private static ConfigData config;

        private class ConfigData
        {
            [JsonProperty(PropertyName = "Permissions and allowed max rockets per permission")]
            public Dictionary<string, int> maxRocketPermission { get; set; }

            [JsonProperty(PropertyName = "Chat command")]
            public string rocketamtcmd { get; set; }

            [JsonProperty(PropertyName = "Rocket spread (degrees)")]
            public float aimCone { get; set; }

            [JsonProperty(PropertyName = "Blocked rocket types")]
            public List<string> blockTypes { get; set; }

            [JsonProperty(PropertyName = "Default player data")]
            public TheDoorKnockerDefaultPlayerData defaultPlayerData { get; set; }

            [JsonProperty(PropertyName = "Clean up old player data")]
            public bool cleanOldData { get; set; }

            [JsonProperty(PropertyName = "Days before cleaning old data")]
            public double daysSinceLastSeenToClean { get; set; }

            [JsonProperty(PropertyName = "Take durability per extra rocket")]
            public bool takeDurability { get; set; }

            [JsonProperty(PropertyName = "Durability taken per rocket")]
            public int durabilityAmount { get; set; }

            [JsonProperty(PropertyName = "Wipe data on map wipe")]
            public bool wipeOnWipe { get; set; }

            [JsonProperty(PropertyName = "Custom rocket speeds")]
            public TheDoorKnockerRocketSpeeds rocketSpeeds { get; set; }
        }

        private ConfigData GetDefaultConfig()
        {
            return new ConfigData
            {
                maxRocketPermission = new Dictionary<string, int>
                {
                    {"thedoorknocker.basic", 2},
                    {"thedoorknocker.vip", 3},
                    {"thedoorknocker.example", 69}
                },
                rocketamtcmd = "tdk",
                aimCone = 4.0f,
                blockTypes = new List<string> { "smoke", "fire" },
                cleanOldData = true,
                daysSinceLastSeenToClean = 7,
                takeDurability = false,
                durabilityAmount = 1,
                wipeOnWipe = true,
                defaultPlayerData = new TheDoorKnockerDefaultPlayerData
                {
                    amount = 2,
                    enabled = true
                },
                rocketSpeeds = new TheDoorKnockerRocketSpeeds
                {
                    basicVelocity = 30,
                    fireVelocity = 30,
                    hvVelocity = 60,
                    smokeVelocity = 30
                }
            };
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<ConfigData>();
                if (config == null)
                {
                    LoadDefaultConfig();
                }
            }
            catch
            {
                PrintError("Configuration file is corrupt! Loading default config...");
                LoadDefaultConfig();
            }
            ValidateConfig();
            SaveConfig();
        }

        protected override void LoadDefaultConfig()
        {
            config = GetDefaultConfig();
        }

        protected override void SaveConfig()
        {
            Config.WriteObject(config);
        }

        private void ValidateConfig()
        {
            bool changed = false;

            if (config.maxRocketPermission == null)
            {
                config.maxRocketPermission = GetDefaultConfig().maxRocketPermission;
                changed = true;
            }

            if (string.IsNullOrEmpty(config.rocketamtcmd))
            {
                config.rocketamtcmd = "tdk";
                changed = true;
            }

            if (config.blockTypes == null)
            {
                config.blockTypes = GetDefaultConfig().blockTypes;
                changed = true;
            }

            if (config.defaultPlayerData == null)
            {
                config.defaultPlayerData = GetDefaultConfig().defaultPlayerData;
                changed = true;
            }

            if (config.rocketSpeeds == null)
            {
                config.rocketSpeeds = GetDefaultConfig().rocketSpeeds;
                changed = true;
            }

            // Add more validations if necessary

            if (changed)
            {
                PrintWarning("Invalid config values detected! Corrected and saving changes.");
                SaveConfig();
            }
        }

        public class TheDoorKnockerDefaultPlayerData
        {
            [JsonProperty(PropertyName = "Enable TDK by default")]
            public bool enabled { get; set; }
            [JsonProperty(PropertyName = "Default rocket amount")]
            public int amount { get; set; }
        }

        public class TheDoorKnockerRocketSpeeds
        {
            [JsonProperty(PropertyName = "Basic rocket speed")]
            public int basicVelocity { get; set; }
            [JsonProperty(PropertyName = "HV rocket speed")]
            public int hvVelocity { get; set; }
            [JsonProperty(PropertyName = "Smoke rocket speed")]
            public int smokeVelocity { get; set; }
            [JsonProperty(PropertyName = "Fire rocket speed")]
            public int fireVelocity { get; set; }
        }

        #endregion

        #region Data Handling

        class SavedData
        {
            [JsonProperty("Player data")]
            public Dictionary<ulong, TheDoorKnockerData> playerData = new Dictionary<ulong, TheDoorKnockerData>();

            public static SavedData Load() =>
                Interface.Oxide.DataFileSystem.ReadObject<SavedData>("TheDoorKnocker/TDK_playerData") ?? new SavedData();

            public void Save() =>
                Interface.Oxide.DataFileSystem.WriteObject("TheDoorKnocker/TDK_playerData", this);

            public void UpdateAmount(ulong userId, int rocketAmount)
            {
                if (playerData.ContainsKey(userId))
                {
                    playerData[userId].playerRockets = rocketAmount;
                    Save();
                }
            }

            public void UpdateEnabled(ulong userId, bool enabled)
            {
                if (playerData.ContainsKey(userId))
                {
                    playerData[userId].rocketsEnabled = enabled;
                    Save();
                }
            }
        }

        public class TheDoorKnockerData
        {
            [JsonProperty(PropertyName = "Rocket count")]
            public int playerRockets { get; set; }
            [JsonProperty(PropertyName = "Rockets enabled")]
            public bool rocketsEnabled { get; set; }
            [JsonProperty(PropertyName = "Last seen")]
            public DateTime lastSeen { get; set; }
            [JsonProperty(PropertyName = "Player preferences")]
            public TheDoorKnockerPlayerPreferences playerPreferences { get; set; }
        }

        public class TheDoorKnockerPlayerPreferences
        {
            public bool basicRocket { get; set; }
            public bool hvRocket { get; set; }
            public bool fireRocket { get; set; }
            public bool smokeRocket { get; set; }
        }

        #endregion

        #region Language

        Dictionary<string, string> _messages = new Dictionary<string, string>
        {
            { "NoPermission", "You lack <color=#FF0000>permission</color> to use this command." },
            { "TurnedOn", "You have <color=#00FBFF>enabled</color> multiple rockets per shot." },
            { "TurnedOff", "You have <color=#FF0000>disabled</color> multiple rockets per shot." },
            { "ChangeRockets", "Successfully changed rockets to <color=#0394fc>{0}</color>"},
            { "NoArgs", "Available arguments: <color=#03f8fc>true/false | # of rockets | toggle [basic/hv/fire/smoke]</color>"},
            { "InvalidRockets", "You lack permission to launch multiple rockets.\nContact an administrator if you believe this is an error."},
            { "TooMany", "You cannot set more than {0} rockets."},
            { "NoZero", "Disable TheDoorKnocker instead of setting rockets to 0."},
            { "InvalidTypeToggle", "Invalid type. Valid types: basic, hv, fire, smoke"},
            { "TypeDisabledTryToggle", "Cannot toggle {0} rockets as they are disabled."},
            { "TypeToggled", "You have {0} {1} rockets."}
        };

        #endregion
    }
}

TheDoorKnocker.cs

About Us

Codefling is the largest marketplace for plugins, maps, tools, and more, making it easy for customers to discover new content and for creators to monetize their work.

Downloads
2.4m
Total downloads
Customers
10.8k
Customers served
Files Sold
155.3k
Marketplace sales
Payments
3.3m
Processed total
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.