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

FREE BuildManager : 1.12.7 1.12.7

Нет прав для скачивания
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 System.Collections.Generic;
using Oxide.Core;
using Oxide.Core.Plugins;
using UnityEngine;
using System.Linq;
using System;
using System.Text.RegularExpressions;
namespace Oxide.Plugins {
    [Info("BuildManager", "DocValerian", "1.12.7")]
    class BuildManager : RustPlugin {
        static BuildManager Plugin;
        [PluginReference]
        private Plugin ServerRewards, PatchesForPVE, HeliFromHell, BradleyFromHell, ZombieFromHell, ZNExperience;
        static ConfigFile Cfg = new ConfigFile();
        private const string permAgrade = "buildmanager.agrade.use";
        private const string permAgradeFree = "buildmanager.agrade.free";
        private const string permRepall = "buildmanager.repairall.use";
        private const string permRepallFree = "buildmanager.repairall.free";
        private const string permException = "buildmanager.exception.manage";
        private const string permUnlimited = "buildmanager.unlimited.use";
        private const string permExtended_1 = "buildmanager.extended.t1";
        private const string permExtended_2 = "buildmanager.extended.t2";
        private const string permExtended_3 = "buildmanager.extended.t3";
        private const string permExtended_4 = "buildmanager.extended.t4";
        private const string permExtended_5 = "buildmanager.extended.t5";
        static string[] foundationPrefabNames = {
            "foundation", "foundation.triangle"
        }
        ;
        static string[] heightPrefabNames = {
            "wall", "wall.half", "wall.low", "wall.frame", "wall.window", "wall.doorway", "roof", "block.stair.ushape", "block.stair.lshape", "block.stair.spiral", "block.stair.spiral.triangle"
        }
        ;
        static string[] halfHeightPrefabNames = {
            "wall.half", "wall.low"
        }
        ;
        static string[] buildingPrefabNames = {
            "foundation", "foundation.triangle", "wall", "wall.half", "wall.low", "wall.frame", "wall.window", "wall.doorway", "roof", "block.stair.ushape", "block.stair.lshape", "floor", "floor.frame", "floor.triangle"
        }
        ;
        int tcMasks = LayerMask.GetMask("Deployed");
        class ConfigFile {
            public Dictionary<string, Dictionary<string, int>> Limits = new Dictionary<string, Dictionary<string, int>> {
                ["town"]
                = new Dictionary<string, int> {
                    ["foundations"]
                    = 10, ["height"] = 2, ["minowntcdistance"] = 200,
                }
                , ["exception"] = new Dictionary<string, int> {
                    ["foundations"]
                    = 800, ["height"] = 50, ["minowntcdistance"] = 200,
                }
                , ["default"] = new Dictionary<string, int> {
                    ["foundations"]
                    = 30, ["height"] = 3, ["minowntcdistance"] = 200,
                }
                , ["buildmanager.extended.t1"] = new Dictionary<string, int> {
                    ["foundations"]
                    = 50, ["height"] = 5, ["minowntcdistance"] = 200,
                }
                , ["buildmanager.extended.t2"] = new Dictionary<string, int> {
                    ["foundations"]
                    = 80, ["height"] = 7, ["minowntcdistance"] = 200,
                }
                , ["buildmanager.extended.t3"] = new Dictionary<string, int> {
                    ["foundations"]
                    = 120, ["height"] = 12, ["minowntcdistance"] = 200,
                }
                , ["buildmanager.extended.t4"] = new Dictionary<string, int> {
                    ["foundations"]
                    = 160, ["height"] = 15, ["minowntcdistance"] = 200,
                }
                , ["buildmanager.extended.t5"] = new Dictionary<string, int> {
                    ["foundations"]
                    = 800, ["height"] = 50, ["minowntcdistance"] = 200,
                }
                , ["buildmanager.unlimited.use"] = new Dictionary<string, int> {
                    ["foundations"]
                    = 5000, ["height"] = 30, ["minowntcdistance"] = 10,
                }
                ,
            }
            ;
            public Dictionary<string, string> BannedItemsAlternatives = new Dictionary<string, string>() {
                ["electric.windmill.small"]
                = "Test Generator (in /trade)", ["mining_quarry"] = "/mm",
            }
            ;
            public Dictionary<string, List<string>> AllowedDeployables = new Dictionary<string, List<string>> {
                ["default"]
                = new List<string> {
                }
                , ["town"] = new List<string> {
                }
                , ["zoneID"] = new List<string> {
                }
                , ["buildmanager.extended.t1"] = new List<string> {
                }
                , ["buildmanager.extended.t2"] = new List<string> {
                }
                , ["buildmanager.extended.t3"] = new List<string> {
                }
                , ["buildmanager.extended.t4"] = new List<string> {
                }
                , ["buildmanager.extended.t5"] = new List<string> {
                }
                , ["buildmanager.unlimited.use"] = new List<string> {
                }
                ,
            }
            ;
            public Dictionary<string, List<string>> ForbiddenDeployables = new Dictionary<string, List<string>> {
                ["default"]
                = new List<string> {
                }
                , ["town"] = new List<string> {
                    "wall.external.high.wood", "wall.external.high.stone", "gates.external.high.wood", "gates.external.high.stone", "watchtower.wood", "teslacoil.deployed", "autoturret_deployed", "laserlight.deployed", "discofloor.deployed", "electric.flasherlight.deployed",
                }
                , ["zoneID"] = new List<string> {
                }
                , ["buildmanager.extended.t1"] = new List<string> {
                }
                , ["buildmanager.extended.t2"] = new List<string> {
                }
                , ["buildmanager.extended.t3"] = new List<string> {
                }
                , ["buildmanager.extended.t4"] = new List<string> {
                }
                , ["buildmanager.extended.t5"] = new List<string> {
                }
                , ["buildmanager.unlimited.use"] = new List<string> {
                }
                ,
            }
            ;
            public bool Debug = false;
            public bool KillBiggerBases = false;
            public int RepairAllPricePerEntity = 5;
            public float RepairAllResMult = 1.5f;
            public float RepairAllFreeResMult = 1.1f;
            public int AgradePricePerEntity = 5;
            public float AgradeResMult = 1.5f;
            public float AgradeFreeResMult = 1.1f;
        }
        class StoredData {
            public List<ulong> ExceptionTcIds = new List<ulong>();
        }
        StoredData storedData;
        private Dictionary<ulong, DateTime> globalWoodRefundTimer = new Dictionary<ulong, DateTime>();
        bool HasPermission(string id, string perm) => permission.UserHasPermission(id, perm);
        void Loaded() {
            Cfg = Config.ReadObject<ConfigFile>();
            LoadMessages();
            Plugin = this;
            permission.RegisterPermission(permAgrade, this);
            permission.RegisterPermission(permAgradeFree, this);
            permission.RegisterPermission(permRepall, this);
            permission.RegisterPermission(permRepallFree, this);
            permission.RegisterPermission(permException, this);
            permission.RegisterPermission(permUnlimited, this);
            permission.RegisterPermission(permExtended_1, this);
            permission.RegisterPermission(permExtended_2, this);
            permission.RegisterPermission(permExtended_3, this);
            permission.RegisterPermission(permExtended_4, this);
            permission.RegisterPermission(permExtended_5, this);
            globalWoodRefundTimer = new Dictionary<ulong, DateTime>();
            storedData = Interface.Oxide.DataFileSystem.ReadObject<StoredData>("BuildManager");
            SaveData();
        }
        private void OnServerInitialized() {
            initSkills();
        }
        protected override void LoadDefaultConfig() {
            PrintWarning("Creating a new configuration file...");
            Config.WriteObject(Cfg, true);
        }
        void SaveData() {
            Interface.Oxide.DataFileSystem.WriteObject("BuildManager", storedData);
        }
        void LoadMessages() {
            Dictionary<string, string> msg = new Dictionary<string, string> {
                ["NoBuildingPrivilege"]
                = "You are not within a building privlege.", ["NoAuthorization"] = "You are not authorized in this building privlege.", ["Line"] = "----------------------------------", ["BlockCnt"] = "Total Building Blocks: {0}", ["FoundationCnt"] = "Foundations (all): {0}", ["HeightCnt"] = "Building height: {0}"
            }
            ;
            lang.RegisterMessages(msg, this);
        }
        private void initSkills() {
            initSkill(0, 0);
            initSkill(1, 2);
            initSkill(2, 3);
            initSkill(3, 3, true);
            initSkill(4, 4, true);
            initSkill(5, 10, true);
            ZNExperience.Call("SaveSkillSetup");
        }
        private void initSkill(int lvl, int cost, bool prestige = false) {
            string id = "buildmanager.extended.t" + lvl;
            string name = "Building";
            string groupId = "abilities";
            int spCost = cost;
            List<string> permissionEffect = new List<string>();
            string description = "";
            string followUpSkillId = "";
            string prerequisiteSkillId = "";
            bool isDefault = false;
            string prestigeUnlockId = "";
            string iconURL = "";
            Dictionary<string, int> limits = Cfg.Limits[(lvl != 0) ? id : "default"];
            description = "Increases your building limits to <color=green>" + limits["foundations"] + "</color> foundations and <color=green>" + limits["height"] + "</color> height for YOUR TCs.(except for /town area)\nCheck your limits with with <color=green>/cb</color>";
            followUpSkillId = "buildmanager.extended.t" + (lvl + 1);
            if (lvl == 0) {
                isDefault = true;
                name += "  Base";
            }
            else {
                isDefault = false;
                name += "  Lv." + lvl;
                permissionEffect = new List<string> {
                    id
                }
                ;
                prerequisiteSkillId = "buildmanager.extended.t" + (lvl - 1);
                if (lvl == 5) {
                    followUpSkillId = "";
                }
            }
            if (prestige) {
                prestigeUnlockId = "pBuild";
            }
            ZNExperience.Call("RegisterSkill", id, name, groupId, spCost, permissionEffect, description, prerequisiteSkillId, followUpSkillId, isDefault, prestigeUnlockId, iconURL);
        }
#region hooks
        //auto upgrade twig - based on BGrade by "Ryan", "1.0.49"
        private void OnEntityBuilt(Planner plan, GameObject gameObject) {
            var player = plan?.GetOwnerPlayer();
            var buildingBlock = gameObject.GetComponent<BuildingBlock>();
            if (player == null || buildingBlock == null) {
                return;
            }
            if (!player.CanBuild() || buildingBlock.grade != BuildingGrade.Enum.Twigs) {
                return;
            }
            BuildingManager.Building b = buildingBlock.GetBuilding();
            if (b == null || HasPermission(player.UserIDString, permUnlimited)) {
                return;
            }
            if(b.buildingBlocks.Count() >= 21 && (b.GetDominatingBuildingPrivilege() == null || (!b.GetDominatingBuildingPrivilege().IsAuthed(player))) ) {
                znBuildMsg(player, "<color=red>(error)</color> You must place a <color=green>Tool Cupboard (TC)</color> after 20 blocks to prevent spam.\n<color=#999999>It can be repositioned later with /remove</color>");
                buildingBlock.Kill(BaseNetworkable.DestroyMode.None);
            }
            // Puts("DEBUG: built " + buildingBlock.PrefabName);
            if (b.buildingBlocks.Count() >= 21 && !buildingBlock.PrefabName.Contains("roof") ) {
                Dictionary<int, int> itemsToTake;
                var resourceResponse = TakeResources(player, 1, buildingBlock, out itemsToTake);
                if (!string.IsNullOrEmpty(resourceResponse)) {
                    SendReply(player, "Not enough resources!");
                    refundBuildingBlock(player, buildingBlock);
                    buildingBlock.Kill();
                    if (globalWoodRefundTimer.ContainsKey(player.userID)) {
                        globalWoodRefundTimer[player.userID] = DateTime.Now;
                    }
                    else {
                        globalWoodRefundTimer.Add(player.userID, DateTime.Now);
                    }
                    return;
                }
                foreach (var itemToTake in itemsToTake) {
                    if (player.inventory.Take(null, itemToTake.Key, itemToTake.Value) > 0) {
                        player.SendConsoleCommand("note.inv", itemToTake.Key, itemToTake.Value * -1);
                    }
                }
                buildingBlock.SetGrade(BuildingGrade.Enum.Wood);
                buildingBlock.SetHealthToMax();
                buildingBlock.StartBeingRotatable();
                buildingBlock.SendNetworkUpdate();
                buildingBlock.UpdateSkin();
                buildingBlock.ResetUpkeepTime();
                buildingBlock.GetBuilding()?.Dirty();
            }
        }
        // prevent placing TC on oversized bases and connecting partial bases
        private void OnEntitySpawned(BaseEntity entity, UnityEngine.GameObject gameObject) {
            /*
            if (entity.ShortPrefabName.Contains("xmas.advanced.lights"))
            {
                
                NextTick(() =>
                {
                   //Puts("DEBUG: adding xmaslight " + entity.OwnerID);
                   entity.Kill(BaseNetworkable.DestroyMode.None);
                });

            }
            */
            if(!entity.ShortPrefabName.Contains("cupboard.tool") && !buildingPrefabNames.Contains(entity.ShortPrefabName)) return;
            if(entity.OwnerID == 0) return;
            BasePlayer player = BasePlayer.FindByID(entity.OwnerID);
            if (player == null) return;
            if(player.IsSleeping() == true || player.IsConnected == false || HasPermission(player.UserIDString, permUnlimited)) return;
            BuildingPrivlidge privilege = entity.GetBuildingPrivilege();
            // CHECK for TC distance to other TCs (of player) first
            if(entity.ShortPrefabName.Contains("cupboard.tool") && !checkTCdistanceOk(player, privilege)) {
                NextTick(() => {
                    entity.Kill(BaseNetworkable.DestroyMode.None);
                }
                );
                Item tcitm = ItemManager.CreateByName("cupboard.tool", 1);
                player.GiveItem(tcitm, BaseEntity.GiveItemReason.Generic);
                return;
            }
            if (!privilege) return;
            BuildingManager.Building building = privilege.GetBuilding();
            Dictionary<string, float> dimensions = getBuildingDimensions(building);
            string currentZone = getCurrentZone(player, privilege);
            if(dimensions["foundationsCount"] > Cfg.Limits[currentZone]["foundations"]) {
                //killBuilding(building, entity.OwnerID);
                NextTick(() => {
                    entity.Kill(BaseNetworkable.DestroyMode.None);
                }
                );
                znBuildMsg(player, "You are trying to circumvent the foundation limit! (" + Cfg.Limits[currentZone]["foundations"] + ")");
            }
            if(dimensions["height"] > Cfg.Limits[currentZone]["height"]) {
                if(entity.ShortPrefabName.Contains("foundation")) {
                    NextTick(() => {
                        entity.Kill(BaseNetworkable.DestroyMode.None);
                    }
                    );
                    znBuildMsg(player, "You have reached the "+currentZone+" height limit (" + Cfg.Limits[currentZone]["height"] + "), placing height changing foundations will waste resources!");
                    return;
                }
                else {
                    NextTick(() => {
                        entity.Kill(BaseNetworkable.DestroyMode.None);
                    }
                    );
                    znBuildMsg(player, "Your base is beyond the " + currentZone + " height limit! (" + Cfg.Limits[currentZone]["height"] + ")");
                    //killBuilding(building, player.userID);
                    //znBuildMsg(player, "You have somehow (tried to) circumvent the height limit! ("
                    //            + Cfg.Limits[currentZone]["height"]
                    //            + ") \n Your entity was destroyed, there will be no refunds!");
                    return;
                }
            }
        }
        private object CanBuild(Planner planner, Construction entity, Construction.Target target) {
            if (planner == null || entity == null) {
                return null;
            }
            // check if we care about what we are trying to build
            string name = entity?.fullName ?? string.Empty;
            string groupName = string.Empty;
            //Puts("DEBUG: can Build: " + name);
            Match match = Regex.Match(name, @".*assets/prefabs/([^/]+)/.*/([^/]+)\.prefab$", RegexOptions.IgnoreCase);
            if (match.Success) {
                groupName = match.Groups[1].Value;
                name = match.Groups[2].Value;
            }
            else {
                return null;
            }
            bool isFoundation = foundationPrefabNames.Contains(name);
            bool isHeightEntity = heightPrefabNames.Contains(name);
            var player = planner?.GetOwnerPlayer();
            if (globalWoodRefundTimer.ContainsKey(player.userID) && (DateTime.Now - globalWoodRefundTimer[player.userID]).TotalSeconds < 5) return false;
            if (HasPermission(player.UserIDString, permUnlimited)) return null;
            if (!isFoundation && !isHeightEntity) {
                if (canBuildInZone(player, name, groupName)) {
                    return null;
                }
                else {
                    return false;
                }
            }
            BuildingPrivlidge privilege = player.GetBuildingPrivilege();
            // the first foundation can always be placed outside of privilege
            // after that, a TC must be placed!
            // CHECK for TC distance to other TCs (of player) first
            if (!privilege && target.socket == null) {
                if(checkTCdistanceOk(player)) {
                    return null;
                }
                else {
                    return false;
                }
            }
            else if(!privilege && isFoundation) {
                return null;
                //TRIAL, see, if people behave...//znBuildMsg(player, "You must place a TC (It can be repositioned later).");
                //return false;
            }
            else if (!privilege && target.entity.transform.position.y < 0) {
                //Puts("DEBUG: Target " + target.entity.transform.position.y);
                return null;
            }
            else if (!privilege) {
                return null;
                //TRIAL, see, if people behave...//znBuildMsg(player, "You must place a TC (It can be repositioned later).");
                //return false;
            }
            // If a TC has been placed, don't allow starting new bases in Privilege
            if (privilege && target.socket == null) {
                znBuildMsg(player, "You cannot build away from the main building.");
                return false;
            }
            BuildingManager.Building building = privilege.GetBuilding();
            // prevent decoupling foundations
            if(building.buildingBlocks != null && !building.buildingBlocks.Contains(target.entity)) {
                znBuildMsg(player, "You cannot build away from the main building.");
                return false;
            }
            Dictionary<string, float> dimensions = getBuildingDimensions(building);
            string currentZone = getCurrentZone(player, privilege);
            // evil limit hackers must be punished.Destroy everything if they try to build in oversized bases.if(dimensions["foundationsCount"] > Cfg.Limits[currentZone]["foundations"])
            {
                znBuildMsg(player, "Your base is beyond the " + currentZone + " foundation limit! (" + Cfg.Limits[currentZone]["foundations"] + ") \n You must remove " + (dimensions["foundationsCount"] - Cfg.Limits[currentZone]["foundations"]) + " foundations to be able to build!");
                return false;
            }
            if(isFoundation && dimensions["foundationsCount"] == Cfg.Limits[currentZone]["foundations"]) {
                znBuildMsg(player, "You have reached the " + currentZone + " foundation limit! (" + Cfg.Limits[currentZone]["foundations"] + ")");
                return false;
            }
            // if we place a wall and we have reached the hight limit (and only then)
            // we need to check if the wall wall type we want to place is making the building taller
            // (or if it is just an internal wall, or a wall that's on the same level as the top layer)
            if(isHeightEntity && dimensions["height"] == Cfg.Limits[currentZone]["height"]) {
                // the finished build would end at target_start+height(unless foundation!) + height_of_thing_to_build
                float finalHeight = target.entity.transform.position.y + entity.bounds.size.y;
                if(!IsFoundationObject((BuildingBlock)target.entity)) {
                    finalHeight += target.entity.bounds.size.y;
                }
                //---debug---
                if(Cfg.Debug) Puts("top " + dimensions["topY"]);
                if(Cfg.Debug) Puts("final " + finalHeight);
                // we only need the full numbers to allow for floor-hook 0.000x differences in height.if(Math.Ceiling(finalHeight) > Math.Ceiling(dimensions["topY"]))
                {
                    znBuildMsg(player, "You have reached the " + currentZone + " height limit! (" + Cfg.Limits[currentZone]["height"] + ")");
                    return false;
                }
            }
            return null;
        }
        private bool canBuildInZone(BasePlayer player, string prefabName, string groupName) {
            if(HasPermission(player.UserIDString, permUnlimited)) return true;
            //Puts("Debug: groupName: " + groupName);
            //Puts("Debug: prefabName: " + prefabName);
            if (Cfg.BannedItemsAlternatives.ContainsKey(prefabName)) {
                znBuildMsg(player, "<color=red>You are not allowed to build this on the server!</color>\n<color=green>Alternative:</color> " + Cfg.BannedItemsAlternatives[prefabName]);
                return false;
            }
            string currentZone;
            currentZone = getCurrentZone(player, null);
            if(Cfg.AllowedDeployables[currentZone].Count > 0 && !Cfg.AllowedDeployables[currentZone].Contains(prefabName) ) {
                znBuildMsg(player, "You are not allowed to build that in \"" + currentZone + "\" area!");
                return false;
            }
            else if(Cfg.ForbiddenDeployables[currentZone].Count > 0 && Cfg.ForbiddenDeployables[currentZone].Contains(prefabName) ) {
                znBuildMsg(player, "You are not allowed to build that in \"" + currentZone + "\" area!");
                return false;
            }
            else {
                return true;
            }
        }
#endregion
#region Commands
        [ChatCommand("agrade")]
        void CommandAgrade(BasePlayer player, string command, string[] args) {
            // player group needs permission
            if (!permission.UserHasPermission(player.UserIDString, permAgrade) || (!ServerRewards && Cfg.AgradePricePerEntity > 0)) {
                znBuildMsg(player, "You are not allowed to use this command! (did you unlock it in /p?)");
                return;
            }
            if (args.Length == 0) {
                agradeUsageInfo(player);
                return;
            }
            if (args.Length == 1) {
                int argGrade;
                try {
                    argGrade = int.Parse(args[0]);
                }
                catch (FormatException) {
                    agradeUsageInfo(player);
                    return;
                }
                if (argGrade < 1 || argGrade > 4) {
                    agradeUsageInfo(player);
                    return;
                }
                // you have to be in a building zone
                BuildingPrivlidge privilege = player.GetBuildingPrivilege();
                if (!privilege) {
                    player.ChatMessage(LangMsg("NoBuildingPrivilege", player.UserIDString));
                    return;
                }
                // if you are not authorized, you will only get a generic error, before stuff happens
                if (!privilege.IsAuthed(player) && !player.IsAdmin) {
                    player.ChatMessage(LangMsg("NoAuthorization", player.UserIDString));
                    return;
                }
                BuildingManager.Building building = privilege.GetBuilding();
                float mult = Cfg.AgradeResMult;
                int rpPerBlock = Cfg.AgradePricePerEntity;
                if (permission.UserHasPermission(player.UserIDString, permAgradeFree)) {
                    mult = Cfg.AgradeFreeResMult;
                    rpPerBlock = 0;
                }
                ;
                if (rpPerBlock > 0) {
                    object bal = ServerRewards?.Call("CheckPoints", player.userID);
                    if (bal == null) return;
                    int playerRP = (int)bal;
                    int totalPrice = rpPerBlock * building.buildingBlocks.Count;
                    if (playerRP < totalPrice) {
                        znBuildMsg(player, "This command costs " + totalPrice + " RP to execute, you only have " + playerRP);
                        return;
                    }
                    else {
                        ServerRewards?.Call("TakePoints", player.userID, totalPrice);
                        znBuildMsg(player, "You paid " + totalPrice + " RP, command is executing.");
                    }
                }
                BuildingGrade.Enum newGrade = (BuildingGrade.Enum)int.Parse(args[0]);
                BuildingGrade.Enum oldGrade;
                int agradeCounter = 0;
                foreach (BuildingBlock block in building.buildingBlocks) {
                    oldGrade = block.grade;
                    // skip work, if the block is already in the target grade.if (oldGrade == newGrade)
                    continue;
                    block.SetGrade(newGrade);
                    foreach (ItemAmount itemAmount in block.BuildCost()) {
                        if ((double)player.inventory.GetAmount(itemAmount.itemid) < ((double)itemAmount.amount * mult)) {
                            // can't afford more, roll back
                            block.SetGrade(oldGrade);
                            znBuildMsg(player, "You ran out of materials to upgrade the building!");
                            Puts("AGRADE: used by " + player + " ran out of materials.");
                            return;
                        }
                        else {
                            player.inventory.Take(null, itemAmount.itemid, (int)Math.Ceiling(itemAmount.amount * mult));
                        }
                    }
                    block.SetHealthToMax();
                    block.StartBeingRotatable();
                    block.SendNetworkUpdate();
                    block.UpdateSkin();
                    block.ResetUpkeepTime();
                    block.GetBuilding()?.Dirty();
                    agradeCounter++;
                }
                znBuildMsg(player, "Building was successfully upgraded! (" + agradeCounter + " entities)");
                Puts("AGRADE: used by " + player + " upgrading " + agradeCounter + "entities.");
            }
        }
        [ChatCommand("repairall")]
        void CommandRepairall(BasePlayer player, string command, string[] args) {
            // player group needs permission
            if (!permission.UserHasPermission(player.UserIDString, permRepall) || (!ServerRewards && Cfg.RepairAllPricePerEntity > 0)) {
                znBuildMsg(player, "You are not allowed to use this command! (did you unlock it in /p?)");
                return;
            }
            bool isHeliTeam = (HeliFromHell != null) ? HeliFromHell.Call<bool>("HasSteaksInHeli", player) : false;
            bool isBradTeam = (BradleyFromHell != null) ? BradleyFromHell.Call<bool>("HasSteaksInBradley", player) : false;
            bool isZombieTeam = (ZombieFromHell != null) ? ZombieFromHell.Call<bool>("HasSteaksInZombie", player) : false;
            if(isHeliTeam || isBradTeam || isZombieTeam) {
                znBuildMsg(player, "You can't repairall while fighting (heli/brad/zombie)!");
                return;
            }
            if (args.Length == 0) {
                repallUsageInfo(player);
                return;
            }
            if (args.Length == 1) {
                if (args[0] != "yes") {
                    repallUsageInfo(player);
                    return;
                }
                // you have to be in a building zone
                BuildingPrivlidge privilege = player.GetBuildingPrivilege();
                if (!privilege) {
                    player.ChatMessage(LangMsg("NoBuildingPrivilege", player.UserIDString));
                    return;
                }
                // if you are not authorized, you will only get a generic error, before stuff happens
                if (!privilege.IsAuthed(player) && !player.IsAdmin) {
                    player.ChatMessage(LangMsg("NoAuthorization", player.UserIDString));
                    return;
                }
                BuildingManager.Building building = privilege.GetBuilding();
                bool isHeliBase = (HeliFromHell != null) ? HeliFromHell.Call<bool>("HasSteaksInHeli", privilege) : false;
                bool isBradBase = (BradleyFromHell != null) ? BradleyFromHell.Call<bool>("HasSteaksInBradley", privilege) : false;
                bool isZombieBase = (ZombieFromHell != null) ? ZombieFromHell.Call<bool>("HasSteaksInZombie", privilege) : false;
                if (isHeliBase || isBradBase || isZombieBase) {
                    znBuildMsg(player, "You can't repairall a base of someone fighting (heli/brad/zombie)!");
                    return;
                }
                float mult = Cfg.RepairAllResMult;
                int rpPerBlock = Cfg.RepairAllPricePerEntity;
                if (permission.UserHasPermission(player.UserIDString, permRepallFree)) {
                    mult = Cfg.RepairAllFreeResMult;
                    rpPerBlock = 0;
                }
                ;
                if (rpPerBlock > 0) {
                    object bal = ServerRewards?.Call("CheckPoints", player.userID);
                    if (bal == null) return;
                    int playerRP = (int)bal;
                    int totalPrice = rpPerBlock * building.buildingBlocks.Count;
                    if (playerRP < totalPrice) {
                        znBuildMsg(player, "This command costs " + totalPrice + " RP to execute, you only have " + playerRP);
                        return;
                    }
                    else {
                        ServerRewards?.Call("TakePoints", player.userID, totalPrice);
                        znBuildMsg(player, "You paid " + totalPrice + " RP, command is executing.");
                    }
                }
                int repairCounter = 0;
                foreach (BuildingBlock block in building.buildingBlocks) {
                    // skip work, if the block is already at full health.if (block.MaxHealth() == block.health)
                    continue;
                    double damagePercentage = mult * (1.0 - (block.health / block.MaxHealth()));
                    foreach (ItemAmount itemAmount in block.BuildCost()) {
                        if ((double)player.inventory.GetAmount(itemAmount.itemid) < ((double)itemAmount.amount * damagePercentage)) {
                            znBuildMsg(player, "You ran out of materials to repair a part the building!");
                            Puts("REPAIRALL: used by " + player + " ran out of materials.");
                            return;
                        }
                        else {
                            player.inventory.Take(null, itemAmount.itemid, (int)Math.Ceiling(itemAmount.amount * damagePercentage));
                        }
                    }
                    block.SetHealthToMax();
                    block.SendNetworkUpdate();
                    block.GetBuilding()?.Dirty();
                    repairCounter++;
                }
                znBuildMsg(player, "Building was successfully repaired! (" + repairCounter + " entities)");
                Puts("REPAIRALL: used by " + player + " repairing " + repairCounter + "entities.");
            }
        }
        [ChatCommand("cbex")]
        void CommandCBEX(BasePlayer player, string command, string[] args) {
            // if you are not authorized, you will only get a generic error, before stuff happens
            if (!permCheckVerbose(player, permException)) return;
            // you have to be in a building zone
            BuildingPrivlidge privilege = player.GetBuildingPrivilege();
            if (!privilege) {
                player.ChatMessage(LangMsg("NoBuildingPrivilege", player.UserIDString));
                return;
            }
            string zone = "default";
            string msg = "<color=orange>=== Building Limit Exception: ===</color>";
            if (storedData.ExceptionTcIds.Contains(privilege.net.ID.Value)) {
                storedData.ExceptionTcIds.Remove(privilege.net.ID.Value);
                msg += "\n<color=red>REMOVED!</color>";
            }
            else {
                storedData.ExceptionTcIds.Add(privilege.net.ID.Value);
                msg += "\n<color=green>ACTIVATED!</color>";
                zone = "exception";
            }
            msg += "\nLimit is now: " + GetCurrentLimit(zone, "f") + " foundations, " + GetCurrentLimit(zone, "h") + " height";
            SaveData();
            znBuildMsg(player, msg);
        }
        [ChatCommand("cb")]
        void CommandCB(BasePlayer player, string command, string[] args) {
            // you have to be in a building zone
            BuildingPrivlidge privilege = player.GetBuildingPrivilege();
            if (!privilege) {
                player.ChatMessage(LangMsg("NoBuildingPrivilege", player.UserIDString));
                return;
            }
            // if you are not authorized, you will only get a generic error, before stuff happens
            if (!privilege.IsAuthed(player) && !player.IsAdmin) {
                player.ChatMessage(LangMsg("NoAuthorization", player.UserIDString));
                return;
            }
            BuildingManager.Building building = privilege.GetBuilding();
            Dictionary<string, float> dimensions = getBuildingDimensions(building);
            string currentZone = getCurrentZone(player, privilege);
            string msg = "<color=orange>=============== Check Building (/cb) ================</color>";
            if (storedData.ExceptionTcIds.Contains(privilege.net.ID.Value)) {
                msg += "\n<color=red>Building uses exceptional limits!</color>";
                currentZone = "exception";
            }
            msg += "\n<color=green>Building dimensions:</color>";
            msg += "\nTotal Building Blocks: \t\t" + dimensions["entitiesCount"];
            msg += "\nFoundations: \t\t\t" + dimensions["foundationsCount"] + "/" + GetCurrentLimit(currentZone, "f");
            msg += "\nHeight: \t\t\t\t" + dimensions["height"] + "/" + GetCurrentLimit(currentZone, "h");
            // REPAIRALL Info
            Dictionary<int, float> res = new Dictionary<int, float>();
            Dictionary<BuildingGrade.Enum, int> gradeCounter = new Dictionary<BuildingGrade.Enum, int>() {
                [BuildingGrade.Enum.Twigs]
                = 0, [BuildingGrade.Enum.Wood] = 0, [BuildingGrade.Enum.Stone] = 0, [BuildingGrade.Enum.Metal] = 0, [BuildingGrade.Enum.TopTier] = 0,
            }
            ;
            float mult = Cfg.RepairAllResMult;
            float rpPerBlock = Cfg.RepairAllPricePerEntity;
            if (permission.UserHasPermission(player.UserIDString, permRepallFree)) {
                mult = Cfg.RepairAllFreeResMult;
                rpPerBlock = 0f;
            }
            ;
            foreach (BuildingBlock block in building.buildingBlocks) {
                // skip work, if the block is already at full health.gradeCounter[block.grade]++;
                if (block.MaxHealth() == block.health) continue;
                double damagePercentage = mult * (1.0 - (block.health / block.MaxHealth()));
                foreach (ItemAmount itemAmount in block.BuildCost()) {
                    if (res.ContainsKey(itemAmount.itemid)) {
                        res[itemAmount.itemid] += (float)Math.Ceiling(itemAmount.amount * damagePercentage);
                    }
                    else {
                        res[itemAmount.itemid] = (float)Math.Ceiling(itemAmount.amount * damagePercentage);
                    }
                }
            }
            msg += "\n\n<color=green>Estimated /repairall cost:</color>";
            if (!permission.UserHasPermission(player.UserIDString, permRepall)) {
                msg += "\nCommand needs to be unlocked in <color=orange>/p</color> first!";
            }
            else {
                int rpPrice = (int) Math.Ceiling(dimensions["entitiesCount"] * rpPerBlock);
                msg += "\n" + rpPrice;
                msg += (rpPrice >= 10000) ? "\t" : "\t\t";
                msg += "RP";
                if (res.Count > 0) {
                    foreach (KeyValuePair<int, float> d in res) {
                        msg += "\n" + Math.Ceiling(d.Value);
                        msg += (d.Value >= 10000f) ? "\t" : "\t\t";
                        msg += ItemManager.itemDictionary[d.Key].displayName.translated;
                    }
                }
                else {
                    msg += "\nNothing to repair!";
                }
            }
            // AGRADE INFO
            mult = Cfg.AgradeResMult;
            rpPerBlock = Cfg.AgradePricePerEntity;
            if (permission.UserHasPermission(player.UserIDString, permAgradeFree)) {
                mult = Cfg.AgradeFreeResMult;
                rpPerBlock = 0f;
            }
            ;
            msg += "\n\n<color=green>Max /agrade (upgrade all) cost:</color>";
            msg += "\n<color=#aaaaaa>Doesn't consider exact block shape but checks grade!</color>";
            if (!permission.UserHasPermission(player.UserIDString, permAgrade)) {
                msg += "\nCommand needs to be unlocked in <color=orange>/p</color> first!";
            }
            else {
                int rpPrice = (int)Math.Ceiling(dimensions["entitiesCount"] * rpPerBlock);
                msg += "\nCommand base-fee:\t\t<color=#aaaaaa>" + rpPrice + "</color> RP";
                int price = 0;
                // grade 1
                price = (int)Math.Ceiling((dimensions["entitiesCount"] - gradeCounter[BuildingGrade.Enum.Wood]) * 200 * mult);
                msg += "\n/agrade 1 (Wood):\t\t<color=#aaaaaa>" + price + "</color> Wood";
                // grade 2
                price = (int)Math.Ceiling((dimensions["entitiesCount"] - gradeCounter[BuildingGrade.Enum.Stone]) * 300 * mult);
                msg += "\n/agrade 2 (Stone):\t\t<color=#aaaaaa>" + price + "</color> Stones";
                // grade 3
                price = (int)Math.Ceiling((dimensions["entitiesCount"] - gradeCounter[BuildingGrade.Enum.Metal]) * 200 * mult);
                msg += "\n/agrade 3 (Metal):\t\t<color=#aaaaaa>" + price + "</color> Metal Fragments";
                // grade 4
                price = (int)Math.Ceiling((dimensions["entitiesCount"] - gradeCounter[BuildingGrade.Enum.TopTier]) * 25 * mult);
                msg += "\n/agrade 4 (HQM):\t\t<color=#aaaaaa>" + price + "</color> High Quality Metal";
            }
            if (Cfg.ForbiddenDeployables.ContainsKey(currentZone) && Cfg.ForbiddenDeployables[currentZone].Count > 0) {
                msg += "\n\n<color=green>Forbidden in the area:</color>";
                foreach(string itm in Cfg.ForbiddenDeployables[currentZone]) {
                    msg += "\n- " + itm;
                }
            }
            SendReply(player, msg);
        }
#endregion
#region functions
        private void znBuildMsg(BasePlayer player, string msg) {
            SendReply(player, "<color=orange>ZN-Build:</color> " + msg);
        }
        private void refundBuildingBlock(BasePlayer player, BuildingBlock buildingBlock) {
            var itemsToGive = new Dictionary<int, int>();
            foreach (var itemAmount in buildingBlock.blockDefinition.grades[0].CostToBuild()) {
                if (!itemsToGive.ContainsKey(itemAmount.itemid)) {
                    itemsToGive.Add(itemAmount.itemid, 0);
                }
                itemsToGive[itemAmount.itemid] += (int)itemAmount.amount;
            }
            foreach (var itemToGive in itemsToGive) {
                player.GiveItem(ItemManager.CreateByItemID(itemToGive.Key, (int)itemToGive.Value), BaseEntity.GiveItemReason.PickedUp);
            }
        }
        private string TakeResources(BasePlayer player, int buildingGrade, BuildingBlock buildingBlock, out Dictionary<int, int> items) {
            var itemsToTake = new Dictionary<int, int>();
            if (buildingBlock == null) {
                Puts("DEBUG: buildingBlock is null for " + player);
                items = null;
                return "";
            }
            foreach (var itemAmount in buildingBlock.blockDefinition.grades[buildingGrade].CostToBuild()) {
                if (!itemsToTake.ContainsKey(itemAmount.itemid)) {
                    itemsToTake.Add(itemAmount.itemid, 0);
                }
                itemsToTake[itemAmount.itemid] += (int)itemAmount.amount;
            }
            var canAfford = true;
            foreach (var itemToTake in itemsToTake) {
                if (!HasItemAmount(player, itemToTake.Key, itemToTake.Value)) {
                    canAfford = false;
                }
            }
            items = itemsToTake;
            return canAfford ? null : "Error.Resources";
        }
        private bool HasItemAmount(BasePlayer player, int itemId, int itemAmount) {
            var count = 0;
            foreach (var item in player.inventory.AllItems()) {
                if (item.info.itemid == itemId) {
                    count += item.amount;
                }
            }
            return count >= itemAmount;
        }
        private bool checkTCdistanceOk(BasePlayer player, BuildingPrivlidge bp = null) {
            Vector3 position = (bp) ? bp.transform.position : player.transform.position;
            // always allow placing in caves
            float terrainHeight = TerrainMeta.HeightMap.GetHeight(position) - 0.5f;
            if(position.y < terrainHeight) return true;
            string typeString = (bp) ? "TC" : "base";
            float range = Cfg.Limits[getCurrentZone(player, bp)]["minowntcdistance"] + 0f;
            float distance;
            List<BuildingPrivlidge> list = new List<BuildingPrivlidge>();
            Vis.Entities<BuildingPrivlidge>(position, range, list, tcMasks);
            foreach(BuildingPrivlidge entity in list) {
                // ignore TCs in caves and the just placed tc
                terrainHeight = TerrainMeta.HeightMap.GetHeight(entity.transform.position) - 0.5f;
                if(entity.transform.position.y < terrainHeight) continue;
                if(bp && entity == bp) continue;
                distance = Vector3Ex.Distance2D(entity.transform.position, position);
                //Puts("Distance: " + distance);
                // player has a TC within 400m already
                if(entity.OwnerID == player.userID) {
                    znBuildMsg(player, "You are not allowed to place another "+typeString+" within "+ range + "m to your existing one.("+distance+"m away)");
                    return false;
                }
                // too close to other base
                //if(distance <= 50f){
                //    znBuildMsg(player, "You are not allowed to place a  "+typeString+" so close to another base.");
                //    return false;
                //}
            }
            // all good
            return true;
        }
        private string getCurrentZone(BasePlayer player, BuildingPrivlidge privlidge) {
            string currentZone = "default";
            if(privlidge != null && storedData.ExceptionTcIds.Contains(privlidge.net.ID.Value)) {
                return "exception";
            }
            if(PatchesForPVE != null) {
                bool isInTownRange = (bool)PatchesForPVE?.Call<bool>("IsCloseToTown", player.transform.position);
                if (isInTownRange) {
                    return "town";
// ... [Code preview truncated due to length. Full source in attached file] ...

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