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

FREE HeliFromHell : 1.5.3 1.5.3

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6

/*
 * https://github.com/DocValerian/rust-plugins
 * Copyright (C) 2022 DocValerian
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.* 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
 * GNU General Public License for more details.* 
 * You should have received a copy of the GNU General Public License
 * along with this program.If not, see <http://www.gnu.org/licenses/>.* 
 * Questions and (limited) Support can be found in our Discord: https://discord.gg/8tkBFRjg3W
 * 
 */
using Facepunch;
using System.Collections.Generic;
using System.Linq;
using System;
using System.Reflection;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust;
using System.Text;
using UnityEngine;
using Rust;
using Oxide.Game.Rust.Cui;
using Random = UnityEngine.Random;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEngine.SceneManagement;
namespace Oxide.Plugins {
    [Info("HeliFromHell", "DocValerian", "1.5.3")]
    class HeliFromHell : RustPlugin {
        static HeliFromHell Plugin;
        [PluginReference]
        Plugin ServerRewards, Clans, LootBoxSpawner, ZNui, ZNTitleManager, ZNExperience;
        private const string permUse = "helifromhell.use";
        private const string permConsole = "helifromhell.ticket";
        bool HasPermission(string id, string perm) => permission.UserHasPermission(id, perm);
#region Config
        protected override void LoadDefaultConfig() {
            Cfg = new ConfigFile();
            Puts("Loaded default configuration file");
        }
        protected override void SaveConfig() => Config.WriteObject(Cfg);
        protected override void LoadConfig() {
            base.LoadConfig();
            try {
                Cfg = Config.ReadObject<ConfigFile>();
            }
            catch (JsonException ex) {
                Puts(ex.Message);
                PrintError("Your configuration file contains a json error, shown above.Please fix this.");
                return;
            }
            catch (Exception ex) {
                Puts(ex.Message);
                LoadDefaultConfig();
            }
            if (Cfg == null) {
                Puts("Config is null");
                LoadDefaultConfig();
            }
            SaveConfig();
        }
        static ConfigFile Cfg = new ConfigFile();
        class ConfigFile {
            public int HeliSpawnRadius = 30;
            public int HeliQueueSeconds = 120;
            public float SoloDamageReduction = 0.2f;
            public float TeamHealthPercentPerPlayer = 0.2f;
            public float TeamRewartPercentPerPlayer = 0.05f;
            public Dictionary<string, Dictionary<string, float>> HeliLevels = new Dictionary<string, Dictionary<string, float>> {
                ["normal"]
                = new Dictionary<string, float> {
                    ["heliHealth"]
                    = 10000f, ["heliWeakspotHealthPercent"] = 40f, ["damageMultiplyer"] = 1.0f, ["rewardPoints"] = 500f, ["rewardPointsHighscore"] = 1000f, ["refundPrice"] = 0f, ["minRewardMultiplyer"] = 2f, ["maxRewardMultiplyer"] = 4f, ["experience"] = 500f,
                }
                , ["noloot_normal"] = new Dictionary<string, float> {
                    ["heliHealth"]
                    = 10000f, ["heliWeakspotHealthPercent"] = 40f, ["damageMultiplyer"] = 1.0f, ["rewardPoints"] = 500f, ["rewardPointsHighscore"] = 1000f, ["refundPrice"] = 0f, ["minRewardMultiplyer"] = 0f, ["maxRewardMultiplyer"] = 0f, ["experience"] = 500f,
                }
                , ["hardcore"] = new Dictionary<string, float> {
                    ["heliHealth"]
                    = 25000f, ["heliWeakspotHealthPercent"] = 40f, ["damageMultiplyer"] = 1.5f, ["rewardPoints"] = 1000f, ["rewardPointsHighscore"] = 1500f, ["refundPrice"] = 0f, ["minRewardMultiplyer"] = 5f, ["maxRewardMultiplyer"] = 14f, ["experience"] = 1000f,
                }
                , ["noloot_hardcore"] = new Dictionary<string, float> {
                    ["heliHealth"]
                    = 25000f, ["heliWeakspotHealthPercent"] = 40f, ["damageMultiplyer"] = 1.5f, ["rewardPoints"] = 1000f, ["rewardPointsHighscore"] = 1500f, ["refundPrice"] = 0f, ["minRewardMultiplyer"] = 0f, ["maxRewardMultiplyer"] = 0f, ["experience"] = 1000f,
                }
                , ["ultra"] = new Dictionary<string, float> {
                    ["heliHealth"]
                    = 50000f, ["heliWeakspotHealthPercent"] = 50f, ["damageMultiplyer"] = 2.0f, ["rewardPoints"] = 1500f, ["rewardPointsHighscore"] = 2000f, ["refundPrice"] = 0f, ["minRewardMultiplyer"] = 15f, ["maxRewardMultiplyer"] = 25f, ["experience"] = 2000f,
                }
                , ["helifromhell"] = new Dictionary<string, float> {
                    ["heliHealth"]
                    = 100000f, ["heliWeakspotHealthPercent"] = 50f, ["damageMultiplyer"] = 3.0f, ["rewardPoints"] = 2000f, ["rewardPointsHighscore"] = 2500f, ["refundPrice"] = 0f, ["minRewardMultiplyer"] = 30f, ["maxRewardMultiplyer"] = 50f, ["experience"] = 4000f,
                }
            }
            ;
            public Dictionary<string, Dictionary<string, string>> Titles = new Dictionary<string, Dictionary<string, string>>() {
                ["normal"]
                = new Dictionary<string, string>() {
                    ["m"]
                    = "HeliCrasher", ["f"] = "HeliCrasher", ["m_eternal"] = "HeliDestroyer", ["f_eternal"] = "HeliDestroyer",
                }
                , ["hardcore"] = new Dictionary<string, string>() {
                    ["m"]
                    = "HeliHunter", ["f"] = "HeliHuntress", ["m_eternal"] = "Master HeliHunter", ["f_eternal"] = "Master HeliHuntress",
                }
                , ["ultra"] = new Dictionary<string, string>() {
                    ["m"]
                    = "Ultra HeliHunter", ["f"] = "Ultra HeliHuntress", ["m_eternal"] = "UltraHeli Legend", ["f_eternal"] = "UltraHeli Legend",
                }
                , ["helifromhell"] = new Dictionary<string, string>() {
                    ["m"]
                    = "Heli Hellraiser", ["f"] = "Heli Hellraiser", ["m_eternal"] = "Lord of HeliHell", ["f_eternal"] = "Queen of HeliHell",
                }
            }
            ;
        }
#endregion
#region Data
        private BaseHelicopter currentHeli;
        private PatrolHelicopterAI currentHeliAI;
        private string currentHeliLevel;
        private BasePlayer currentHeliOwner;
        private HashSet<ulong> currentTeamMemberIDs = new HashSet<ulong>();
        private FieldInfo tooHotUntil = typeof(HelicopterDebris).GetField("tooHotUntil", (BindingFlags.Instance | BindingFlags.NonPublic));
        private DateTime currentHeliSpawnTime = DateTime.Now;
        private DateTime lastHeliKillTime = DateTime.Now;
        private DateTime lastHeliCallTime = DateTime.Now;
        private DateTime lastDamageTime = DateTime.Now;
        private List<string> teamSizeName = new List<string> {
            "none", "solo", "duo", "trio", "4P", "5P", "6P", "7P", "8P", "Zerg_9", "Zerg_10", "Zerg_11", "Zerg_12", "Zerg_13", "Zerg_14", "Zerg_15", "Zerg_16", "Zerg_17", "Zerg_18", "Zerg_19", "Full_20"
        }
        ;
        private Dictionary<ulong, float> currentDamage = new Dictionary<ulong, float>();
        private bool currentIsHighscore = false;
        private bool currentIsForceKill = false;
        private Timer heliRedirectionTimer;
        private Timer currentUITimer;
        private Dictionary<ulong, DateTime> lastPlayerHeli = new Dictionary<ulong, DateTime>();
        private string[] cooldownHelis = {
            "normal", "hardcore"
        }
        ;
        private string lastWinStat = "";
        private float lastWinTime = 0.0f;
        class StoredData {
            public List<ulong> HeliQueue = new List<ulong>();
            public Dictionary<ulong, string> TicketData = new Dictionary<ulong, string>();
        }
        class HighscoreData {
            public Dictionary<string, Dictionary<int, float>> HighscoreTimes = new Dictionary<string, Dictionary<int, float>>();
            public Dictionary<string, Dictionary<int, string>> HighscorePlayer = new Dictionary<string, Dictionary<int, string>>();
        }
        StoredData storedData;
        HighscoreData highscoreData;
        void SaveData() {
            Interface.Oxide.DataFileSystem.WriteObject("HeliFromHell", storedData);
            Interface.Oxide.DataFileSystem.WriteObject("HeliFromHell_Highscores", highscoreData);
        }
#endregion
        void Loaded() {
            Cfg = Config.ReadObject<ConfigFile>();
            Plugin = this;
            permission.RegisterPermission(permUse, this);
            permission.RegisterPermission(permConsole, this);
            storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>("HeliFromHell");
            highscoreData = Interface.Oxide.DataFileSystem.ReadObject<HighscoreData>("HeliFromHell_Highscores");
            SaveData();
        }
        private void OnServerInitialized() {
            initTitles();
        }
        private void Unload() {
            Unsubscribe(nameof(OnEntityKill));
            if (currentHeli != null) {
                currentIsForceKill = true;
                currentHeli.Kill();
            }
            SaveData();
            resetUI();
        }
        private void OnNewSave() {
            // reset highscore automatically on wipe
            // keep purchases (storedData) alive
            highscoreData = new HighscoreData();
            SaveData();
        }
#region Commands
        [ConsoleCommand("helifromhell.highscore")]
        private void CmdUIkill(ConsoleSystem.Arg arg) {
            if (arg.Player() != null) {
                CuiHelper.DestroyUi(arg.Player(), "HeliUI");
                displayHighscore(arg.Player(), arg.Args[0]);
            }
        }
        [ConsoleCommand("helifromhell.ticket")]
        private void CmdBuyHeliConsole(ConsoleSystem.Arg arg) {
            if (arg.Args == null || arg.Args.Length != 2) return;
            if (arg.Player() != null) {
                if (!HasPermission(arg.Player().UserIDString, permConsole)) {
                    PrintToConsole(arg.Player(), "No Permission");
                    return;
                }
            }
            Action<string> printToConsole;
            if (arg.Player() == null) {
                printToConsole = (str) => Puts(str);
            }
            else {
                printToConsole = (str) => PrintToConsole(arg.Player(), str);
            }
            if (!arg.Args[0].IsSteamId()) {
                printToConsole("InvalidSteamId " + arg.Args[0]);
                return;
            }
            var player = FindPlayer(ulong.Parse(arg.Args[0]));
            if (player == null) {
                printToConsole("Player Not Found");
                return;
            }
            string heliLevel = arg.Args[1];
            if (!Cfg.HeliLevels.ContainsKey(heliLevel)) {
                printToConsole("Invalid heli Level " + heliLevel);
                return;
            }
            if (heliLevel.Contains("solo") && !SoloCheckSuccess(player)) {
                refundTicket(player, heliLevel);
                printToConsole("Ticket was refunded!");
                return;
            }
            if (addToQueue(player, heliLevel)) {
                printToConsole("Added ticket for " + player + " at level " + heliLevel);
            }
            else {
                refundTicket(player, heliLevel);
                printToConsole("Player " + player + " already has a ticket!");
            }
        }
        private void showUsageMessage(BasePlayer player) {
            string msg = "<color=orange>============ Heli From Hell (v" + Plugin.Version + ") ============</color>";
            msg += "\n- The heli can be spawned everywhere.\n- It only attacks the caller(+team)\n- Only the caller(+team) can damage it!";
            msg += "\n- It can only be attacked in public space or an authed base!";
            msg += "\n- Auto-Surrender if not damaged! (120s + 2s per %damaged)";
            msg += "\n\n<color=green>Main commands:</color>";
            msg += "\n/heli info \t\t\tShow the heli queue and wait time";
            msg += "\n/heli levels \t\tShow heli levels info";
            msg += "\n/heli get <level> \t\tGet a heli Ticket (free)  \n\t\t\t\tcheck <color=orange>/heli levels</color>";
            msg += "\n\n/heli spawn \t\tSpawn your heli";
            msg += "\n\n<color=green>Other commands:</color>";
            msg += "\n/heli \t\t\t\tShow this info";
            msg += "\n/heli score \t\t\tOpen highscores";
            msg += "\n/heli last \t\t\tShow last fight report";
            msg += "\n/heli cancel \t\tRemove your heli ticket";
            msg += "\n/heli call \t\t\tForce heli to return (200s cooldown)";
            msg += "\n<color=green>/heli surrender</color> \t\tSend heli away";
            msg += "\n<color=green>/loot</color> \t\t\t\tAfter the round: \n\t\t\t\t - spawn crates with all your loot!";
            if (player.IsAdmin) {
                msg += "\n\n<color=red>=== Admin Commands</color>";
                msg += "\n/heli kill \t\t\tKill the heli";
                msg += "\n/heli kick <steamid> \tKick player from queue";
            }
            SendReply(player, msg);
        }
        private void showInfoMessage(BasePlayer player) {
            var secondsSinceLastKill = Math.Floor((DateTime.Now - lastHeliKillTime).TotalSeconds);
            string msg = "";
            if (currentHeli != null && currentHeliOwner != null) {
                var secondsFighting = Math.Floor((DateTime.Now - currentHeliSpawnTime).TotalSeconds);
                msg += "<color=green>" + currentHeliOwner.displayName + " is currently fighting a " + currentHeliLevel + " heli</color>";
                msg += "\nSeconds since spawn: \t\t\t" + secondsFighting;
                msg += "\nCurrent heli health (core): \t\t\t" + Math.Ceiling(currentHeli.health) + "/" + currentHeli._maxHealth;
                foreach (BaseHelicopter.weakspot weakspot in currentHeli.weakspots) {
                    msg += "\nWeakspot health: \t\t\t" + Math.Ceiling(weakspot.health) + "/" + weakspot.maxHealth;
                }
                msg += "\n\n";
            }
            msg += "Seconds since last heli kill: \t\t" + secondsSinceLastKill;
            msg += "\nSkip queue possible at: \t\t" + Cfg.HeliQueueSeconds;
            msg += "\n\n<color=orange>=============== Heli Queue ================</color>";
            if (storedData.HeliQueue.Count == 0) {
                msg += "\nNoone waiting to fight a heli!";
            }
            else {
                int i = 1;
                foreach (ulong ticket in storedData.HeliQueue) {
                    BasePlayer ticketPlayer = FindPlayer(ticket);
                    if (ticketPlayer != null) {
                        msg += "\n[" + i + "] <color=green>" + storedData.TicketData[ticket] + "</color>\t - " + ticketPlayer.displayName;
                        i++;
                    }
                }
            }
            SendReply(player, msg);
        }
        private void showLevelsMessage(BasePlayer player) {
            string msg = "<color=orange>============ Heli From Hell (v" + Plugin.Version + ") ============</color>";
            foreach (KeyValuePair<string, Dictionary<string, float>> level in Cfg.HeliLevels) {
                msg += "\n<color=green>" + level.Key + "</color>";
                msg += "\nHealth: \t\t" + level.Value["heliHealth"] + "<color=#999999> (+" + (Cfg.TeamHealthPercentPerPlayer * 100) + "% per player)</color>";
                msg += "\nDamage: \t\tx" + level.Value["damageMultiplyer"];
                msg += "\nRP: \t\t\t" + level.Value["rewardPoints"] + ", Highscore: +" + level.Value["rewardPointsHighscore"];
                msg += "\nBaseLoot: \t\t" + level.Value["minRewardMultiplyer"] + "-" + level.Value["maxRewardMultiplyer"] + "<color=#999999> (+" + (Cfg.TeamRewartPercentPerPlayer * 100) + "% per player)</color>";
            }
            SendReply(player, msg);
        }
        [ChatCommand("heli")]
        private void CmdHeliMain(BasePlayer player, string command, string[] args) {
            if (!HasPermission(player.UserIDString, permUse)) {
                SendReply(player, "You don't have permission to use this command");
                return;
            }
            if (args.Length == 0) {
                showUsageMessage(player);
                return;
            }
            if (args.Length == 1) {
                switch (args[0]) {
                    case "info" : showInfoMessage(player);
                    break;
                    case "cancel" : if (!storedData.TicketData.ContainsKey(player.userID)) {
                        SendReply(player, "You do not have a heli ticket, use <color=blue>/heli get...</color>");
                        break;
                    }
                    refundTicket(player, storedData.TicketData[player.userID]);
                    removeFromQueue(player);
                    SendReply(player, "Your heli ticket has been canceled!");
                    break;
                    case "surrender" : if (currentHeli != null && player == currentHeliOwner) {
                        surrenderEnemy();
                    }
                    break;
                    case "levels" : showLevelsMessage(player);
                    break;
                    case "call" : if (currentHeliOwner == player) {
                        forceHeliToPlayer(player);
                    }
                    else {
                        SendReply(player, "There is no heli you can call right now!");
                    }
                    break;
                    case "last" : SendReply(player, "Last Heli Fight:\n" + lastWinStat);
                    break;
                    case "spawn" :  // only one heli at a time
                    if (currentHeli != null) {
                        SendReply(player, "There is already a heli in the air, wait for your turn!");
                        return;
                    }
                    // check if player has permission
                    if (storedData.HeliQueue.Count == 0 || !storedData.TicketData.ContainsKey(player.userID)) {
                        SendReply(player, "You don't have a heli ticket, use <color=blue>/heli get...</color>");
                        break;
                    }
                    var secondsSinceLastKill = (DateTime.Now - lastHeliKillTime).TotalSeconds;
                    if (storedData.HeliQueue[0] != player.userID && secondsSinceLastKill < Cfg.HeliQueueSeconds && !player.IsAdmin) {
                        SendReply(player, "It's not your turn to call a heli.Check <color=blue>/heli info</color>");
                        break;
                    }
                    if (!TCAuthVerification(player)) {
                        SendReply(player, "Heli can only be spawned from a base you're authed on!");
                        break;
                    }
                    if (storedData.TicketData[player.userID].Contains("solo") && !SoloCheckSuccess(player)) {
                        break;
                    }
                    // re-position skipped player
                    if (storedData.HeliQueue[0] != player.userID && secondsSinceLastKill >= Cfg.HeliQueueSeconds && !player.IsAdmin) {
                        ulong firstSpot = storedData.HeliQueue[0];
                        removeFromQueue(firstSpot);
                        //storedData.HeliQueue.Remove(firstSpot);
                        //storedData.HeliQueue.Add(firstSpot);
                        //SaveData();
                    }
                    CallHeliForPlayer(player, storedData.TicketData[player.userID]);
                    break;
                    case "score" : displayHighscore(player, "normal");
                    break;
                    case "kill" : if (currentHeli != null && player.IsAdmin) {
                        refundTicket(currentHeliOwner, currentHeliLevel);
                        currentIsForceKill = true;
                        SendReply(currentHeliOwner, "Your heli has been sent away by ADMIN: <color=blue>" + player.displayName + "</color>\nTicket was refunded!");
                        SendReply(player, currentHeliOwner + " had their heli sent away, was refunded & informed!");
                        currentHeli.Kill();
                    }
                    break;
                    default : showUsageMessage(player);
                    break;
                }
            }
            if (args.Length == 2) {
                switch (args[0]) {
                    case "kick" : if (player.IsAdmin) {
                        if (!args[1].IsSteamId()) {
                            SendReply(player, "InvalidSteamId " + args[1]);
                            break;
                        }
                        BasePlayer targetPlayer = FindPlayer(ulong.Parse(args[1]));
                        if (targetPlayer == null || !storedData.HeliQueue.Contains(ulong.Parse(args[1]))) {
                            SendReply(player, "Player not Ffound (in queue");
                            break;
                        }
                        refundTicket(targetPlayer, storedData.TicketData[targetPlayer.userID]);
                        removeFromQueue(targetPlayer);
                        SendReply(targetPlayer, "You have been removed from the queue by ADMIN: <color=blue>" + player.displayName + "</color>\nTicket was refunded!");
                        SendReply(player, targetPlayer + " was kicked from queue, refunded, informed!");
                    }
                    break;
                    case "get" : int getCooldown = 10;
                    if (!Cfg.HeliLevels.ContainsKey(args[1])) {
                        SendReply(player, "You must use a valid level with get (normal, hardcore, ultra, hell)");
                        break;
                    }
                    if (cooldownHelis.Contains(args[1]) && lastPlayerHeli.ContainsKey(player.userID) && (int)Math.Floor((DateTime.Now - lastPlayerHeli[player.userID]).TotalMinutes) < getCooldown) {
                        SendReply(player, "You must wait " + (getCooldown - (int)Math.Floor((DateTime.Now - lastPlayerHeli[player.userID]).TotalMinutes)) + " more minutes to do another " + args[1] + " heli!\nYou can do 'noloot_...', 'ultra' and 'helifromhell' any time ");
                        break;
                    }
                    if (addToQueue(player, args[1])) {
                        SendReply(player, "Added /heli ticket at level " + args[1]);
                    }
                    break;
                    default : showUsageMessage(player);
                    break;
                }
            }
        }
#endregion
#region Hooks
        private void OnEntityKill(BaseEntity entity) {
            if (entity == currentHeli) {
                if (!currentIsForceKill) {
                    checkHighscore();
                    rewardTeam();
                    createRewardCrates(entity.transform.position);
                }
                cleanupAfterHeli();
            }
        }
        object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
            if (info == null) return null;
            if (currentHeli == null) return null;
            float damageScale = Cfg.HeliLevels[currentHeliLevel]["damageMultiplyer"];
            //solo player boost
            if (currentTeamMemberIDs.Count() == 1) damageScale -= 0.2f;
            if (entity == currentHeli || info?.Initiator == currentHeli) {
                BasePlayer player = info?.Initiator as BasePlayer;
                BaseHelicopter heli = info?.Initiator as BaseHelicopter;
                if (player != null) {
                    if (!HasSteaksInHeli((BaseEntity)player)) {
                        info.damageTypes.ScaleAll(0.0f);
                    }
                    if (!TCAuthVerification(player)) {
                        SendReply(player, "You can only attack Heli in a base you're authed on!");
                        info.damageTypes.ScaleAll(0.0f);
                    }
                    currentDamage[player.userID] += info.damageTypes.Total();
                    currentDamage[0] += info.damageTypes.Total();
                    lastDamageTime = DateTime.Now;
                    //Puts("DEBUG: damaging heli for "+ info.damageTypes.Total());
                }
                if (heli != null) {
                    //don't allow heli to damage innocents
                    if (!HasSteaksInHeli((BaseEntity)entity)) {
                        if (IsTCHacking((BaseEntity)entity)) {
                            info.damageTypes.ScaleAll(200000.0f);
                        }
                        else {
                            info.damageTypes.ScaleAll(0.0f);
                        }
                    }
                    //Puts("DEBUG: Heli is attacking " +entity+ " for "+ info.damageTypes.Total());
                }
            }
            //Puts("DEBUG: DAMAGE" + info.damageTypes.Total() + " --- " + info.WeaponPrefab + "..." + info.Initiator);
            // mitigate napalm/fire damage to bystanderes
            if (info.Initiator != null && (info.Initiator.name.Contains("napalm") || info.Initiator.name.Contains("oilfireball"))) {
                //Puts("DEBUG: heli fire? " + info.Initiator?.name);
                if (!HasSteaksInHeli((BaseEntity)entity)) {
                    info.damageTypes.ScaleAll(0.0f);
                }
                return null;
            }
            // mitigate rocket damage to bystanderes
            if (info.WeaponPrefab != null && info.WeaponPrefab.name.Contains("rocket_heli")) {
                if (!HasSteaksInHeli((BaseEntity)entity)) {
                    if (IsTCHacking((BaseEntity)entity)) {
                        info.damageTypes.ScaleAll(500.0f);
                    }
                    else {
                        //Puts("DEBUG: rocket hit innocent, no damage" + entity);
                        info.damageTypes.ScaleAll(0.0f);
                    }
                }
                else {
                    info.damageTypes.ScaleAll(damageScale);
                }
                //Puts("DEBUG: heli rocket?" + info.damageTypes.Total() + " --- " + info.WeaponPrefab + "..." + info.Initiator);
            }
            return null;
        }
        private object OnPlayerAttack(BasePlayer attacker, HitInfo info) {
            if (info == null || info.HitEntity == null) return null;
            if (info.HitEntity == currentHeli) {
                if (!HasSteaksInHeli(attacker)) {
                    SendReply(attacker, "You don't have permission to attack this heli!");
                    info.damageTypes.ScaleAll(0.0f);
                    return false;
                }
                if (!TCAuthVerification(attacker)) {
                    SendReply(attacker, "You can only attack Heli in a base you're authed on!");
                    info.damageTypes.ScaleAll(0.0f);
                    return false;
                }
            }
            return null;
        }
        private object CanHelicopterStrafeTarget(PatrolHelicopterAI heliAi, BasePlayer target) {
            if (heliAi != currentHeliAI) return null;
            return HasSteaksInHeli(target) ? null : (object)false;
        }
        private object CanHelicopterTarget(PatrolHelicopterAI heliAi, BasePlayer target) {
            if (heliAi != currentHeliAI) return null;
            return HasSteaksInHeli(target) ? null : (object)false;
        }
        private object OnHelicopterTarget(HelicopterTurret turret, BaseCombatEntity target) {
            if (turret?._heliAI != currentHeliAI) return null;
            return HasSteaksInHeli(target) ? null : (object)false;
        }
        // loot protection
        void OnEntitySpawned(BaseNetworkable entity) {
            //remove fire from heli (and possible heli), cause it is no use...if (entity.name.Contains("oilfireball") && !entity.IsDestroyed)
            {
                entity.Kill();
            }
            if (entity is BaseHelicopter && (currentHeli == null || currentHeli != entity)) {
                Puts("Killing public Heli with no owner");
                entity.Kill();
            }
            if (entity is HelicopterDebris) {
                var debris = entity as HelicopterDebris;
                if (debris == null) return;
                debris.Kill();
            }
        }
        private void OnPlayerDisconnected(BasePlayer player, string reason) {
            killUI(player);
            if (player && player == currentHeliOwner && currentHeli != null) {
                surrenderEnemy();
                Puts(player + " disconnected, active heli was surrendered");
            }
            if (player && storedData.TicketData.ContainsKey(player.userID)) {
                refundTicket(player, storedData.TicketData[player.userID]);
                removeFromQueue(player);
                Puts(player + " disconnected, heli ticket was removed");
            }
        }
        // napalm will be fired with 25% chance, only on unauthed TCs it is 100
        // make sure owner has TC, to prevent team-hacks
        private bool CanHelicopterUseNapalm(PatrolHelicopterAI heli) {
            return TCAuthVerification(currentHeliOwner);
        }
#endregion
#region HelperFunctions
        private void initTitles() {
            foreach (KeyValuePair<string, Dictionary<string, string>> d in Cfg.Titles) {
                ZNTitleManager?.Call("UpsertTitle", getTitleID(d.Key), "Heli '" + d.Key + "'", "Seconds", d.Value["m_eternal"], d.Value["f_eternal"], d.Value["m"], d.Value["f"]);
            }
        }
        private string getTitleID(string difficulty) {
            int index = difficulty.IndexOf("_");
            difficulty = (index > 0) ? difficulty.Substring(index + 1) : difficulty;
            return Plugin.Name + "_" + difficulty;
        }
        private void surrenderEnemy(bool force = false) {
            if (currentHeli != null) {
                if (!force && currentHeli.health == currentHeli.MaxHealth()) {
                    SendReply(currentHeliOwner, "You can't surrender an undamaged Heli!");
                    return;
                }
                currentIsForceKill = true;
                SendReply(currentHeliOwner, "Your heli has been sent away.");
                currentHeli.Kill();
            }
        }
        private void createRewardCrates(Vector3 targetPos) {
            if (LootBoxSpawner == null) {
                Puts("ERROR: LootBoxSpawner not loaded!");
                return;
            }
            else {
                int minRewardMultiplyer = (int)Math.Ceiling(Cfg.HeliLevels[currentHeliLevel]["minRewardMultiplyer"]);
                minRewardMultiplyer += (int)Math.Floor((currentTeamMemberIDs.Count - 1) * Cfg.TeamRewartPercentPerPlayer * minRewardMultiplyer);
                int maxRewardMultiplyer = (int)Math.Ceiling(Cfg.HeliLevels[currentHeliLevel]["maxRewardMultiplyer"]);
                maxRewardMultiplyer += (int)Math.Floor((currentTeamMemberIDs.Count - 1) * Cfg.TeamRewartPercentPerPlayer * maxRewardMultiplyer);
                string msg;
                if (maxRewardMultiplyer == 0) {
                    msg = "You finished a 'noloot' variant, there is only an RP reward.";
                }
                else {
                    msg = "Use <color=green>/loot</color> to get your reward.";
                    LootBoxSpawner.Call("storeRewardClaim", currentHeliOwner.userID, currentHeliLevel, minRewardMultiplyer, maxRewardMultiplyer, "heli");
                }
                SendReply(currentHeliOwner, msg);
            }
        }
        private BasePlayer FindPlayer(ulong userID) {
            BasePlayer player = BasePlayer.FindByID(userID);
            if (player == null) {
                player = BasePlayer.FindSleeping(userID);
            }
            return player;
        }
        private void adjustHeliPower(BaseHelicopter heli) {
            string heliLevel = currentHeliLevel;
            float damageScale = Cfg.HeliLevels[currentHeliLevel]["damageMultiplyer"];
            //solo player boost
            if (currentTeamMemberIDs.Count() == 1) damageScale -= 0.2f;
            int currentTeamSize = currentTeamMemberIDs.Count();
            float heliHealth = Cfg.HeliLevels[heliLevel]["heliHealth"];
            heliHealth += (float)(heliHealth * 0.2f * (currentTeamSize - 1f));
            heli._maxHealth = heliHealth;
            heli.health = heliHealth;
            heli.maxCratesToSpawn = 0;
            heli.bulletDamage *= damageScale;
            foreach (BaseHelicopter.weakspot weakspot in heli.weakspots) {
                float weakhealth = (heliHealth / 100) * Cfg.HeliLevels[heliLevel]["heliWeakspotHealthPercent"];
                weakspot.maxHealth = weakhealth;
                weakspot.health = weakhealth;
            }
        }
        private Vector3 getRandomSpawn(BasePlayer player) {
            Vector3 playerPos = player.transform.position;
            int range = Cfg.HeliSpawnRadius;
            float spawnX = Random.Range(-range, range);
            spawnX = (spawnX < 0) ? spawnX - range : spawnX + range;
            float spawnZ = Random.Range(-range, range);
            spawnZ = (spawnZ < 0) ? spawnZ - range : spawnZ + range;
            return playerPos + new Vector3(spawnX, 40, spawnZ);
        }
        private static BaseHelicopter InstantiateEntity(Vector3 position) {
            var prefabName = "assets/prefabs/npc/patrol helicopter/patrolhelicopter.prefab";
            var prefab = GameManager.server.FindPrefab(prefabName);
            var go = Facepunch.Instantiate.GameObject(prefab, position, default(Quaternion));
            go.name = prefabName;
            SceneManager.MoveGameObjectToScene(go, Rust.Server.EntityScene);
            if (go.GetComponent<Spawnable>()) {
                UnityEngine.Object.Destroy(go.GetComponent<Spawnable>());
            }
            if (!go.activeSelf) {
                go.SetActive(true);
            }
            return go.GetComponent<BaseHelicopter>();
        }
        private bool CallHeliForPlayer(BasePlayer player, string heliLevel = "normal") {
            var heliPos = getRandomSpawn(player);
            //currentHeli = GameManager.server.CreateEntity("assets/prefabs/npc/patrol helicopter/patrolhelicopter.prefab", new Vector3(), new Quaternion(), true) as BaseHelicopter;
            currentHeli = InstantiateEntity(heliPos);
            if (!currentHeli) return false;
            currentHeliAI = currentHeli.GetComponent<PatrolHelicopterAI>();
            currentHeliOwner = player;
            currentHeli.Spawn();
            currentHeli.transform.position = heliPos;
            currentHeliSpawnTime = DateTime.Now;
            if (cooldownHelis.Contains(heliLevel)) lastPlayerHeli[player.userID] = DateTime.Now;
            currentHeliLevel = heliLevel;
            currentDamage.Add(0, 0f);
            // total damage counter
            lastDamageTime = DateTime.Now;
            lastHeliCallTime = DateTime.Now;
            // team related additions
            if (currentHeliOwner.currentTeam != 0UL) {
                RelationshipManager.PlayerTeam theTeam = RelationshipManager.ServerInstance.FindTeam(player.currentTeam);
                foreach (var member in theTeam.members) {
                    BasePlayer memberPlayer = BasePlayer.Find("" + member);
                    if (memberPlayer != null) currentTeamMemberIDs.Add(member);
                    currentDamage.Add(member, 0f);
                    currentHeliAI._targetList.Add(new PatrolHelicopterAI.targetinfo((BaseEntity)memberPlayer, memberPlayer));
                }
            }
            else {
                currentTeamMemberIDs.Add(player.userID);
                currentDamage.Add(player.userID, 0f);
                currentHeliAI._targetList.Add(new PatrolHelicopterAI.targetinfo((BaseEntity)player, player));
            }
            adjustHeliPower(currentHeli);
            // make sure we always focus on the calling player and never go patrolling.currentHeliAI.SetTargetDestination(currentHeliOwner.transform.position);
            removeFromQueue(player);
            SetupGameTimer();
            foreach (var p in BasePlayer.activePlayerList) {
                SendReply(p, "Personal <color=#63ff64>" + heliLevel + "</color> helicopter was spawned for <color=#63ff64>" + player.displayName + " </color>.\nIt will not damage bystanders.");
            }
            ZNui?.Call("ToggleEvent", "heliEvent", true);
            return true;
        }
        private void SetupGameTimer() {
            heliRedirectionTimer = timer.Every(15f, () => {
                //Puts("DEBUG: Timer run " + currentHeliAI._targetList.Count());
                currentHeliAI._targetList.Add(new PatrolHelicopterAI.targetinfo((BaseEntity)currentHeliOwner, currentHeliOwner));
            }
            );
            currentUITimer = timer.Every(1f, () => {
                if (UiPlayers.Count > 0) {
                    foreach (BasePlayer p in UiPlayers) {
                        reloadUI(p);
                    }
                }
                else {
                    foreach (ulong pID in currentTeamMemberIDs) {
                        reloadUI(FindPlayer(pID));
                    }
                }
                if (!currentHeliOwner.IsConnected || (DateTime.Now - lastDamageTime).TotalSeconds > getNoDamageSurrenderTime()) {
                    surrenderEnemy(true);
                }
            }
            );
        }
        private int getNoDamageSurrenderTime() {
            float health = currentHeli.health;
            float maxHealth = currentHeli._maxHealth;
            foreach (BaseHelicopter.weakspot weakspot in currentHeli.weakspots) {
                health += weakspot.health;
                maxHealth += weakspot.maxHealth;
            }
            int healthPercent = (int)Math.Ceiling((health / maxHealth) * 100);
            return 120 + ((100 - healthPercent) * 2);
        }
        private void forceHeliToPlayer(BasePlayer player) {
            if (currentHeli == null) return;
            int MaxHeliDistanceToPlayer = 200;
            currentHeliAI._targetList.Clear();
            currentHeliAI._targetList.Add(new PatrolHelicopterAI.targetinfo(player, player));
            float heliDistance = Vector3Ex.Distance2D(currentHeli.transform.position, player.transform.position);
            if (heliDistance > MaxHeliDistanceToPlayer) {
                if (currentHeliAI._currentState != PatrolHelicopterAI.aiState.MOVE || Vector3Ex.Distance2D(currentHeliAI.destination, player.transform.position) > MaxHeliDistanceToPlayer) {
                    currentHeliAI.ExitCurrentState();
                    var heliTarget = player.transform.position.XZ() + Vector3.up * 250;
                    RaycastHit hit;
                    if (Physics.SphereCast(player.transform.position.XZ() + Vector3.up * 600, 50, Vector3.down, out hit, 1500, Layers.Solid)) {
                        heliTarget = hit.point + Vector3.up * 20;
                    }
                    Puts($"Forcing helicopter {currentHeli.transform.position} to player {player.displayName}, pos {heliTarget}");
                    currentHeliAI.State_Move_Enter(heliTarget);
                    currentHeli.transform.position = heliTarget;
                    lastHeliCallTime = DateTime.Now;
                }
                SendReply(player, "Heli was called to you!");
            }
            else {
                SendReply(player, "Heli is still to close to be called.(" + heliDistance + "m, needs " + MaxHeliDistanceToPlayer + "m)");
            }
        }
        private void notifyNextPlayer() {
            if (storedData.HeliQueue.Count > 0) {
                ulong nextTicket = storedData.HeliQueue[0];
                BasePlayer nextPlayer = FindPlayer(nextTicket);
                if (nextPlayer != null) {
                    SendReply(nextPlayer, "<color=green>Your heli</color> can now be called!\nUse <color=blue>/heli spawn</color> now.");
                }
                return;
            }
        }
        private void cleanupAfterHeli() {
            currentUITimer?.Destroy();
            resetUI();
            heliRedirectionTimer.Destroy();
            currentHeli = (BaseHelicopter)null;
            currentHeliOwner = (BasePlayer)null;
            currentHeliAI = (PatrolHelicopterAI)null;
            currentHeliLevel = string.Empty;
            currentHeliSpawnTime = DateTime.Now;
            currentTeamMemberIDs.Clear();
            currentDamage = new Dictionary<ulong, float>();
            lastHeliKillTime = DateTime.Now;
            lastHeliCallTime = DateTime.Now;
            currentIsHighscore = false;
            currentIsForceKill = false;
            notifyNextPlayer();
            ZNui?.Call("ToggleEvent", "heliEvent", false);
        }
        private bool TCAuthVerification(BasePlayer player) {
            BuildingPrivlidge privilege = player.GetBuildingPrivilege();
            if (!privilege) return false;
            if (!privilege.IsAuthed(player)) {
                return false;
            }
            return true;
        }
        private bool SoloCheckSuccess(BasePlayer player) {
            if (!IsSoloPlayer(player)) {
                SendReply(player, "You can't have a team or clan of more than 3 for this!");
                return false;
            }
            return true;
        }
        private bool IsSoloPlayer(BasePlayer player) {
            if (player.currentTeam != 0UL) return false;
            if (Clans != null) {
                string clanTag = Clans?.Call<string>("GetClanOf", player.userID);
                if (!String.IsNullOrEmpty(clanTag)) {
                    object clan = Clans?.Call<JObject>("GetClan", clanTag);
                    if (clan != null && clan is JObject) {
                        JToken members = (clan as JObject).GetValue("members");
                        if (members != null && members is JArray) {
                            if (members.Count() > 3) return false;
                        }
                    }
                }
            }
            return true;
        }
        private bool IsTCHacking(BaseEntity entity) {
            if (!(entity is BuildingBlock)) {
                return false;
            }
            // public safety
            if (currentHeliOwner == null || currentHeli == null) {
                return false;
            }
            var building = BuildingManager.server.GetBuilding(((DecayEntity)entity).buildingID);
            var tc = building?.GetDominatingBuildingPrivilege();
            if (tc == null) {
                // a building block without TC is hit - exploit!
                return true;
            }
            return false;
        }
        private bool HasSteaksInHeli(BaseEntity entity) {
            //return false;
            if (!(entity is BasePlayer) && !(entity is DecayEntity)) {
                return false;
            }
            // public safety
            if (currentHeliOwner == null || currentHeli == null) {
                return false;
            }
            if (entity is BasePlayer) {
                // owner can attack / be attacked
                if (entity == currentHeliOwner) {
                    return true;
                }
                if (currentTeamMemberIDs.Contains(((BasePlayer)entity).userID)) {
                    return true;
                }
            }
            // allow damage to player and team entities
            if (entity is DecayEntity) {
                if (entity.OwnerID == currentHeliOwner.userID) {
                    return true;
                }
                if (currentTeamMemberIDs.Contains(entity.OwnerID)) {
                    return true;
                }
                // allow damage to entities in a TC-range that the team is authed on
                var building = BuildingManager.server.GetBuilding(((DecayEntity)entity).buildingID);
                var tc = building?.GetDominatingBuildingPrivilege();
                if (tc != null) {
                    foreach (var entry in tc.authorizedPlayers) {
                        if (entry.userid == currentHeliOwner.userID) {
                            return true;
                        }
                        if (currentTeamMemberIDs.Contains(entry.userid)) {
                            return true;
                        }
                    }
                }
            }
            return false;
        }
        private bool addToQueue(BasePlayer player, string level) {
            // only allow a new ticket if there is not already one
            if (!storedData.HeliQueue.Contains(player.userID)) {
                storedData.HeliQueue.Add(player.userID);
                storedData.TicketData.Add(player.userID, level);
                SaveData();
                return true;
            }
            else {
                SendReply(player, "You can only have one heli ticket at a time.");
                return false;
            }
        }
        private void removeFromQueue(BasePlayer player) {
            storedData.HeliQueue.Remove(player.userID);
            storedData.TicketData.Remove(player.userID);
            SaveData();
        }
        private void removeFromQueue(ulong playerId) {
            storedData.HeliQueue.Remove(playerId);
            storedData.TicketData.Remove(playerId);
            SaveData();
        }
        private void refundTicket(BasePlayer player, string heliLevel) {
            if (!ServerRewards) return;
            ServerRewards?.Call("AddPoints", player.userID, (int)Cfg.HeliLevels[heliLevel]["refundPrice"]);
            SendReply(player, "Heli ticket price refunded.");
        }
        private void refundSurrender(BasePlayer player, string heliLevel) {
            if (!ServerRewards) return;
            ServerRewards?.Call("AddPoints", player.userID, (int)(Math.Ceiling(Cfg.HeliLevels[heliLevel]["refundPrice"] / 2)));
            SendReply(player, "50% of heli price refunded for surrender.");
        }
        private void rewardTeam() {
            if (currentDamage.Count == 0 || currentDamage[0] <= 0 || currentHeliLevel == null) return;
            string msg = "<color=orange>You took down your Heli!</
// ... [Code preview truncated due to length. Full source in attached file] ...

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