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

FREE BradleyFromHell : 1.6.1 1.6.1

Нет прав для скачивания
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
 * 
 */
// Requires: PathFinding
using System.Collections.Generic;
using System.Linq;
using System;
using System.Reflection;
using Oxide.Core;
using Oxide.Core.Plugins;
using UnityEngine;
using UnityEngine.AI;
using Oxide.Game.Rust.Cui;
using Random = UnityEngine.Random;
using UnityEngine.SceneManagement;
using Newtonsoft.Json;
namespace Oxide.Plugins {
    [Info("BradleyFromHell", "DocValerian", "1.6.1")]
    class BradleyFromHell : RustPlugin {
        static BradleyFromHell Plugin {
            get;
            set;
        }
        [PluginReference]
        Plugin ServerRewards, PathFinding, Clans, LootBoxSpawner, ZNui, ZNTitleManager, ZNExperience;
        private const string permUse = "bradleyfromhell.use";
        private const string permConsole = "bradleyfromhell.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 BradleySpawnRadius = 30;
            public int BradleyQueueSeconds = 120;
            public float SoloDamageReduction = 0.2f;
            public float TeamHealthPercentPerPlayer = 0.2f;
            public float TeamRewartPercentPerPlayer = 0.05f;
            public Dictionary<string, Dictionary<string, float>> BradleyLevels = new Dictionary<string, Dictionary<string, float>> {
                ["normal"]
                = new Dictionary<string, float> {
                    ["bradleyHealth"]
                    = 1500f, ["damageMultiplyer"] = 1.0f, ["rewardPoints"] = 500f, ["rewardPointsHighscore"] = 1000f, ["refundPrice"] = 0f, ["minRewardMultiplyer"] = 2f, ["maxRewardMultiplyer"] = 5f, ["experience"] = 500f,
                }
                , ["noloot_normal"] = new Dictionary<string, float> {
                    ["bradleyHealth"]
                    = 1500f, ["damageMultiplyer"] = 1.0f, ["rewardPoints"] = 500f, ["rewardPointsHighscore"] = 1000f, ["refundPrice"] = 0f, ["minRewardMultiplyer"] = 0f, ["maxRewardMultiplyer"] = 0f, ["experience"] = 500f,
                }
                , ["hardcore"] = new Dictionary<string, float> {
                    ["bradleyHealth"]
                    = 5000f, ["damageMultiplyer"] = 1.8f, ["rewardPoints"] = 1000f, ["rewardPointsHighscore"] = 1500f, ["refundPrice"] = 0f, ["minRewardMultiplyer"] = 6f, ["maxRewardMultiplyer"] = 15f, ["experience"] = 1000f,
                }
                , ["ultra"] = new Dictionary<string, float> {
                    ["bradleyHealth"]
                    = 10000f, ["damageMultiplyer"] = 2.2f, ["rewardPoints"] = 1500f, ["rewardPointsHighscore"] = 2000f, ["refundPrice"] = 0f, ["minRewardMultiplyer"] = 16f, ["maxRewardMultiplyer"] = 25f, ["experience"] = 2000f,
                }
                , ["bradleyfromhell"] = new Dictionary<string, float> {
                    ["bradleyHealth"]
                    = 25000f, ["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"]
                    = "TankBuster", ["f"] = "TankBuster", ["m_eternal"] = "TankDestroyer", ["f_eternal"] = "TankDestroyer",
                }
                , ["hardcore"] = new Dictionary<string, string>() {
                    ["m"]
                    = "TankHunter", ["f"] = "TankHuntress", ["m_eternal"] = "Master TankHunter", ["f_eternal"] = "Master TankHuntress",
                }
                , ["ultra"] = new Dictionary<string, string>() {
                    ["m"]
                    = "Ultra TankHunter", ["f"] = "Ultra TankHuntress", ["m_eternal"] = "UltraBrad Legend", ["f_eternal"] = "UltraBrad Legend",
                }
                , ["bradleyfromhell"] = new Dictionary<string, string>() {
                    ["m"]
                    = "Tank Hellraiser", ["f"] = "Tank Hellraiser", ["m_eternal"] = "God of Tanks", ["f_eternal"] = "Goddess of Tanks",
                }
            }
            ;
        }
#endregion
#region Data
        private BradleyAPC currentBradley;
        private string currentBradleyLevel;
        private BasePlayer currentBradleyOwner;
        private HashSet<ulong> currentTeamMemberIDs = new HashSet<ulong>();
        private DateTime currentBradleySpawnTime = DateTime.Now;
        private DateTime lastBradleyKillTime = 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 bradleyRedirectionTimer;
        private Timer bradleyFireTimer;
        private Timer currentUITimer;
        public static int blockLayer;
        private Dictionary<ulong, DateTime> lastPlayerBradley = new Dictionary<ulong, DateTime>();
        private string[] cooldownBrads = {
            "normal", "hardcore"
        }
        ;
        private string lastWinStat = "";
        private float lastWinTime = 0.0f;
        class StoredData {
            public List<ulong> BradleyQueue = 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("BradleyFromHell", storedData);
            Interface.Oxide.DataFileSystem.WriteObject("BradleyFromHell_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>("BradleyFromHell");
            highscoreData = Interface.Oxide.DataFileSystem.ReadObject<HighscoreData>("BradleyFromHell_Highscores");
            SaveData();
        }
        private void Unload() {
            Unsubscribe(nameof(OnEntityKill));
            if (currentBradley != null) {
                currentIsForceKill = true;
                currentBradley.Kill();
            }
            SaveData();
            resetUI();
        }
        private void OnNewSave() {
            // reset highscore automatically on wipe
            // keep purchases (storedData) alive
            highscoreData = new HighscoreData();
            SaveData();
        }
        private void OnServerInitialized() {
            blockLayer = LayerMask.GetMask("World", "Construction", "Tree", "Deployed", "Default");
            initTitles();
        }
#region Commands
        [ConsoleCommand("bradleyfromhell.highscore")]
        private void CmdUIkill(ConsoleSystem.Arg arg) {
            if (arg.Player() != null) {
                CuiHelper.DestroyUi(arg.Player(), "BradleyUI");
                displayHighscore(arg.Player(), arg.Args[0]);
            }
        }
        [ConsoleCommand("bradleyfromhell.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 bradleyLevel = arg.Args[1];
            if (!Cfg.BradleyLevels.ContainsKey(bradleyLevel)) {
                printToConsole("Invalid bradley Level " + bradleyLevel);
                return;
            }
            if (addToQueue(player, bradleyLevel)) {
                printToConsole("Added ticket for " + player + " at level " + bradleyLevel);
            }
            else {
                printToConsole("Player " + player + " already has a ticket!");
            }
        }
        private void showUsageMessage(BasePlayer player) {
            string msg = "<color=orange>============ Bradley From Hell (v" + Plugin.Version + ") ============</color>";
            msg += "\n- The Tank 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 an authed base!";
            msg += "\n- Auto-Surrender if not damaged! (120s + 2s per %damaged)";
            msg += "\n\n<color=green>Main commands:</color>";
            msg += "\n/brad info \t\t\tShow the Bradley queue and wait time";
            msg += "\n/brad levels \t\tShow brad levels info";
            msg += "\n/brad get <level> \tGet a Bradley Ticket (free)  \n\t\t\t\tcheck <color=orange>/brad levels</color>";
            msg += "\n/brad spawn \t\tSpawn your Bradley";
            msg += "\n\n<color=green>Other commands:</color>";
            msg += "\n/brad \t\t\tShow this info";
            msg += "\n/brad score \t\tOpen highscores";
            msg += "\n/brad last \t\t\tShow last fight report";
            msg += "\n/brad cancel \t\tRemove your Bradley ticket";
            msg += "\n<color=green>/brad surrender</color> \t\tSend Bradley 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/brad kill \t\t\tKill the Bradley";
                msg += "\n/brad kick <steamid> \tKick player from queue";
            }
            SendReply(player, msg);
        }
        private void showInfoMessage(BasePlayer player) {
            var secondsSinceLastKill = Math.Floor((DateTime.Now - lastBradleyKillTime).TotalSeconds);
            string msg = "";
            if (currentBradley != null && currentBradleyOwner != null) {
                var secondsFighting = Math.Floor((DateTime.Now - currentBradleySpawnTime).TotalSeconds);
                msg += "<color=green>" + currentBradleyOwner.displayName + " is currently fighting a " + currentBradleyLevel + " Bradley</color>";
                msg += "\nSeconds since spawn: \t\t\t" + secondsFighting;
                msg += "\nCurrent Bradley health: \t\t" + Math.Ceiling(currentBradley.health) + "/" + currentBradley._maxHealth + "\n\n";
            }
            msg += "Seconds since last Bradley kill: \t" + secondsSinceLastKill;
            msg += "\nSkip queue possible at: \t\t" + Cfg.BradleyQueueSeconds;
            msg += "\n\n<color=orange>=============== Bradley Queue ================</color>";
            if (storedData.BradleyQueue.Count == 0) {
                msg += "\nNoone waiting to fight a Bradley!";
            }
            else {
                int i = 1;
                foreach (ulong ticket in storedData.BradleyQueue) {
                    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>============ Bradley From Hell (v" + Plugin.Version + ") ============</color>";
            foreach (KeyValuePair<string, Dictionary<string, float>> level in Cfg.BradleyLevels) {
                msg += "\n<color=green>" + level.Key + "</color>";
                msg += "\nHealth: \t\t" + level.Value["bradleyHealth"] + "<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("brad")]
        private void CmdBradleyMain(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 "levels" : showLevelsMessage(player);
                    break;
                    case "cancel" : if (!storedData.TicketData.ContainsKey(player.userID)) {
                        SendReply(player, "You do not have a bradley ticket, use <color=blue>/brad get...</color>");
                        break;
                    }
                    removeFromQueue(player);
                    SendReply(player, "Your Bradley ticket has been canceled!");
                    break;
                    case "surrender" : if (currentBradley != null && player == currentBradleyOwner) {
                        if (currentBradley.health == currentBradley.MaxHealth()) {
                            SendReply(currentBradleyOwner, "You can't surrender an undamaged Bradley!");
                            return;
                        }
                        currentIsForceKill = true;
                        SendReply(currentBradleyOwner, "Your Bradley has been sent away!");
                        currentBradley.Kill();
                    }
                    break;
                    case "last" : SendReply(player, "Last Brad Fight:\n" + lastWinStat);
                    break;
                    case "spawn" :  // only one bradley at a time
                    if (currentBradley != null) {
                        SendReply(player, "There is already a Bradley in the air, wait for your turn!");
                        return;
                    }
                    // check if player has permission
                    if (storedData.BradleyQueue.Count == 0 || !storedData.TicketData.ContainsKey(player.userID)) {
                        SendReply(player, "You don't have a Bradley ticket, use <color=blue>/brad get...</color>");
                        break;
                    }
                    var secondsSinceLastKill = (DateTime.Now - lastBradleyKillTime).TotalSeconds;
                    if (storedData.BradleyQueue[0] != player.userID && secondsSinceLastKill < Cfg.BradleyQueueSeconds && !player.IsAdmin) {
                        SendReply(player, "It's not your turn to call a Bradley.Check <color=blue>/brad info</color>");
                        break;
                    }
                    if (!TCAuthVerification(player)) {
                        SendReply(player, "Bradley can only be spawned from a base you're authed on!");
                        break;
                    }
                    // re-position skipped player
                    if (storedData.BradleyQueue[0] != player.userID && secondsSinceLastKill >= Cfg.BradleyQueueSeconds && !player.IsAdmin) {
                        ulong firstSpot = storedData.BradleyQueue[0];
                        removeFromQueue(firstSpot);
                        //storedData.BradleyQueue.Remove(firstSpot);
                        //storedData.BradleyQueue.Add(firstSpot);
                        //SaveData();
                    }
                    CallBradleyForPlayer(player, storedData.TicketData[player.userID]);
                    break;
                    case "score" : displayHighscore(player, "normal");
                    break;
                    case "kill" : if (currentBradley != null && player.IsAdmin) {
                        SendReply(currentBradleyOwner, "Your Bradley has been sent away by ADMIN: <color=blue>" + player.displayName + "</color>");
                        SendReply(player, currentBradleyOwner + " had their Bradley sent away, was informed!");
                        currentIsForceKill = true;
                        currentBradley.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.BradleyQueue.Contains(ulong.Parse(args[1]))) {
                            SendReply(player, "Player not Ffound (in queue");
                            break;
                        }
                        removeFromQueue(targetPlayer);
                        SendReply(targetPlayer, "You have been removed from the queue by ADMIN: <color=blue>" + player.displayName + "</color>");
                        SendReply(player, targetPlayer + " was kicked from queue, informed!");
                    }
                    break;
                    case "get" : int getCooldown = 10;
                    if (!Cfg.BradleyLevels.ContainsKey(args[1])) {
                        SendReply(player, "You must use a valid level with get (normal, hardcore, ultra, hell)");
                        break;
                    }
                    if (cooldownBrads.Contains(args[1]) && lastPlayerBradley.ContainsKey(player.userID) && (int)Math.Floor((DateTime.Now - lastPlayerBradley[player.userID]).TotalMinutes) < getCooldown) {
                        SendReply(player, "You must wait " + (getCooldown - (int)Math.Floor((DateTime.Now - lastPlayerBradley[player.userID]).TotalMinutes)) + " more minutes to do another " + args[1] + " Bradley!\nYou can do 'noloot_...', 'ultra' and 'bradleyfromhell' any time ");
                        break;
                    }
                    if (addToQueue(player, args[1])) {
                        SendReply(player, "Added /brad ticket at level " + args[1]);
                    }
                    break;
                    default : showUsageMessage(player);
                    break;
                }
            }
        }
#endregion
#region Hooks
        private object CanBuild(Planner planner, Construction entity, Construction.Target target) {
            if (currentBradley == null || planner == null || entity == null) {
                return null;
            }
            // check if we care about what we are trying to build
            string name = entity?.fullName ?? string.Empty;
            //Puts("can Build: " + name + " at " + planner.GetOwnerPlayer().transform.position);
            if (!name.Contains("foundation")) return null;
            float distance = Vector3Ex.Distance2D(currentBradley.transform.position, planner.GetOwnerPlayer().transform.position);
            if (distance <= 40f) {
                SendReply(planner.GetOwnerPlayer(), "You can't build new foundations so close to a Bradley");
                return false;
            }
            return null;
        }
        private void OnEntityKill(BaseEntity entity) {
            if (entity == currentBradley) {
                if (!currentIsForceKill) {
                    checkHighscore();
                    rewardTeam();
                    createRewardCrates(entity.transform.position);
                }
                cleanupAfterBradley();
            }
        }
        object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
            if (info == null) return null;
            if (currentBradley == null) return null;
            float damageScale = Cfg.BradleyLevels[currentBradleyLevel]["damageMultiplyer"];
            //solo player boost
            if (currentTeamMemberIDs.Count() == 1) damageScale -= Cfg.SoloDamageReduction;
            if (entity == currentBradley || info?.Initiator == currentBradley) {
                BasePlayer player = info?.Initiator as BasePlayer;
                BradleyAPC bradley = info?.Initiator as BradleyAPC;
                if (player != null) {
                    if (!HasSteaksInBradley((BaseEntity)player)) {
                        info.damageTypes.ScaleAll(0.0f);
                    }
                    if (!TCAuthVerification(player)) {
                        SendReply(player, "You can only attack Bradley 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 bradley for "+ info.damageTypes.Total());
                }
                if (bradley != null) {
                    //don't allow bradley to damage innocents
                    if (!HasSteaksInBradley((BaseEntity)entity)) {
                        if (IsTCHacking((BaseEntity)entity)) {
                            info.damageTypes.ScaleAll(200000.0f);
                        }
                        else {
                            //there are no innocents if they get hit.//info.damageTypes.ScaleAll(0.0f);
                            if (entity is BuildingBlock || entity is DecayEntity) {
                                info.damageTypes.ScaleAll(0.0f);
                            }
                            else {
                                info.damageTypes.ScaleAll(damageScale);
                            }
                        }
                    }
                    else {
                        info.damageTypes.ScaleAll(damageScale);
                    }
                    //Puts("DEBUG: Bradley is attacking " +entity+ " for "+ info.damageTypes.Total());
                }
            }
            //Puts("DEBUG: DAMAGE" + info.damageTypes.Total() + " --- " + info.WeaponPrefab + "..." + info.Initiator);
            // mitigate rocket damage to bystanderes
            if (info.WeaponPrefab != null && info.WeaponPrefab.name.Contains("MainCannonShell")) {
                //Puts("DEBUG: bradley cannon?" + info.damageTypes.Total() + " --- " + info.WeaponPrefab + "..." + entity);
                if (!HasSteaksInBradley((BaseEntity)entity)) {
                    if (IsTCHacking((BaseEntity)entity)) {
                        info.damageTypes.ScaleAll(50000.0f);
                    }
                    else {
                        //Puts("DEBUG: rocket hit innocent, no damage" + entity);
                        if (entity is BuildingBlock || entity is DecayEntity) {
                            info.damageTypes.ScaleAll(0.0f);
                        }
                        else {
                            info.damageTypes.ScaleAll(damageScale);
                        }
                    }
                }
                else {
                    info.damageTypes.ScaleAll(damageScale);
                    if (entity is BuildingBlock || entity is DecayEntity || entity.name.Contains("shopfront.metal") || entity.name.Contains("door")) {
                        //Puts("Attacking building wall, make it destructive");
                        info.damageTypes.ScaleAll(450.0f * damageScale);
                    }
                }
                //Puts("DEBUG: Bradley is canon attacking " +entity+ " for "+ info.damageTypes.Total());
            }
            return null;
        }
        private object OnPlayerAttack(BasePlayer attacker, HitInfo info) {
            if (info == null || info.HitEntity == null) return null;
            if (info.HitEntity == currentBradley) {
                if (!HasSteaksInBradley(attacker)) {
                    SendReply(attacker, "You don't have permission to attack this Bradley!");
                    info.damageTypes.ScaleAll(0.0f);
                    return false;
                }
                if (!TCAuthVerification(attacker)) {
                    SendReply(attacker, "You can only attack Bradley in a base you're authed on!");
                    info.damageTypes.ScaleAll(0.0f);
                    return false;
                }
            }
            return null;
        }
        private object CanBradleyApcTarget(BradleyAPC apc, BaseEntity target) {
            if (apc != currentBradley) return null;
            return HasSteaksInBradley(target) ? null : (object)false;
        }
        // loot protection
        void OnEntitySpawned(BaseNetworkable entity) {
            if (entity == null) return;
            //remove fire from bradley (and possible bradley), cause it is no use...if (entity.name != null && entity.name.Contains("oilfireball") && !entity.IsDestroyed)
            {
                entity.Kill();
            }
            if (entity is BradleyAPC && (currentBradley == null || currentBradley != entity)) {
                Puts("Killing public Bradley with no owner");
                entity.Kill();
            }
            if (entity is HelicopterDebris) {
                var debris = entity as HelicopterDebris;
                if (debris == null || entity.IsDestroyed) return;
                debris.Kill();
            }
        }
        private void OnPlayerDisconnected(BasePlayer player, string reason) {
            killUI(player);
            if (player && player == currentBradleyOwner && currentBradley != null) {
                currentIsForceKill = true;
                currentBradley.Kill();
                Puts(player + " disconnected, active Bradley was surrendered");
            }
            if (player && storedData.TicketData.ContainsKey(player.userID)) {
                removeFromQueue(player);
                Puts(player + " disconnected, Bradley ticket was removed");
            }
        }
#endregion
#region BradleyMods
        class BradleyModifyer : MonoBehaviour {
            public BradleyAPC APC {
                get;
                set;
            }
            bool IsBoosted {
                get;
                set;
            }
            void Awake() {
                APC = GetComponent<BradleyAPC>();
                APC.myRigidBody.useGravity = true;
                //APC.coaxFireRate = 0.03667f;
            }
            private float hoverHeight = 1.0f;
            private float terrainHeight;
            private Vector3 pos;
            private RaycastHit hit;
            public Transform raycastPoint;
            void Update() {
            }
            void OnCollisionEnter(Collision collision) {
                var obj = collision.gameObject;
                //print("DEBUG: collision with name: " + collision.gameObject.name);
                if (obj.name.Contains("wall.frame") || obj.name.Contains("refinery_small") || obj.name.Contains("gate") || obj.name.Contains("ollider") || obj.name.Contains("table") || obj.name.Contains("fence") || obj.name.Contains("furnace") || obj.name.Contains("barricade") || obj.name.Contains("bench") || obj.name.Contains("bed") || obj.name.Contains("box") || obj.name.Contains("water") || obj.name.Contains("locker") || obj.name.Contains("barbeque") || obj.name.Contains("chair") || obj.name.Contains("sign") || obj.name.Contains("wall.low")) {
                    Physics.IgnoreCollision(collision.collider, APC.myCollider);
                    Vector3 newPosition = Plugin.GetNewAPCTarget();
                    APC.transform.position = newPosition;
                    /*var ent = obj.GetComponentInParent<BaseEntity>();
                        if (ent != null)
                        {
                            ent.Kill(BaseNetworkable.DestroyMode.Gib);
                            return;
                        }*/
                }
                if (obj.name.Contains("building core")) {
                    var ent = obj.GetComponentInParent<BaseEntity>();
                    if (ent != null) {
                        Vector3 newPosition = Plugin.GetNewAPCTarget();
                        APC.transform.position = newPosition;
                        return;
                        if (!Plugin.HasSteaksInBradley(ent)) return;
                        ((BuildingBlock)ent).health -= 1201f;
                        if (((BuildingBlock)ent).health <= 1) ent.Kill(BaseNetworkable.DestroyMode.Gib);
                    }
                }
                if (obj.name.Contains("foundation") || obj.name.Contains("ramp") || obj.name.Contains("roof") || obj.name.Contains("wall.low")) {
                    var ent = obj.GetComponentInParent<BaseEntity>();
                    if (ent != null) {
                        Vector3 newPosition = Plugin.GetNewAPCTarget();
                        APC.transform.position = newPosition;
                        return;
                        if (!Plugin.HasSteaksInBradley(ent)) return;
                        ent.Kill(BaseNetworkable.DestroyMode.Gib);
                        return;
                    }
                }
                if (collision.gameObject.layer == 16 || obj.name.Contains("foundation")) {
                    if (!collision.gameObject.name.Contains("perimeter_wall") || obj.name.Contains("foundation")) {
                        Physics.IgnoreCollision(collision.collider, APC.myCollider);
                    }
                    if (!IsBoosted) {
                        var force = APC.moveForceMax;
                        APC.moveForceMax *= 4.5f;
                        Plugin.timer.Once(1f, () => {
                            if (APC != null && !APC.IsDead()) {
                                APC.moveForceMax = force;
                                IsBoosted = false;
                            }
                        }
                        );
                        IsBoosted = true;
                    }
                    return;
                }
                var res = obj.GetComponentInParent<ResourceEntity>();
                if (res != null) {
                    var fakeInfo = new HitInfo();
                    fakeInfo.PointStart = APC.transform.position - APC.myRigidBody.velocity * 0.5f;
                    fakeInfo.PointEnd = res.transform.position;
                    res.OnKilled(fakeInfo);
                    return;
                }
                /* 
                var dent = obj.GetComponentInParent<DecayEntity>();
                if(dent != null)
                {
                    dent.Kill(BaseNetworkable.DestroyMode.Gib);
                    return;
                } 
                */
                var jpile = obj.GetComponent<JunkPile>();
                if (jpile != null) {
                    jpile.SinkAndDestroy();
                }
            }
        }
#endregion
#region HelperFunctions
        private void initTitles() {
            foreach (KeyValuePair<string, Dictionary<string, string>> d in Cfg.Titles) {
                ZNTitleManager?.Call("UpsertTitle", getTitleID(d.Key), "Brad '" + 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() {
            if (currentBradley != null) {
                currentIsForceKill = true;
                SendReply(currentBradleyOwner, "Your Bradley has been sent away.");
                currentBradley.Kill();
            }
        }
        private void createRewardCrates(Vector3 targetPos) {
            if (LootBoxSpawner == null) {
                Puts("ERROR: LootBoxSpawner not loaded!");
                return;
            }
            else {
                int minRewardMultiplyer = (int)Math.Ceiling(Cfg.BradleyLevels[currentBradleyLevel]["minRewardMultiplyer"]);
                minRewardMultiplyer += (int)Math.Floor((currentTeamMemberIDs.Count - 1) * Cfg.TeamRewartPercentPerPlayer * minRewardMultiplyer);
                int maxRewardMultiplyer = (int)Math.Ceiling(Cfg.BradleyLevels[currentBradleyLevel]["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 {
                    LootBoxSpawner.Call("storeRewardClaim", currentBradleyOwner.userID, currentBradleyLevel, minRewardMultiplyer, maxRewardMultiplyer, "brad");
                    msg = "Use <color=green>/loot</color> to get your reward.";
                }
                SendReply(currentBradleyOwner, msg);
            }
        }
        private BasePlayer FindPlayer(ulong userID) {
            BasePlayer player = BasePlayer.FindByID(userID);
            if (player == null) {
                player = BasePlayer.FindSleeping(userID);
            }
            return player;
        }
        private void adjustBradleyPower(BradleyAPC bradley) {
            string bradleyLevel = currentBradleyLevel;
            int currentTeamSize = currentTeamMemberIDs.Count();
            float bradleyHealth = Cfg.BradleyLevels[bradleyLevel]["bradleyHealth"];
            bradleyHealth += (float)(bradleyHealth * Cfg.TeamHealthPercentPerPlayer * (currentTeamSize - 1f));
            bradley._maxHealth = bradleyHealth;
            bradley.health = bradleyHealth;
            bradley.maxCratesToSpawn = 0;
            bradley.moveForceMax *= 1.2f;
        }
        private static BradleyAPC InstantiateEntity(Vector3 position) {
            var prefabName = "assets/prefabs/npc/m2bradley/bradleyapc.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<BradleyAPC>();
        }
        private bool CallBradleyForPlayer(BasePlayer player, string bradleyLevel = "normal") {
            currentBradleyOwner = player;
            currentBradley = InstantiateEntity(GetNewAPCTarget());
            if (!currentBradley) return false;
            currentBradley.Spawn();
            currentBradley.SendNetworkUpdateImmediate();
            currentBradley.UpdateMovement_Hunt();
            //currentBradley.transform.position = GetNewAPCTarget();
            currentBradleyOwner = player;
            currentBradleySpawnTime = DateTime.Now;
            if (cooldownBrads.Contains(bradleyLevel)) lastPlayerBradley[player.userID] = DateTime.Now;
            currentBradleyLevel = bradleyLevel;
            currentDamage.Add(0, 0f);
            // total damage counter
            lastDamageTime = DateTime.Now;
            // team related additions
            if (currentBradleyOwner.currentTeam != 0UL) {
                RelationshipManager.PlayerTeam theTeam = RelationshipManager.ServerInstance.FindTeam(player.currentTeam);
                foreach (var member in theTeam.members) {
                    BasePlayer p = BasePlayer.Find("" + member);
                    if (p != null) {
                        currentTeamMemberIDs.Add(member);
                        currentDamage.Add(member, 0f);
                        currentBradley.AddOrUpdateTarget(player, player.transform.position);
                    }
                }
            }
            else {
                currentTeamMemberIDs.Add(player.userID);
                currentDamage.Add(player.userID, 0f);
                currentBradley.AddOrUpdateTarget(player, player.transform.position);
            }
            adjustBradleyPower(currentBradley);
            removeFromQueue(player);
            currentBradley.gameObject.AddComponent<BradleyModifyer>();
            // add movement timer
            SetupGameTimer();
            currentBradley.SendNetworkUpdateImmediate();
            foreach (var p in BasePlayer.activePlayerList) {
                SendReply(p, "Personal <color=#63ff64>" + bradleyLevel + "</color> BradleyAPC was spawned for <color=#63ff64>" + player.displayName + " </color>.\nIt will not damage bystanders.");
            }
            ZNui?.Call("ToggleEvent", "tankEvent", true);
            return true;
        }
        private Vector3 FindTeamPosition() {
            if (currentDamage.Count <= 2 || currentDamage[0] <= 0) return currentBradleyOwner.transform.position;
            int rand = Random.Range(1, currentDamage.Count);
            ulong playerID = currentDamage.ElementAt(rand).Key;
            BasePlayer p = FindPlayer(playerID);
            if (p != null) {
                return p.transform.position;
            }
            else {
                return currentBradleyOwner.transform.position;
            }
        }
        private void FireGun() {
            currentBradley.FireGun(currentBradleyOwner.eyes.position, 3f, true);
            //currentBradley.FireGun(currentBradleyOwner.eyes.position, 3f, false);
            currentBradley.FireGunTest();
            currentBradley.mainGunTarget = (BaseCombatEntity)currentBradleyOwner;
            currentBradley.DoWeaponAiming();
            currentBradley.FireGun(currentBradleyOwner.eyes.position, 3f, true);
        }
        private void AirStrike() {
            return;
            if (currentDamage.Count <= 2) return;
            timer.Repeat(1f, 2, () => {
                float randX = Random.Range(-8, 8);
                float randZ = Random.Range(-8, 8);
                float randY = Random.Range(5f, 20f);
                Vector3 spawnPoint2 = FindTeamPosition() + new Vector3(randX, randY, randZ);
                string cratePrefab = "assets/prefabs/ammo/rocket/rocket_basic.prefab";
                var entity = GameManager.server.CreateEntity(cratePrefab, spawnPoint2);
                entity.OwnerID = currentBradley.net.ID;
                if (entity == null) {
                    return;
                }
                entity.Spawn();
            }
            );
        }
        private void SetupGameTimer() {
            Vector3 lastBradPosition = currentBradley.transform.position;
            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 (!currentBradleyOwner.IsConnected || (DateTime.Now - lastDamageTime).TotalSeconds > getNoDamageSurrenderTime()) {
                    surrenderEnemy();
                }
            }
            );
            //bradleyFireTimer = timer.Every(6f, () =>
            //{
            //});
            bradleyRedirectionTimer = timer.Every(7f, () => {
                float disty = Math.Abs(FindTeamPosition().y - currentBradley.transform.position.y);
                if(disty > 10f || currentBradley.health < (currentBradley._maxHealth/ 3f)) {
                    timer.Once(0.5f, () => {
                        FireGun();
                    }
                    );
                    timer.Once(1.5f, () => {
                        FireGun();
                    }
                    );
                }
                if(currentBradley.health < (currentBradley._maxHealth / 5f)) {
                    AirStrike();
                }
                FireGun();
                timer.Once(1f, () => {
                    FireGun();
                }
                );
                List<Vector3> newPath = GetNewAPCPath(currentBradley.transform.position);
                currentBradley.currentPathIndex = 0;
                currentBradley.AddOrUpdateTarget(currentBradleyOwner, FindTeamPosition());
                Vector3 newPosition = GetNewAPCTarget();
                float distance = Vector3Ex.Distance2D(currentBradley.transform.position, lastBradPosition);
                if (distance <= 2f) {
                    currentBradley.transform.position = newPosition;
                    SendReply(currentBradleyOwner, "Brad used the teleporter to get unstuck!");
                    Puts("DEBUG: brad TP to: " + currentBradley.transform.position + " from: " + lastBradPosition);
                    return;
                }
                lastBradPosition = currentBradley.transform.position;
                // bradley is stuck
                if (newPath == null) return;
                if (newPath.Count > 120 || currentBradley.transform.position.y < (TerrainMeta.HeightMap.GetHeight(currentBradley.transform.position) - 5)) {
                    newPath = GetNewAPCPath(newPosition);
                    if (newPath != null) {
                        currentBradley.transform.position = newPosition;
                        //Puts("DEBUG: Bradley uses Blink ability ");
                    }
                    else {
                        //Puts("Player " + currentBradleyOwner + " too far away or hiding from Bradley.Waiting for them to move.");
                        return;
                    }
                }
                currentBradley.currentPath = newPath;
                //Puts("DEBUG: update path " + currentBradley.currentPath + " ___ " + currentBradley.currentPath?.Count);
            }
            );
        }
        private int getNoDamageSurrenderTime() {
            float health = currentBradley.health;
            float maxHealth = currentBradley._maxHealth;
            int healthPercent = (int)Math.Ceiling((health / maxHealth) * 100);
            return 120 + ((100 - healthPercent) * 2);
        }
        private List<Vector3> GetNewAPCPath(Vector3 position) {
            List<Vector3> path = (List<Vector3>)PathFinding?.Call("FindBestPath", position, GetNewAPCTarget());
            return path;
        }
        private Vector3 GetNewAPCTarget(int rec = 0, float range = 20f) {
            float rand1 = Random.Range(-range, range);
            float rand2 = Random.Range(-range, range);
            float minDistance = 20f;
            float randX = (rand1 > 0 ? (rand1 + minDistance) : (rand1 - minDistance));
            float randZ = (rand2 > 0 ? (rand2 + minDistance) : (rand2 - minDistance));
            Vector3 node = FindTeamPosition() + new Vector3(randX, 200f, randZ);
            node = SampleHeightWithRaycast(node);
            // check if the path is blocked by something
            NavMeshHit navMeshHit;
            if (!NavMesh.SamplePosition(node, out navMeshHit, 5f, NavMesh.AllAreas)) {
                //Puts("DEBUG: retry navmesh " + node);
                // break recursion
                if (rec > 15) return node;
                // try to find an unblocked random
                rec++;
 
// ... [Code preview truncated due to length. Full source in attached file] ...

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