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

FREE RoadBradley : 1.5.3 1.5.3

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
//Reference: 0Harmony
using System;
using System.Collections.Generic;
using System.Linq;
using ConVar;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Oxide.Game.Rust.Libraries;
using Rust;
using UnityEngine;
using Harmony;
namespace Oxide.Plugins {
    [Info("RoadBradley", "ThePitereq", "1.5.3")]
    public class RoadBradley : RustPlugin {
        private static RoadBradley _plugin;
        [PluginReference]
        private readonly Plugin Economics, ServerRewards, Friends, Clans, ShoppyStock;
        private static HarmonyInstance harmony;
        private readonly List<BradleyAPC> roadBradleys = new List<BradleyAPC>();
        private readonly Dictionary<string, RoadInfo> roads = new Dictionary<string, RoadInfo>();
        private readonly Dictionary<ulong, Dictionary<string, int>> purchaseCooldowns = new Dictionary<ulong, Dictionary<string, int>>();
        private readonly Dictionary<BradleyAPC, int> bradleyTimers = new Dictionary<BradleyAPC, int>();
        private readonly Dictionary<Vector3, string> obstacleChecks = new Dictionary<Vector3, string>();
        private readonly Dictionary<string, SpawnConfig> mapRoutes = new Dictionary<string, SpawnConfig>();
        private readonly Dictionary<BradleyAPC, ulong> currentBradleyOwners = new Dictionary<BradleyAPC, ulong>();
        private readonly List<ulong> routeEditors = new List<ulong>();
        private readonly TankDeathInfo tankDeathInfo = new TankDeathInfo();
        private string mapName;
        private Timer killTimer;
        private static readonly Dictionary<string, string> markerPrefabs = new Dictionary<string, string>() {
            {
                "crate", "assets/prefabs/tools/map/cratemarker.prefab"
            }
            , {
                "chinook", "assets/prefabs/tools/map/ch47marker.prefab"
            }
            , {
                "cargoship", "assets/prefabs/tools/map/cargomarker.prefab"
            }
            , {
                "generic", "assets/prefabs/tools/map/genericradiusmarker.prefab"
            }
            , {
                "vending", "assets/prefabs/deployable/vendingmachine/vending_mapmarker.prefab"
            }
        }
        ;
        private class RoadInfo {
            public bool isDefault = true;
            public bool isRandomEvent = false;
            public bool isPurchasable = false;
            public bool isNowOccupied = false;
            public string routeName = string.Empty;
            public List<Vector3> checkpoints = new List<Vector3>();
        }
        private class TankDeathInfo {
            public Vector3 tankDeathLoc = Vector3.zero;
            public string tankDeathProfile = "";
            public ulong tankDeathOwner = 0;
            public ulong topDmgUser = 0;
            public Dictionary<string, int> crateCount = new Dictionary<string, int>();
        }
        private void Init() {
            Unsubscribe(nameof(OnWeaponFired));
            Unsubscribe(nameof(OnPlayerAttack));
            Unsubscribe(nameof(OnLoseCondition));
        }
        private void OnServerInitialized() {
            _plugin = this;
            cmd.AddChatCommand("tankroute", this, nameof(TankRouteCommand));
            permission.RegisterPermission("roadbradley.admin", this);
            permission.RegisterPermission("roadbradley.bypass", this);
            config = Config.ReadObject<PluginConfig>();
            if (config.commands.Count == 0) config.commands.Add("buytank");
            AddCovalenceCommand("spawnrbtank", nameof(SpawnTankCommand));
            AddCovalenceCommand("tankcount", nameof(TankCountCommand));
            Config.WriteObject(config);
            LoadMessages();
            LoadData();
            harmony = HarmonyInstance.Create("com.ThePitereq.RoadBradley");
            harmony.Patch(original : AccessTools.Method(typeof(BradleyAPC), nameof(BradleyAPC.DoPhysicsMove)), prefix : new HarmonyMethod(typeof(BradleyLimitMovement), nameof(BradleyLimitMovement.Prefix)));
            /*foreach (var road in roadData.roads.ToList())
            {
                Vector3 prev = Vector3.zero;
                bool startDeleting = false;
                foreach (var checkpoint in road.Value.ToList())
                {
                    if (checkpoint == prev)
                        startDeleting = true;
                    prev = checkpoint;
                    if (startDeleting)
                        roadData.roads[road.Key].Remove(checkpoint);
                }
            }
            SaveData();*/
            if (config.checkObstacles) foreach (ProtoBuf.PrefabData entry in World.Serialization.world.prefabs) {
                if (TerrainMeta.TopologyMap.GetTopology(entry.position, 2048) && !obstacleChecks.ContainsKey(entry.position)) {
                    string prefabName = StringPool.Get(entry.id).Split('/').Last().Replace(".prefab", "");
                    bool shouldAdd = true;
                    foreach (var whitelist in config.obstacleWhitelist) {
                        if (prefabName.ToLower().Contains(whitelist.ToLower())) {
                            shouldAdd = false;
                            break;
                        }
                    }
                    if (shouldAdd) obstacleChecks.Add(entry.position, prefabName);
                }
            }
            FindRoads();
            cmd.AddChatCommand("showroute", this, nameof(DebugShowRouteCommand));
            //DEBUG
            foreach (var command in config.commands) cmd.AddChatCommand(command, this, nameof(BuyTankCommand));
            if (!roads.Any()) {
                PrintWarning("Roads on map not found! Disabling the plugin...");
                Server.Command($"oxide.unload {this.Name}");
                return;
            }
            if (!config.mapTracks.ContainsKey("default")) {
                PrintWarning("Default road config not found! Disabling the plugin...");
                Server.Command($"oxide.unload {this.Name}");
                return;
            }
            mapName = ConVar.Server.levelurl.Split('/').Last();
            foreach (var configValue in config.mapTracks) if (mapName.Contains(configValue.Key)) {
                mapName = configValue.Key;
                break;
            }
            foreach (var configValue in config.purchases.Values) if (configValue.permission != "") permission.RegisterPermission(configValue.permission, this);
            if (config.mapTracks.ContainsKey(mapName)) foreach (var spawnConfig in config.mapTracks[mapName]) mapRoutes.Add(spawnConfig, config.spawns[spawnConfig]);
            else {
                mapName = "default";
                if (ConVar.Server.level == "HapisIsland") mapName = "HapisIsland";
                if (config.mapTracks.ContainsKey(mapName)) foreach (var spawnConfig in config.mapTracks[mapName]) mapRoutes.Add(spawnConfig, config.spawns[spawnConfig]);
            }
            if (config.ignoreOwnerships) Unsubscribe(nameof(CanLootEntity));
            if (!config.enabledBags) Unsubscribe(nameof(CanBeWounded));
            Puts($"Setting routes for '{mapName}' map profile...");
            GenerateDefaultTracks();
            if (config.purchases.Any()) GeneratePurchasableTracks();
            foreach (var route in mapRoutes) SpawnDefaultRouteTank(route.Key);
            SaveData();
        }
        private void Unload() {
            SaveData();
            foreach (var bradley in roadBradleys) bradley?.Kill();
            foreach (var player in BasePlayer.activePlayerList) {
                CuiHelper.DestroyUi(player, "RoadBradleyUI_Main");
                CuiHelper.DestroyUi(player, "RoadBradleyUI_Timer");
                CuiHelper.DestroyUi(player, "RoadBradleyUI_Edit");
            }
            harmony.UnpatchAll("com.ThePitereq.RoadBradley");
        }
        private void FindRoads() {
            int counter = 0;
            foreach (var road in TerrainMeta.Path.Roads) {
                if (config.asphaltOnly && road.Width <= 5) continue;
                roads.TryAdd($"{counter}", new RoadInfo() {
                    isDefault = true
                }
                );
                roads[$"{counter}"].checkpoints = new List<Vector3>(road.Path.Points.ToList());
                roads.Add($"{counter}_Edited", new RoadInfo() {
                    isDefault = false, isPurchasable = true
                }
                );
                roads[$"{counter}_Edited"].checkpoints = new List<Vector3>();
                List<Vector3> alreadyListed = new List<Vector3>();
                bool failedCheck = false;
                foreach (var checkpoint in road.Path.Points.ToList()) {
                    if (config.checkObstacles) {
                        foreach (var obstacle in obstacleChecks) {
                            if (!alreadyListed.Contains(obstacle.Key) && Vector3.Distance(checkpoint, obstacle.Key) < road.Width / 2) {
                                alreadyListed.Add(obstacle.Key);
                                if (config.removeObstacleRoads) {
                                    Puts($"There is an obstacle '{obstacle.Value}' on the road '{counter}' at '{obstacle.Key}'.Removing road from the road pool!");
                                    roads.Remove($"{counter}_Edited");
                                    failedCheck = true;
                                    break;
                                }
                                else Puts($"There is an obstacle '{obstacle.Value}' on the road '{counter}' at '{obstacle.Key}'.");
                            }
                        }
                        if (failedCheck) break;
                    }
                    Vector3 checkpointFixed = checkpoint;
                    checkpointFixed.y = TerrainMeta.HeightMap.GetHeight(checkpointFixed);
                    if (config.heightOffset != 0) checkpointFixed.y += config.heightOffset;
                    roads[$"{counter}_Edited"].checkpoints.Add(checkpointFixed);
                }
                counter++;
                if (failedCheck) continue;
            }
            foreach (var road in roadData.roads) {
                roads.Add(road.Key, new RoadInfo() {
                    isDefault = false, checkpoints = road.Value
                }
                );
            }
            SaveData();
        }
        private void GenerateDefaultTracks() {
            bool longestSet = false;
            foreach (var route in mapRoutes) {
                if (!config.spawns.ContainsKey(route.Key)) {
                    PrintWarning($"Route '{route.Key}' not found in configuration! Skipping...");
                    continue;
                }
                if (route.Value.useLongestPath) {
                    if (longestSet) PrintWarning($"You've already set one route to be on longest route! Bradleys can collide!");
                    longestSet = true;
                    int longest = 0;
                    string longestName = "";
                    foreach (var road in roads) {
                        if (road.Value.isDefault) continue;
                        int count = road.Value.checkpoints.Count;
                        if (count > longest) {
                            longest = count;
                            longestName = road.Key;
                        }
                    }
                    if (roads[longestName].checkpoints.Count < 5) {
                        PrintWarning($"Route '{longestName}' is too small for a bradley! Cannot be used.");
                        continue;
                    }
                    if (config.removeTimedRoads) roads[longestName].isPurchasable = false;
                    roads[longestName].isRandomEvent = true;
                    roads[longestName].routeName = route.Key;
                    bool isLooped = false;
                    if (Vector3.Distance(roads[longestName].checkpoints.First(), roads[longestName].checkpoints.Last()) < 5f) isLooped = true;
                    if (!isLooped) {
                        if (route.Value.removeCheckpointAmount * 2 >= roads[longestName].checkpoints.Count) PrintWarning($"You are removing more start/end checkpoints that is available on road '{longestName}'!");
                        List<Vector3> removeCheckpoints = new List<Vector3>();
                        removeCheckpoints.AddRange(roads[longestName].checkpoints.Take(config.removePurchasableCheckpointAmount));
                        removeCheckpoints.AddRange(roads[longestName].checkpoints.TakeLast(config.removePurchasableCheckpointAmount));
                        foreach (var point in removeCheckpoints) roads[longestName].checkpoints.Remove(point);
                        int pointCount = roads[longestName].checkpoints.Count - 1;
                        foreach (var point in roads[longestName].checkpoints.ToList()) {
                            roads[longestName].checkpoints.Add(roads[longestName].checkpoints[pointCount]);
                            pointCount--;
                        }
                    }
                    Puts($"Route '{longestName}' set and added as longest bradley route!");
                }
                else {
                    List<List<string>> routes = new List<List<string>>(route.Value.trackList);
                    if (route.Value.useAllDefault) {
                        routes = new List<List<string>>();
                        foreach (var road in roads) if (road.Value.isDefault) routes.Add(new List<string>() {
                            road.Key
                        }
                        );
                    }
                    int routeCount = 0;
                    foreach (var road1 in routes) {
                        string fixedName1 = $"{road1[0]}_Edited";
                        int i = int.TryParse(road1[0], out i) ? i : -1;
                        if (i == -1) fixedName1 = road1[0];
                        if (!roads.ContainsKey(fixedName1)) {
                            PrintWarning($"No data found about road '{fixedName1}' on map! Skipping whole route!");
                            continue;
                        }
                        string roadDisplay = fixedName1;
                        if (route.Value.trackList.Any()) roadDisplay = string.Join(",", route.Value.trackList[routeCount]);
                        foreach (var road2 in road1.Skip(1)) {
                            string fixedName2 = $"{road2}_Edited";
                            int x;
                            if (!int.TryParse(road2, out x)) fixedName2 = road2;
                            if (!roads.ContainsKey(fixedName2)) {
                                PrintWarning($"No data found about road '{road2}' on map! Skipping this road in route!");
                                continue;
                            }
                            roads[fixedName1].checkpoints.AddRange(roads[fixedName2].checkpoints);
                            if (config.removeTimedRoads) {
                                roads[fixedName2].isPurchasable = false;
                                roads[fixedName2].isRandomEvent = false;
                            }
                        }
                        if (roads[fixedName1].checkpoints.Count < 5) {
                            PrintWarning($"Route made with roads '{roadDisplay}' is too small! Cannot be used.");
                            continue;
                        }
                        if (config.removeTimedRoads) roads[fixedName1].isPurchasable = false;
                        roads[fixedName1].isRandomEvent = true;
                        roads[fixedName1].routeName = route.Key;
                        bool isLooped = false;
                        if (Vector3.Distance(roads[fixedName1].checkpoints.First(), roads[fixedName1].checkpoints.Last()) < 5f) isLooped = true;
                        if (!isLooped) {
                            if (i != -1) {
                                if (route.Value.removeCheckpointAmount * 2 >= roads[fixedName1].checkpoints.Count) PrintWarning($"You are removing more start/end checkpoints that is available on road '{fixedName1}'!");
                                List<Vector3> removeCheckpoints = new List<Vector3>();
                                removeCheckpoints.AddRange(roads[fixedName1].checkpoints.Take(config.removePurchasableCheckpointAmount));
                                removeCheckpoints.AddRange(roads[fixedName1].checkpoints.TakeLast(config.removePurchasableCheckpointAmount));
                                foreach (var point in removeCheckpoints) roads[fixedName1].checkpoints.Remove(point);
                            }
                            int pointCount = roads[fixedName1].checkpoints.Count - 1;
                            foreach (var point in roads[fixedName1].checkpoints.ToList()) {
                                roads[fixedName1].checkpoints.Add(roads[fixedName1].checkpoints[pointCount]);
                                pointCount--;
                            }
                        }
                        Puts($"Route made with roads '{roadDisplay}' set and added as bradley route!");
                        routeCount++;
                    }
                }
            }
        }
        private void GeneratePurchasableTracks() {
            int counter = 0;
            foreach (var road in roads) {
                if (road.Value.isDefault) continue;
                if (config.removeTimedRoads && road.Value.isRandomEvent) continue;
                if (!road.Value.checkpoints.Any()) continue;
                int i = int.TryParse(road.Key.Split('_')[0], out i) ? i : -1;
                if (i == -1 && !(config.customRoads.ContainsKey(mapName) && config.customRoads[mapName].Contains(road.Key))) continue;
                if (i != -1 && config.roadBlacklist.ContainsKey(mapName) && config.roadBlacklist[mapName].Contains(i)) continue;
                road.Value.isPurchasable = true;
                bool isLooped = false;
                if (Vector3.Distance(road.Value.checkpoints.First(), road.Value.checkpoints.Last()) < 5f) isLooped = true;
                if (!isLooped) {
                    if (i != -1) {
                        if (config.removePurchasableCheckpointAmount * 2 >= road.Value.checkpoints.Count) PrintWarning($"You are removing more start/end checkpoints that is available on road {road.Key}!");
                        List<Vector3> removeCheckpoints = new List<Vector3>();
                        removeCheckpoints.AddRange(road.Value.checkpoints.Take(config.removePurchasableCheckpointAmount));
                        removeCheckpoints.AddRange(road.Value.checkpoints.TakeLast(config.removePurchasableCheckpointAmount));
                        foreach (var point in removeCheckpoints) road.Value.checkpoints.Remove(point);
                    }
                    int pointCount = road.Value.checkpoints.Count - 1;
                    foreach (var point in road.Value.checkpoints.ToList()) {
                        road.Value.checkpoints.Add(road.Value.checkpoints[pointCount]);
                        pointCount--;
                    }
                }
                counter++;
                Puts($"Route '{road.Key}' set and added as purchasable bradley route!");
            }
            if (counter == 0) PrintWarning("You have too less roads to make purchasable bradleys! Decrease amount of timed bradleys or disable purchases!");
            else Puts("Tracks for purchasable bradleys set successfully!");
        }
        private void SpawnDefaultRouteTank(string route) {
            int thisRouteCount = 0;
            foreach (var tank in roadBradleys.ToList()) {
                if (tank == null) {
                    roadBradleys.Remove(tank);
                    continue;
                }
                if (tank.GetComponent<RoadBradleyController>().routeName == route) thisRouteCount++;
            }
            int playerCount = BasePlayer.activePlayerList.Count;
            int bradleys = 0;
            foreach (var bradleyAmount in config.spawns[route].onlinePlayers) {
                if (playerCount >= bradleyAmount.Value) bradleys = bradleyAmount.Key;
            }
            int bradleysToSpawn = bradleys - thisRouteCount;
            if (bradleysToSpawn <= 0) {
                if (thisRouteCount == 0) timer.Once(900, () => SpawnDefaultRouteTank(route));
                return;
            }
            for (int i = 0; i < bradleysToSpawn; i++) {
                int chance = 0;
                foreach (var tankType in config.spawns[route].chances) chance += tankType.Value;
                int rolledTank = Core.Random.Range(1, chance + 1);
                chance = 0;
                foreach (var tankType in config.spawns[route].chances) {
                    chance += tankType.Value;
                    if (chance >= rolledTank) {
                        SpawnTank(tankType.Key, route);
                        break;
                    }
                }
            }
        }
        private void SpawnTank(string profileName, string routeName) {
            ProfileConfig configValue = config.profiles[profileName];
            List<string> possibleRoads = new List<string>();
            foreach (var road in roads) {
                if (road.Value.routeName == routeName && !road.Value.isNowOccupied) possibleRoads.Add(road.Key);
            }
            if (!possibleRoads.Any()) {
                PrintWarning($"Couldn't find suitable road for bradley with profile '{profileName}' on route '{routeName}'.");
                return;
            }
            string rolledRoad = possibleRoads[Core.Random.Range(0, possibleRoads.Count - 1)];
            int spawnPoint = 0;
            if (config.randomizeSpawn) spawnPoint = Core.Random.Range(0, roads[rolledRoad].checkpoints.Count - 1);
            Vector3 startPosition = roads[rolledRoad].checkpoints[spawnPoint] + new Vector3(0, 0.1f, 0);
            RuntimePath runtimePath = new RuntimePath();
            RuntimePath runtimePath2 = runtimePath;
            IAIPathNode[] nodes = new RuntimePathNode[roads[rolledRoad].checkpoints.Count];
            runtimePath2.Nodes = nodes;
            IAIPathNode iaipathNode = null;
            int num5 = 0;
            int num6 = roads[rolledRoad].checkpoints.Count - 1;
            for (int j = 0; j <= num6; j++) {
                IAIPathNode iaipathNode2 = new RuntimePathNode(roads[rolledRoad].checkpoints[j] + Vector3.up * 1f);
                if (iaipathNode != null) {
                    iaipathNode2.AddLink(iaipathNode);
                    iaipathNode.AddLink(iaipathNode2);
                }
                runtimePath.Nodes[num5] = iaipathNode2;
                iaipathNode = iaipathNode2;
                num5++;
            }
            RuntimeInterestNode interestNode = new RuntimeInterestNode(roads[rolledRoad].checkpoints[0] + Vector3.up * 1f);
            runtimePath.AddInterestNode(interestNode);
            RuntimeInterestNode interestNode2 = new RuntimeInterestNode(roads[rolledRoad].checkpoints.Last() + Vector3.up * 1f);
            runtimePath.AddInterestNode(interestNode2);
            BradleyAPC tank = GameManager.server.CreateEntity("assets/prefabs/npc/m2bradley/bradleyapc.prefab", startPosition) as BradleyAPC;
            roads[rolledRoad].isNowOccupied = true;
            tank.Spawn();
            tank.InstallPatrolPath(runtimePath);
            tank.gameObject.AddComponent<RoadBradleyController>();
            RoadBradleyController controller = tank.GetComponent<RoadBradleyController>();
            controller.roadInfo = roads[rolledRoad];
            controller.routeName = routeName;
            controller.profile = profileName;
            if (configValue.disarmEnabled) {
                GameObject go = new GameObject();
                go.AddComponent<BradleyDisarmZone>();
                BradleyDisarmZone bradleyDisarm = go.GetComponent<BradleyDisarmZone>();
                go.transform.SetParent(tank.transform, true);
                bradleyDisarm.SetupZone(tank);
            }
            roadBradleys.Add(tank);
            tank.currentPath = new List<Vector3>(roads[rolledRoad].checkpoints);
            tank.currentPathIndex = spawnPoint;
            tank.moveForceMax = configValue.moveForce;
            tank.throttle = configValue.moveSpeed;
            tank.leftThrottle = configValue.moveSpeed;
            tank.rightThrottle = configValue.moveSpeed;
            tank.searchRange = configValue.viewRange;
            tank.viewDistance = configValue.viewRange;
            if (configValue.lootPreset == "") tank.maxCratesToSpawn = configValue.crateAmount;
            else {
                int crateAmount = Core.Random.Range(config.lootPresets[configValue.lootPreset].minCrates, config.lootPresets[configValue.lootPreset].maxCrates + 1);
                tank.maxCratesToSpawn = crateAmount;
            }
            tank.coaxBurstLength = configValue.coaxBurstLength;
            tank.coaxFireRate = configValue.coaxFireRate;
            tank.coaxAimCone = configValue.coaxAimCone;
            tank.bulletDamage = configValue.coaxBulletDamage;
            tank._health = configValue.health;
            tank._maxHealth = configValue.health;
            tank.globalBroadcast = true;
            if (configValue.tankScale != 1) {
                timer.Once(5, () => {
                    if (tank != null && !tank.IsDestroyed) {
                        SphereEntity sphere = GameManager.server.CreateEntity("assets/prefabs/visualization/sphere.prefab", tank.transform.position) as SphereEntity;
                        sphere.Spawn();
                        tank.SetParent(sphere, true);
                        sphere.LerpRadiusTo(configValue.tankScale, 1000);
                    }
                }
                );
            }
            string markerType = configValue.markerType.ToLower();
            if (markerType != "none") {
                BaseEntity marker = GameManager.server.CreateEntity(markerPrefabs[markerType], tank.transform.position);
                marker.SetParent(tank, true);
                marker.Spawn();
                marker.transform.position = startPosition;
            }
            if (config.enableTankInfo) {
                VendingMachineMapMarker marker2 = GameManager.server.CreateEntity(markerPrefabs["vending"], tank.transform.position) as VendingMachineMapMarker;
                marker2.SetParent(tank, true);
                marker2.Spawn();
                marker2.transform.position = startPosition;
                marker2.markerShopName = string.Format(config.tankInfo, profileName.ToUpper());
            }
            if (config.spawns[routeName].announceSpawn) foreach (var player in BasePlayer.activePlayerList) SendReply(player, Lang("BradleySpawned", player.UserIDString, profileName, PhoneController.PositionToGridCoord(startPosition)));
            tank.SendNetworkUpdate();
        }
        private void TryPurchaseTank(BasePlayer player, string profile, bool forceBuy = false) {
            if (!config.purchases.ContainsKey(profile)) return;
            if (!forceBuy) {
                string date = DateTime.Now.ToShortDateString();
                limitData.limits.TryAdd(date, new Dictionary<ulong, Dictionary<string, int>>());
                limitData.limits[date].TryAdd(player.userID, new Dictionary<string, int>());
                limitData.limits[date][player.userID].TryAdd(profile, 0);
                if (!permission.UserHasPermission(player.UserIDString, "roadbradley.bypass")) {
                    if (purchaseCooldowns.ContainsKey(player.userID) && purchaseCooldowns[player.userID].ContainsKey(profile)) return;
                    if (currentBradleyOwners.ContainsValue(player.userID)) return;
                    if (config.purchases[profile].maxDaily != 0 && limitData.limits[date][player.userID][profile] >= config.purchases[profile].maxDaily) return;
                }
            }
            string targetRoad = "";
            Dictionary<string, float> nearestRoad = new Dictionary<string, float>();
            foreach (var road in roads) if (road.Value.isPurchasable && !road.Value.isNowOccupied && road.Value.checkpoints.Any()) nearestRoad.Add(road.Key, Vector3.Distance(player.transform.position, road.Value.checkpoints[0]));
            foreach (var road in nearestRoad.OrderBy(x => x.Value)) {
                targetRoad = road.Key;
                break;
            }
            CuiHelper.DestroyUi(player, "RoadBradleyUI_Main");
            if (targetRoad == "") {
                SendReply(player, Lang("NoFreeRoad", player.UserIDString));
                return;
            }
            if (config.maxBradleys > 0) {
                int spawnedPurchasedTanks = 0;
                foreach (var apc in roadBradleys) {
                    if (apc == null) continue;
                    RoadBradleyController apcCont = apc.GetComponent<RoadBradleyController>();
                    if (apcCont != null && apcCont.ownerId != 0) spawnedPurchasedTanks++;
                }
                if (spawnedPurchasedTanks > config.maxBradleys) {
                    SendReply(player, Lang("TooManyBradleys", player.UserIDString));
                    return;
                }
            }
            if (!forceBuy) {
                if (!permission.UserHasPermission(player.UserIDString, "roadbradley.bypass") && !TakeResources(player, config.purchases[profile].requiredItems)) return;
                string date = DateTime.Now.ToShortDateString();
                limitData.limits[date][player.userID][profile]++;
                purchaseCooldowns.TryAdd(player.userID, new Dictionary<string, int>());
                purchaseCooldowns[player.userID].TryAdd(profile, 0);
                purchaseCooldowns[player.userID][profile] = config.purchases[profile].cooldown;
            }
            ProfileConfig configValue = config.profiles[profile];
            int spawnPoint = 0;
            if (config.randomizeSpawn) spawnPoint = Core.Random.Range(0, roads[targetRoad].checkpoints.Count - 1);
            Vector3 startPosition = roads[targetRoad].checkpoints[spawnPoint] + new Vector3(0, 0.1f, 0);
            BradleyAPC tank = GameManager.server.CreateEntity("assets/prefabs/npc/m2bradley/bradleyapc.prefab", startPosition) as BradleyAPC;
            Puts($"Tank '{profile}' purchased by '{player.displayName}' ({player.UserIDString}) has spawned on road '{targetRoad}'!");
            tank.Spawn();
            Interface.Call("OnRoadBradleyPurchased", player, tank, profile, targetRoad);
            roads[targetRoad].isNowOccupied = true;
            tank.gameObject.AddComponent<RoadBradleyController>();
            RoadBradleyController controller = tank.GetComponent<RoadBradleyController>();
            controller.roadInfo = roads[targetRoad];
            controller.profile = profile;
            controller.ownerId = player.userID;
            if (configValue.disarmEnabled) {
                GameObject go = new GameObject();
                go.AddComponent<BradleyDisarmZone>();
                BradleyDisarmZone bradleyDisarm = go.GetComponent<BradleyDisarmZone>();
                go.transform.SetParent(tank.transform, true);
                bradleyDisarm.SetupZone(tank);
            }
            roadBradleys.Add(tank);
            currentBradleyOwners.Add(tank, player.userID);
            bradleyTimers.TryAdd(tank, config.purchases[profile].killTime + config.purchases[profile].comingTime);
            tank.currentPath = new List<Vector3>(roads[targetRoad].checkpoints);
            tank.currentPathIndex = spawnPoint;
            tank.moveForceMax = configValue.moveForce;
            tank.throttle = configValue.moveSpeed;
            tank.leftThrottle = configValue.moveSpeed;
            tank.rightThrottle = configValue.moveSpeed;
            tank.searchRange = configValue.viewRange;
            tank.viewDistance = configValue.viewRange;
            if (configValue.lootPreset == "") tank.maxCratesToSpawn = configValue.crateAmount;
            else {
                int crateAmount = Core.Random.Range(config.lootPresets[configValue.lootPreset].minCrates, config.lootPresets[configValue.lootPreset].maxCrates + 1);
                tank.maxCratesToSpawn = crateAmount;
            }
            tank.coaxBurstLength = configValue.coaxBurstLength;
            tank.coaxFireRate = configValue.coaxFireRate;
            tank.coaxAimCone = configValue.coaxAimCone;
            tank.bulletDamage = configValue.coaxBulletDamage;
            tank._health = configValue.health;
            tank._maxHealth = configValue.health;
            tank.globalBroadcast = true;
            if (configValue.tankScale != 1) {
                timer.Once(5, () => {
                    if (tank != null && !tank.IsDestroyed) {
                        SphereEntity sphere = GameManager.server.CreateEntity("assets/prefabs/visualization/sphere.prefab", tank.transform.position) as SphereEntity;
                        sphere.Spawn();
                        tank.SetParent(sphere, true);
                        sphere.LerpRadiusTo(configValue.tankScale, 1000);
                    }
                }
                );
            }
            string markerType = configValue.markerType.ToLower();
            if (markerType != "none") {
                BaseEntity marker = GameManager.server.CreateEntity(markerPrefabs[markerType], tank.transform.position);
                marker.Spawn();
                marker.SetParent(tank, true);
            }
            if (config.enablePurchasedTankInfo) {
                VendingMachineMapMarker marker2 = GameManager.server.CreateEntity(markerPrefabs["vending"], startPosition) as VendingMachineMapMarker;
                marker2.Spawn();
                marker2.SetParent(tank, true);
                marker2.markerShopName = string.Format(config.purchasedTankInfo, profile.ToUpper(), player.displayName);
            }
            tank.SendNetworkUpdate();
            SendReply(player, Lang("BradleyPurchased", player.UserIDString, profile, PhoneController.PositionToGridCoord(startPosition), CalculateTime(config.purchases[profile].killTime), CalculateTime(config.purchases[profile].comingTime)));
            if (killTimer == null) killTimer = timer.Every(1, () => CheckTimers());
        }
        private void CheckTimers() {
            if (!bradleyTimers.Any() && !purchaseCooldowns.Any()) {
                killTimer.Destroy();
                killTimer = null;
                return;
            }
            foreach (var tank in bradleyTimers.Keys.ToList()) {
                if (tank == null) {
                    bradleyTimers.Remove(tank);
                    continue;
                }
                RoadBradleyController controller = tank.GetComponent<RoadBradleyController>();
                if (controller.ownerId == 0) continue;
                foreach (var fighter in controller.targets) {
                    BasePlayer player = BasePlayer.FindByID(fighter);
                    if (player == null) continue;
                    UpdateTimer(player, tank);
                }
                bradleyTimers[tank]--;
                if (bradleyTimers[tank] <= 0) {
                    BasePlayer player = BasePlayer.FindByID(controller.ownerId);
                    if (player != null) {
                        SendReply(player, Lang("FightLost", player.UserIDString));
                        CuiHelper.DestroyUi(player, "RoadBradleyUI_Timer");
                    }
                    foreach (var fighter in controller.targets) {
                        if (fighter == controller.ownerId) continue;
                        player = BasePlayer.FindByID(fighter);
                        if (player != null) {
                            SendReply(player, Lang("FightLost", player.UserIDString));
                            CuiHelper.DestroyUi(player, "RoadBradleyUI_Timer");
                        }
                    }
                    Effect.server.Run("assets/prefabs/weapons/beancan grenade/effects/beancan_grenade_explosion.prefab", tank.transform.position);
                    tank.Kill();
                    bradleyTimers.Remove(tank);
                }
            }
            foreach (var timer1 in purchaseCooldowns.ToList()) {
                foreach (var timer2 in timer1.Value.ToList()) {
                    purchaseCooldowns[timer1.Key][timer2.Key]--;
                    if (purchaseCooldowns[timer1.Key][timer2.Key] <= 0) {
                        purchaseCooldowns[timer1.Key].Remove(timer2.Key);
                        if (!purchaseCooldowns[timer1.Key].Any()) purchaseCooldowns.Remove(timer1.Key);
                    }
                }
            }
        }
        private static string CalculateTime(int time) {
            int seconds = time % 60;
            int minutes = (time - seconds) / 60;
            int remaingingMinutes = minutes % 60;
            int hours = (minutes - remaingingMinutes) / 60;
            if (hours == 0) return $"{minutes}m {seconds}s";
            else return $"{hours}h {remaingingMinutes}m";
        }
        private object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
            if (entity is BradleyAPC) {
                if (info.WeaponPrefab != null && info.WeaponPrefab.ShortPrefabName == "rocket_mlrs") return false;
                BradleyAPC apc = entity as BradleyAPC;
                BasePlayer player = info.InitiatorPlayer;
                if (info == null || player == null) return null;
                RoadBradleyController controller = apc.GetComponent<RoadBradleyController>();
                if (controller == null) return null;
                if (controller.targets.Contains(player.userID)) {
                    controller.damageDealt.TryAdd(player.userID, 0);
                    controller.damageDealt[player.userID] += info.damageTypes.Total();
                    controller.CheckMLRSSpawn();
                    return null;
                }
                if (controller.ownerId != 0 && config.purchases[controller.profile].ownerDamage) {
                    if ((controller.ownerId == player.userID) || (config.useFriends && Friends != null && AreFriends(controller.ownerId, player.userID)) || (config.useClans && Clans != null && Clans.Call<bool>("IsClanMember", controller.ownerId.ToString(), player.userID.ToString())) || (config.useTeams && player.Team != null && player.Team.members.Contains(controller.ownerId))) {
                        controller.targets.Add(player.userID);
                        if (!controller.damageDealt.Any()) CheckFirstDamage(apc, controller);
                        controller.damageDealt.TryAdd(player.userID, 0);
                        controller.damageDealt[player.userID] += info.damageTypes.Total();
                        controller.CheckMLRSSpawn();
                    }
                    else {
                        SendReply(player, Lang("CannotDamage", player.UserIDString));
                        return false;
                    }
                }
                else {
                    if (!controller.damageDealt.Any()) CheckFirstDamage(apc, controller);
                    controller.targets.Add(player.userID);
                    controller.damageDealt.TryAdd(player.userID, 0);
                    controller.damageDealt[player.userID] += info.damageTypes.Total();
                    controller.CheckMLRSSpawn();
                    return null;
                }
            }
            else if (config.callerDamage && info.WeaponPrefab != null && info.WeaponPrefab.ShortPrefabName == "maincannonshell") {
                float nearest = 10000;
                BradleyAPC apc = null;
                RoadBradleyController controller;
                /*if (entity is BasePlayer)
                {
					foreach (var bradley in roadBradleys)
					{
						float distance = Vector3.Distance(entity.transform.position, bradley.transform.position);
						if (distance < nearest)
						{
							nearest = distance;
							apc = bradley;
						}
					}
					if (apc == null) return null;
					controller = apc.GetComponent<RoadBradleyController>();
                    if (!controller.targets.Contains((entity as BasePlayer).userID))
                        return false;
                    else
                        return null;
                }*/
                if (entity.OwnerID == 0) return null;
                if (entity is BasePlayer) return null;
                foreach (var bradley in roadBradleys) {
                    float distance = Vector3.Distance(entity.transform.position, bradley.transform.position);
                    if (distance < nearest) {
                        nearest = distance;
                        apc = bradley;
                    }
                }
                if (apc == null) return null;
                controller = apc.GetComponent<RoadBradleyController>();
                if (controller == null || controller.ownerId == 0) return null;
                if (config.callerTeamCheck) {
                    RelationshipManager.PlayerTeam team = RelationshipManager.ServerInstance.FindPlayersTeam(entity.OwnerID);
                    if (team != null && team.members.Contains(controller.ownerId)) return null;
                }
                if (controller.targets.Contains(entity.OwnerID)) return null;
                BasePlayer player = BasePlayer.FindByID(controller.ownerId);
                controller.damageAuths++;
                if (controller.damageAuths % config.damageAuthsRemind == 0 && controller.damageAuths < config.damageAuths) SendReply(player, Lang("FightUnauthorizedInfo", player.UserIDString, controller.damageAuths, config.damageAuths));
                if (controller.damageAuths == config.damageAuths) {
                    bradleyTimers[apc] = 0;
                    SendReply(player, Lang("FightLostUnauthorized", player.UserIDString, config.damageAuths));
                }
                return false;
            }
            else if (info.WeaponPrefab != null && info.WeaponPrefab.ShortPrefabName == "rocket_mlrs") {
                if (!roadBradleys.Any()) return null;
                DecayEntity hitEntity = entity as DecayEntity;
                if (hitEntity == null) return null;
                BradleyAPC closest = null;
                float distance = float.MaxValue;
                foreach (var brad in roadBradleys) {
                    float bradDistance = Vector3.Distance(entity.transform.position, brad.transform.position);
                    if (bradDistance < distance) {
                        distance = bradDistance;
                        closest = brad;
                    }
                }
                if (distance > 100 && Vector3.Distance(tankDeathInfo.tankDeathLoc, entity.transform.position) < 100) {
                    if (hitEntity.OwnerID == tankDeathInfo.tankDeathOwner) return null;
                    BuildingPrivlidge cupboard = hitEntity.GetBuildingPrivilege();
                    if (cupboard == null) return null;
                    if (!cupboard.IsAuthed(tankDeathInfo.tankDeathOwner)) return false;
                    return null;
                }
                else if (distance > 150) return null;
                RoadBradleyController controller = closest.GetComponent<RoadBradleyController>();
                if (entity is BasePlayer && !controller.targets.Contains((entity as BasePlayer).userID)) return false;
                if (controller.ownerId == 0) return null;
                if (hitEntity.OwnerID == controller.ownerId) return null;
                BuildingPrivlidge tc = hitEntity.GetBuildingPrivilege();
                if (tc == null) return null;
                if (!tc.IsAuthed(controller.ownerId)) return false;
            }
            return null;
        }
        private object CanBeWounded(BasePlayer player, HitInfo info) {
            if (info == null) return null;
            return OnKilledByBradley(player, info, true);
        }
        private object OnPlayerDeath(BasePlayer player, HitInfo info) {
            if (player is NPCPlayer) return null;
            foreach (var tank in roadBradleys) {
                RoadBradleyController controller = tank?.GetComponent<RoadBradleyController>();
                if (controller == null) continue;
                controller.targets.Remove(player.userID);
            }
            if (config.enabledBags) return OnKilledByBradley(player, info);
            else return null;
        }
        private void OnEntityKill(BradleyAPC apc) {
            if (apc == null || apc.net == null) return;
            RoadBradleyController controller = apc.GetComponent<RoadBradleyController>();
            if (controller == null) return;
            if (controller.ownerId == 0) {
                int waitTime = Core.Random.Range(config.spawns[controller.roadInfo.routeName].respawnTime - config.spawns[controller.roadInfo.routeName].respawnTimeRandomize, config.spawns[controller.roadInfo.routeName].respawnTime + config.spawns[controller.roadInfo.routeName].respawnTimeRandomize);
                timer.Once(waitTime, () => SpawnDefaultRouteTank(controller.roadInfo.routeName));
            }
            controller.roadInfo.isNowOccupied = false;
            SphereEntity sphere = apc.GetParentEntity() as SphereEntity;
            if (sphere != null && !sphere.IsDestroyed) sphere.Kill();
            roadBradleys.Remove(apc);
            bradleyTimers.Remove(apc);
            currentBradleyOwners.Remove(apc);
        }
        private void OnEntityKill(HelicopterDebris debris) {
            SphereEntity sphere = debris.GetParentEntity() as SphereEntity;
            if (sphere != null && !sphere.IsDestroyed) sphere.Kill();
        }
        private void OnEntitySpawned(HelicopterDebris debris) {
            if (tankDeathInfo.tankDeathProfile == string.Empty) return;
            if (debris.ShortPrefabName == "servergibs_bradley") {
                NextTick(() => {
                    if (debris == null || debris.IsDestroyed) return;
                    if (config.profiles[tankDeathInfo.tankDeathProfile].gibsScale) {
                        float scale = config.profiles[tankDeathInfo.tankDeathProfile].tankScale;
                        if (scale != 1) {
                            Vector3 pos = debris.transform.position;
                            SphereEntity sphere = GameManager.server.CreateEntity("assets/prefabs/visualization/sphere.prefab", debris.transform.position) as SphereEntity;
                            sphere.Spawn();
                            debris.SetParent(sphere, true);
                            sphere.LerpRadiusTo(scale, 10000);
                        }
                    }
                    debris.InitializeHealth(config.profiles[tankDeathInfo.tankDeathProfile].gibsHealth, config.profiles[tankDeathInfo.tankDeathProfile].gibsHealt
// ... [Code preview truncated due to length. Full source in attached file] ...

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