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

1.9m

Downloads

Total number of downloads.

8.9k

Customers

Total customers served.

131.4k

Files Sold

Total number of files sold.

2.7m

Payments Processed

Total payments processed.

×
×
  • 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.