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

FREE BaseBounty : 1.0.0 1.0.0

Нет прав для скачивания
C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using ConVar;
using HarmonyLib;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Oxide.Plugins;
using ProtoBuf;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using UnityEngine;
using static BuildingPrivlidge;
using static Carbon.Plugins.BaseBountyPerk;
using static UnityEngine.Rendering.PostProcessing.BloomRenderer;
namespace Carbon.Plugins {
    // Extension method to find the driver
    public static class VehicleExtensions {
        public static BasePlayer GetDriver(this BaseVehicle vehicle) {
            return vehicle?.mountPoints[0]?.mountable?.GetMounted() as BasePlayer;
        }
    }
    [Info("Base Bounty", "TTV OdsScott", "1.0.0")]
    [Description("Base bounty with raid protection")]
    public class BaseBounty : CarbonPlugin {
        public override bool AutoPatch => true;
        [PluginReference]
        public readonly Plugin ImageLibrary, Clans, SimpleStatus, DogTags, RaidHooks, DiscordThreads, NightTime, Kits, CarSpawnSettings;
        public static BaseBounty Instance;
        public ToolcupboardTracker ToolcupboardTracker;
        public BaseBountyData BaseBountyData;
        public const float HoursOfProtection = 4f;
        private Dictionary<ulong, BaseEntity> PlayerHorses = new Dictionary<ulong, BaseEntity>();
        private Dictionary<ulong, BaseEntity> PlayerCars = new Dictionary<ulong, BaseEntity>();
        private Dictionary<ulong, BaseEntity> PlayerMinis = new Dictionary<ulong, BaseEntity>();
        private bool _debugMode = true;
        private void Init() {
            Instance = this;
            BaseBountyData = BaseBountyData.Load();
            LoadImages();
            CreateStatus();
        }
        public static double HoursSinceWipe {
            get {
                DateTime wipeTime = SaveRestore.SaveCreatedTime;
                TimeSpan timeSinceWipe = DateTime.UtcNow - wipeTime;
                return timeSinceWipe.TotalHours;
            }
        }
        private void LoadImages() {
            if (ImageLibrary == null || !ImageLibrary.IsLoaded) {
                Debug("Image Library not found or unloaded.");
                return;
            }
            ImageLibrary.Call<bool>("AddImage", "https://rustwipeday.com/img/raidprotectionindicator.png", "SrpIndicatorIcon", 0UL);
            ImageLibrary.Call<bool>("AddImage", "https://rustwipeday.com/img/kits/dogtagneutral.png", "DogTagIcon", 0UL);
        }
        private void CreateStatus() {
            if (SimpleStatus == null || !SimpleStatus.IsLoaded) {
                Debug("Simple Status not found or unloaded.");
                return;
            }
            SimpleStatus.CallHook("CreateStatus", this, "raidprotection.status", Colors.COLOR_GREEN_DARK_LESS, "RAID PROTECTION", Colors.COLOR_GREEN, "0%", Colors.COLOR_GREEN, "SrpIndicatorIcon", Colors.COLOR_GREEN);
            SimpleStatus.CallHook("CreateStatus", this, "raidprotection.bounty", Colors.COLOR_GREY, "BASE BOUNTY", Colors.COLOR_BLACK, "0 Points", Colors.COLOR_BLACK, "itemid:1223900335", null);
        }
        private void OnServerInitialized() {
            ToolcupboardTracker = new ToolcupboardTracker(BaseBountyData);
            GameObject.FindObjectsOfType<BuildingPrivlidge>().ToList().ForEach((buildingPrivlidge) => ToolcupboardTracker.FindOrCreate(buildingPrivlidge));
            foreach (BasePlayer basePlayer in BasePlayer.activePlayerList) {
                ToolcupboardTracker.TrackBuildingPrivlidgeLoop(basePlayer);
            }
        }
        private void Unload() {
            OnServerSave();
            Instance = null;
        }
        // @TODO: Ideally I think we only want to gain base bounty when turning in white dog tags making it rare and hard to level.// void OnConsumedDogTag(BasePlayer player, Item activeItem) => BaseBountyData.AddBaseBountyPoint(player, 1);
        void OnAddBountyPoints(ulong playerId, int points, string type) {
            Puts(type);
            if (points <= 0 || type != "dogtagneutral") {
                return;
            }
            var player = BasePlayer.FindByID(playerId);
            if (player == null) {
                return;
            }
            BaseBountyData.AddBaseBountyPoint(player, points);
        }
        private bool IsNightTime() {
            // Utilize TimeOfDay plugin's TOD_Sky instance for accurate time checks.return TOD_Sky.Instance.Cycle.Hour < TOD_Sky.Instance.SunriseTime || TOD_Sky.Instance.Cycle.Hour > TOD_Sky.Instance.SunsetTime;
        }
        int OnHonorPointsAwarded(BasePlayer player, string victimName, bool isNpc, string victimRank, int points) {
            var highestHonorPerk = Instance.ToolcupboardTracker.GetHighestPerkLevel(player, BaseBountyPerk.BaseBountyPerkEnum.Honor);
            var newPoints = (int)(points * (1 + CalculatePercentage(highestHonorPerk, 100, 25) / 100));
            // Fix for night time double rates.if (IsNightTime()) { newPoints = newPoints * 2; }
            return newPoints;
        }
        /// <summary>
        ///  I did not like this
        /// </summary>
        /// <param name="basePlayer"></param>
        /// <param name="buildingPrivlidge"></param>
        /*void OnTakeBountyPoints(ulong playerId, int points)
        {
            var player = BasePlayer.FindByID(playerId);

            if (player == null)
            {
                return;
            }

            BaseBountyData.AddBaseBountyPoint(player, points);
        }*/
        private void OnLootEntity(BasePlayer basePlayer, BuildingPrivlidge buildingPrivlidge) => ToolcupboardTracker.OnOpenCupboard(basePlayer, buildingPrivlidge);
        private void OnLootEntityEnd(BasePlayer basePlayer, BuildingPrivlidge buildingPrivlidge) => ToolcupboardTracker.OnCloseCupboard(basePlayer, buildingPrivlidge);
        private void OnPlayerSleepEnded(BasePlayer basePlayer) {
            ToolcupboardTracker.TrackBuildingPrivlidgeLoop(basePlayer);
            var mainCupboard = ToolcupboardTracker.GetPlayerMainCupboard(basePlayer.userID);
            if (mainCupboard == null) {
                return;
            }
            mainCupboard.DepositPlayerHeldBounty(basePlayer);
        }
        object OnDispenserGather(ResourceDispenser dispenser, BaseEntity entity, Item item) {
            if (entity.ToPlayer() == null) {
                return null;
            }
            var highestLevel = Instance.ToolcupboardTracker.GetHighestPerkLevel(entity.ToPlayer(), BaseBountyPerk.BaseBountyPerkEnum.Gathering);
            if (highestLevel == 0) {
                return null;
            }
            item.amount += (int)(item.amount * (0.01 * CalculatePercentage(highestLevel, 200, 30)));
            return null;
        }
        private void OnEntityKill(BuildingPrivlidge buildingPrivlidge, HitInfo hitInfo) => ToolcupboardTracker.FindOrCreate(buildingPrivlidge).Kill(hitInfo);
        private void OnEntitySpawned(BuildingPrivlidge buildingPrivlidge) => ToolcupboardTracker.FindOrCreate(buildingPrivlidge);
        private object OnCupboardAuthorize(BuildingPrivlidge buildingPrivlidge, BasePlayer player) => ToolcupboardTracker.AuthorizePlayer(buildingPrivlidge, player);
        private object OnCupboardDeauthorize(BuildingPrivlidge buildingPrivlidge, BasePlayer player) => ToolcupboardTracker.DeauthorizePlayer(buildingPrivlidge, player);
        private void OnServerSave() => BaseBountyData.Save();
        private object OnEntityTakeDamage(DecayEntity entity, HitInfo info) => ProtectFromDamage(entity, info);
        private object OnEntityTakeDamage(IOEntity entity, HitInfo info) => ProtectFromDamage(entity, info);
        private object OnEntityTakeDamage(BaseResourceExtractor entity, HitInfo info) => ProtectFromDamage(entity, info);
        private object ProtectFromDamage(BaseCombatEntity entity, HitInfo info) {
            if (entity?.net == null || info == null) {
                return null;
            }
            BuildingPrivlidge buildingPrivlidge = entity.GetBuildingPrivilege();
            if (buildingPrivlidge == null) {
                return null;
            }
            Rust.DamageType majorityDamage = info.damageTypes.GetMajorityDamageType();
            if (majorityDamage == Rust.DamageType.Decay || majorityDamage == Rust.DamageType.ElectricShock) {
                return null;
            }
            ;
            BaseBountyCupboard baseBountyCupboard = ToolcupboardTracker.FindOrCreate(buildingPrivlidge);
            var protectionPercentage = baseBountyCupboard.ProtectionPercentage;
            if (protectionPercentage >= 100) {
                return true;
            }
            else {
                info.damageTypes.ScaleAll((float)(1 - (protectionPercentage / 100)));
            }
            return null;
        }
        object CanBuild(Planner planner, Construction prefab, Construction.Target target) {
            var player = target.player;
            List<DroppedItemContainer> droppedItemContainers = Facepunch.Pool.GetList<DroppedItemContainer>();
            var obb = target.player.WorldSpaceBounds();
            Vis.Entities(obb.position, 16f + obb.extents.magnitude, droppedItemContainers);
            for (int i = 0; i < droppedItemContainers.Count; i++) {
                DroppedItemContainer droppedItemContainer = droppedItemContainers[i];
                if (ToolcupboardTracker.BaseBountyClaimContainer.ContainsKey(droppedItemContainer)) {
                    player.ChatMessage($"<color=#c45508>[RustWipeDay]</color>: You can not build in this area while a base bounty is still unclaimed.");
                    return false;
                }
            }
            Facepunch.Pool.FreeList(ref droppedItemContainers);
            return null;
        }
        object CanLootEntity(BasePlayer player, DroppedItemContainer droppedItemContainer) => ToolcupboardTracker.OnLootClaimContainer(player, droppedItemContainer);
#region Fuel System Perk Handling
        /// <summary>
        /// Tracks active engine perks for vehicles by storing fuel storage IDs, driver IDs, and perk levels./// </summary>
        private Dictionary<ulong, (ulong driverId, int perkLevel)> FuelStorageEnginePerks = new Dictionary<ulong, (ulong, int)>();
#endregion
#region Engine Event Handlers
        /// <summary>
        /// Called when a vehicle engine starts.Registers the driver and their highest fuel perk level./// </summary>
        /// <param name="vehicle">The vehicle whose engine is starting.</param>
        /// <param name="driver">The player driving the vehicle.</param>
        /// <returns>Null to allow normal engine start behavior.</returns>
        private object OnEngineStart(BaseVehicle vehicle, BasePlayer driver) {
            if (vehicle == null || driver == null) {
                return null;
                // No valid vehicle or driver
            }
            var fuelSystem = vehicle.GetFuelSystem();
            if (fuelSystem == null || !ToolcupboardTracker.GetPlayerBaseBountyToolcupboards(driver.userID).Any()) {
                return null;
                // No fuel system or no eligible cupboards for the driver
            }
            // Retrieve the highest fuel perk level for the driver
            var highestFuelLevel = ToolcupboardTracker.GetHighestPerkLevel(driver, BaseBountyPerk.BaseBountyPerkEnum.Fuel);
            var fuelStorageId = fuelSystem.GetInstanceID().Value;
            // Update the perks tracking dictionary
            FuelStorageEnginePerks[fuelStorageId] = (driver.userID, highestFuelLevel);
            return null;
        }
        /// <summary>
        /// Called when a vehicle engine stops.Cleans up any associated engine perks./// </summary>
        /// <param name="vehicle">The vehicle whose engine is stopping.</param>
        /// <param name="driver">The player driving the vehicle.</param>
        /// <returns>Null to allow normal engine stop behavior.</returns>
        private object OnEngineStop(BaseVehicle vehicle, BasePlayer driver) {
            if (vehicle == null) {
                return null;
                // No valid vehicle
            }
            var fuelSystem = vehicle.GetFuelSystem();
            if (fuelSystem == null) {
                return null;
                // No fuel system
            }
            var fuelStorageId = fuelSystem.GetInstanceID().Value;
            FuelStorageEnginePerks.Remove(fuelStorageId);
            // Clean up perks on engine stop
            return null;
        }
#endregion
#region Fuel Efficiency Hook
        /// <summary>
        /// Modifies fuel usage based on the player's fuel perk level./// </summary>
        /// <param name="fuelSystem">The fuel system of the vehicle.</param>
        /// <param name="fuelContainer">The container holding the vehicle's fuel.</param>
        /// <param name="seconds">The duration for which fuel is being consumed.</param>
        /// <param name="fuelUsedPerSecond">The base amount of fuel consumed per second.</param>
        /// <returns>Null to allow normal fuel consumption behavior, or 0 to prevent consumption.</returns>
        private object CanUseFuel(EntityFuelSystem fuelSystem, StorageContainer fuelContainer, float seconds, float fuelUsedPerSecond) {
            if (fuelSystem == null || fuelContainer == null) {
                return null;
                // Invalid fuel system or container
            }
            var fuelStorageId = fuelSystem.fuelStorageInstance.uid.Value;
            if (!FuelStorageEnginePerks.TryGetValue(fuelStorageId, out var perkData)) {
                return null;
                // No perks registered for this fuel storage
            }
            var (driverId, fuelPerk) = perkData;
            // Apply the fuel perk bonus to reduce consumption
            var fuelBonus = (seconds * fuelUsedPerSecond) * (fuelPerk * 0.01f);
            fuelSystem.pendingFuel -= fuelBonus;
            // Reduce pending fuel consumption
            return null;
        }
#endregion
        private (int baseXp, int baseXpRequired, int baseLevel) GetPlayerBaseLevel(ulong userId) {
            var cupboard = ToolcupboardTracker.GetPlayerMainCupboard(userId);
            try {
                return (cupboard.Bounty - cupboard.LevelXp, cupboard.NextLevelXp - cupboard.LevelXp, cupboard.Level);
            }
            catch (Exception e) {
                return (0, 0, 0);
            }
        }
        [ChatCommand("basebounty")]
        private void BaseBountyCommand(BasePlayer player, string command, string[] args) {
            var amount = BaseBountyData.GetBaseBountyPoints(player.userID);
            SendReply(player, $"<color=#c45508>[RustWipeDay]</color>: You currently have {amount} base bounty points." );
        }
        [ConsoleCommand("basebounty.claim")]
        private void Command_BaseBounty_Claim(IPlayer player, string command, string[] args) {
            var userId = ulong.Parse(player.Id);
            var basePlayer = BasePlayer.FindByID(userId);
            if (basePlayer == null || ToolcupboardTracker.GetPlayerMainCupboard(userId) == null) {
                return;
            }
            ulong privId = Convert.ToUInt64(args[0]);
            var baseBountyCupboard = ToolcupboardTracker.Find(privId);
            if (baseBountyCupboard == null ) {
                return;
            }
            uint perkId = Convert.ToUInt32(args[1]);
            var perk = BaseBountyPerk.BaseBountyPerks[(int)perkId];
            if (baseBountyCupboard.Data.BaseBountyPerkLevel[perkId] + 1 > perk.MaxLevel) {
                return;
            }
            var cost = perk.Cost;
            if (!baseBountyCupboard.SpendBounty(cost)) {
                basePlayer.ChatMessage($"<color=#c45508>[RustWipeDay]</color>: Not enough base bounty points to claim the {perk.Title} base perk.");
                return;
            }
            baseBountyCupboard.Data.BaseBountyPerkLevel[perkId]++;
            if (perkId == (int)BaseBountyPerk.BaseBountyPerkEnum.TurretLimit) {
                baseBountyCupboard.UpdateSentryInterference();
            }
            baseBountyCupboard.UpdateMapMarker();
            basePlayer.ChatMessage($"<color=#c45508>[RustWipeDay]</color>: You have claimed the {perk.Title} base perk for {cost} bounty points.Your base bounty has increased to {baseBountyCupboard.Bounty}.");
            Command_BaseBounty_Panel(player, command, new string[] {
                args[0]
            }
            );
        }
        [ConsoleCommand("basebounty.panel.close")]
        private void Command_BaseBounty_Panel_Close(IPlayer player, string command, string[] args) {
            var basePlayer = BasePlayer.FindByID(ulong.Parse(player.Id));
            if (basePlayer == null) {
                return;
            }
            CuiHelper.DestroyUi(basePlayer, "BaseBountyPanel");
        }
        [Command("basebounty.panel")]
        private void Command_BaseBounty_Panel(IPlayer player, string command, string[] args) {
            var basePlayer = BasePlayer.FindByID(ulong.Parse(player.Id));
            if (basePlayer == null) {
                return;
            }
            var baseBountyCupboard = ToolcupboardTracker.GetPlayerMainCupboard(basePlayer.userID);
            if (baseBountyCupboard == null) {
                return;
            }
            basePlayer.EndLooting();
            basePlayer.ClientRPCPlayer(null, basePlayer, "OnDied");
            Gui.OpenBaseBountyPanel(basePlayer, baseBountyCupboard);
        }
        // This command spawns or claims a horse for the player.[ChatCommand("myhorse")]
        private void MyHorseCommand(BasePlayer player, string command, string[] args) {
            // Check for level requirements first
            var mainCupboard = ToolcupboardTracker.GetPlayerMainCupboard(player.userID);
            if (mainCupboard == null) {
                SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You do not have a main cupboard set.Set one using /basebounty.setmain.");
                return;
            }
            int animalPerkLevel = mainCupboard.Level;
            if (animalPerkLevel < 5) {
                SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You must have a base bounty level of at least 5 to use this command.");
                return;
            }
            var mountedEntity = player.GetMountedVehicle();
            // Check if the player is mounted on a horse
            if (mountedEntity is BaseMountable mountedHorse && mountedHorse.ShortPrefabName.Contains("horse")) {
                if (args.Length > 0 && args[0].ToLower() == "claim") {
                    // Claim the mounted horse
                    if (mountedHorse.OwnerID != 0 || PlayerHorses.ContainsValue(mountedHorse)) {
                        SendReply(player, "<color=#c45508>[RustWipeDay]</color>: This horse is already owned.");
                        return;
                    }
                    mountedHorse.OwnerID = player.userID;
                    // Assign ownership
                    PlayerHorses[player.userID] = mountedHorse;
                    mountedHorse.gameObject.AddComponent<TeleportCooldown>().Initialize(180f);
                    // Apply cooldown
                    SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You have claimed this horse.");
                    return;
                }
                else {
                    // Inform the player about /myhorse claim
                    SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You are currently on a horse.Use <color=#00ff00>/myhorse claim</color> to claim it if it's unowned.");
                    return;
                }
            }
            // Check for existing horse owned by the player
            if (PlayerHorses.TryGetValue(player.userID, out BaseEntity existingHorse) && existingHorse.IsValid()) {
                // Teleport the horse to the player's location
                if (existingHorse.GetComponent<TeleportCooldown>() != null) {
                    SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You must wait before teleporting your horse again.");
                    return;
                }
                existingHorse.transform.position = FindSafeSpawnPosition(player.transform.position + player.transform.forward * 2f, 20f);
                existingHorse.SendNetworkUpdate();
                existingHorse.gameObject.AddComponent<TeleportCooldown>().Initialize(180f);
                // 3-minute cooldown
                SendReply(player, "<color=#c45508>[RustWipeDay]</color>: Your horse has been teleported to a safe location near you.");
                return;
            }
            // Find a safe spawn position for the horse
            Vector3 spawnPosition = FindSafeSpawnPosition(player.transform.position + player.transform.forward * 5f, 20f);
            if (spawnPosition == Vector3.zero) {
                SendReply(player, "<color=#c45508>[RustWipeDay]</color>: Unable to find a safe location to spawn your horse.Please try again.");
                return;
            }
            // Spawn the horse
            BaseEntity horse = GameManager.server.CreateEntity("assets/rust.ai/nextai/testridablehorse.prefab", spawnPosition, Quaternion.identity);
            if (horse == null) {
                SendReply(player, "<color=#c45508>[RustWipeDay]</color>: Failed to spawn the horse.Please try again.");
                return;
            }
            horse.Spawn();
            horse.OwnerID = player.userID;
            PlayerHorses[player.userID] = horse;
            SendReply(player, "<color=#c45508>[RustWipeDay]</color>: Your horse has been granted.");
        }
        // This command spawns or claims a modular car for the player.[ChatCommand("mycar")]
        private void MyCarCommand(BasePlayer player, string command, string[] args) {
            // Check for level requirements first
            var mainCupboard = ToolcupboardTracker.GetPlayerMainCupboard(player.userID);
            if (mainCupboard == null) {
                SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You do not have a main cupboard set.Set one using /basebounty.setmain.");
                return;
            }
            int vehiclePerkLevel = mainCupboard.Level;
            if (vehiclePerkLevel < 10) {
                SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You must have a base bounty level of at least 10 to use this command.");
                return;
            }
            var mountedVehicle = player.GetMountedVehicle();
            // Check if the player is mounted in a vehicle
            if (mountedVehicle) {
                if (args.Length > 0 && args[0].ToLower() == "claim") {
                    // Claim the mounted modular car
                    if (mountedVehicle.OwnerID != 0 || PlayerCars.ContainsValue(mountedVehicle)) {
                        SendReply(player, "<color=#c45508>[RustWipeDay]</color>: This vehicle is already owned.");
                        return;
                    }
                    if (IsFlyingVehicle(mountedVehicle)) {
                        SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You can only claim ground vehicles.");
                        return;
                    }
                    mountedVehicle.OwnerID = player.userID;
                    // Assign ownership
                    PlayerCars[player.userID] = mountedVehicle;
                    mountedVehicle.gameObject.AddComponent<TeleportCooldown>().Initialize(180f);
                    // Apply cooldown
                    SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You have claimed this vehicle.");
                    return;
                }
                else {
                    // Inform the player about /mycar claim
                    SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You are currently in a vehicle.Use <color=#00ff00>/mycar claim</color> to claim it if it's unowned.");
                    return;
                }
            }
            // Check for existing car owned by the player
            if (PlayerCars.TryGetValue(player.userID, out BaseEntity existingCar) && existingCar.IsValid()) {
                // Teleport the car to the player's location
                if (existingCar.GetComponent<TeleportCooldown>() != null) {
                    SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You must wait before teleporting your vehicle again.");
                    return;
                }
                existingCar.transform.position = FindSafeSpawnPosition(player.transform.position + player.transform.forward * 2f, 20f);
                existingCar.SendNetworkUpdate();
                existingCar.gameObject.AddComponent<TeleportCooldown>().Initialize(180f);
                // 3-minute cooldown
                SendReply(player, "<color=#c45508>[RustWipeDay]</color>: Your vehicle has been teleported to a safe location near you.");
                return;
            }
            // Find a safe spawn position for the car
            Vector3 spawnPosition = FindSafeSpawnPosition(player.transform.position + player.transform.forward * 5f, 20f);
            if (spawnPosition == Vector3.zero) {
                SendReply(player, "<color=#c45508>[RustWipeDay]</color>: Unable to find a safe location to spawn your vehicle.Please try again.");
                return;
            }
            // Spawn the car
            ModularCar car = GameManager.server.CreateEntity("assets/content/vehicles/modularcar/4module_car_spawned.entity.prefab", spawnPosition, Quaternion.identity) as ModularCar;
            if (car == null) {
                SendReply(player, "<color=#c45508>[RustWipeDay]</color>: Failed to spawn the vehicle.Please try again.");
                return;
            }
            car.Spawn();
            CarSpawnSettings.Call("ProcessCar", car);
            // Equip, repair, and fuel the car
            car.OwnerID = player.userID;
            PlayerCars[player.userID] = car;
            SendReply(player, "<color=#c45508>[RustWipeDay]</color>: Your vehicle has been granted.");
        }
        // This command spawns a minicopter for the player.[ChatCommand("mymini")]
        private void MyMiniCommand(BasePlayer player, string command, string[] args) {
            // Check for level requirements first
            var mainCupboard = ToolcupboardTracker.GetPlayerMainCupboard(player.userID);
            if (mainCupboard == null) {
                SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You do not have a main cupboard set.Set one using /basebounty.setmain.");
                return;
            }
            int vehiclePerkLevel = mainCupboard.Level;
            if (vehiclePerkLevel < 20) {
                SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You must have a base bounty level of at least 20 to use this command.");
                return;
            }
            var mountedVehicle = player.GetMountedVehicle();
            // Check if the player is mounted in a vehicle
            if (mountedVehicle) {
                if (args.Length > 0 && args[0].ToLower() == "claim") {
                    // Claim the mounted flying vehicle
                    if (mountedVehicle.OwnerID != 0 || PlayerMinis.ContainsValue(mountedVehicle)) {
                        SendReply(player, "<color=#c45508>[RustWipeDay]</color>: This vehicle is already owned.");
                        return;
                    }
                    if (!IsFlyingVehicle(mountedVehicle)) {
                        SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You can only claim flying vehicles.");
                        return;
                    }
                    mountedVehicle.OwnerID = player.userID;
                    // Assign ownership
                    PlayerMinis[player.userID] = mountedVehicle;
                    mountedVehicle.gameObject.AddComponent<TeleportCooldown>().Initialize(180f);
                    // Apply cooldown
                    SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You have claimed this vehicle.");
                    return;
                }
                else {
                    // Inform the player about /mymini claim
                    SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You are currently in a vehicle.Use <color=#00ff00>/mymini claim</color> to claim it if it's unowned.");
                    return;
                }
            }
            // Check for existing minicopter owned by the player
            if (PlayerMinis.TryGetValue(player.userID, out BaseEntity existingMini) && existingMini.IsValid()) {
                // Teleport the minicopter to the player's location
                if (existingMini.GetComponent<TeleportCooldown>() != null) {
                    SendReply(player, "<color=#c45508>[RustWipeDay]</color>: You must wait before teleporting your vehicle again.");
                    return;
                }
                existingMini.transform.position = FindSafeSpawnPosition(player.transform.position + player.transform.forward * 2f, 20f);
                existingMini.SendNetworkUpdate();
                existingMini.gameObject.AddComponent<TeleportCooldown>().Initialize(180f);
                // 3-minute cooldown
                SendReply(player, "<color=#c45508>[RustWipeDay]</color>: Your minicopter has been teleported to a safe location near you.");
                return;
            }
            // Find a safe spawn position for the minicopter
            Vector3 spawnPosition = FindSafeSpawnPosition(player.transform.position + player.transform.forward * 5f, 20f);
            if (spawnPosition == Vector3.zero) {
                SendReply(player, "<color=#c45508>[RustWipeDay]</color>: Unable to find a safe location to spawn your vehicle.Please try again.");
                return;
            }
            // Spawn the minicopter
            BaseEntity mini = GameManager.server.CreateEntity("assets/content/vehicles/minicopter/minicopter.entity.prefab", spawnPosition, Quaternion.identity);
            if (mini == null) {
                SendReply(player, "<color=#c45508>[RustWipeDay]</color>: Failed to spawn the minicopter.Please try again.");
                return;
            }
            mini.Spawn();
            mini.OwnerID = player.userID;
            PlayerMinis[player.userID] = mini;
            SendReply(player, "<color=#c45508>[RustWipeDay]</color>: Your minicopter has been granted.");
        }
#region Helper Methods
        /// <summary>
        /// Finds a safe spawn position within a defined radius./// Ensures the position is free of players, entities, and water./// </summary>
        /// <param name="startPosition">The initial position to search around.</param>
        /// <param name="maxRadius">The maximum radius to search.</param>
        /// <returns>A safe position or Vector3.zero if none is found.</returns>
        private Vector3 FindSafeSpawnPosition(Vector3 startPosition, float maxRadius) {
            const int maxAttempts = 15;
            const float safeDistance = 5f;
            for (int i = 0; i < maxAttempts; i++) {
                Vector3 potentialPosition = startPosition + UnityEngine.Random.insideUnitSphere * maxRadius;
                potentialPosition.y = TerrainMeta.HeightMap.GetHeight(potentialPosition);
                if (IsPositionSafe(potentialPosition, safeDistance)) {
                    return potentialPosition;
                }
            }
            return Vector3.zero;
            // No safe position found
        }
        /// <summary>
        /// Checks if a position is safe for spawning a car./// Ensures no nearby players, entities, or water./// </summary>
        /// <param name="position">The position to check.</param>
        /// <param name="safeDistance">The minimum safe distance from other entities or players.</param>
        /// <returns>True if the position is safe; otherwise, false.</returns>
        private bool IsPositionSafe(Vector3 position, float safeDistance) {
            // Ensure no players are nearby
            foreach (BasePlayer player in BasePlayer.activePlayerList) {
                if (player.Distance(position) < safeDistance) {
                    return false;
                }
            }
            // Ensure no significant entities are nearby
            var entities = new List<BaseEntity>();
            Vis.Entities(position, safeDistance, entities, LayerMask.GetMask("Default", "Deployed", "Construction"));
            foreach (BaseEntity entity in entities) {
                if (entity != null && entity is BaseCombatEntity) {
                    return false;
                }
            }
            // Ensure the position is on solid ground and not in water
            return UnityEngine.Physics.Raycast(position + Vector3.up * 0.5f, Vector3.down, out RaycastHit hit, safeDistance, LayerMask.GetMask("Terrain")) && hit.collider != null;
        }
        /// <summary>
        /// Determines if a vehicle is a flying vehicle./// </summary>
        /// <param name="vehicle">The vehicle to check.</param>
        /// <returns>True if the vehicle can fly; otherwise, false.</returns>
        private bool IsFlyingVehicle(BaseVehicle vehicle) {
            // Check for specific flying vehicle types (e.g., Minicopter, Scrap Transport Helicopter)
            return vehicle.PrefabName.Contains("minicopter") || vehicle.PrefabName.Contains("scraptransport");
        }
#endregion
        private class TeleportCooldown : MonoBehaviour {
            private float cooldownTime;
            public void Initialize(float cooldown) {
                cooldownTime = UnityEngine.Time.time + cooldown;
                Invoke(nameof(RemoveCooldown), cooldown);
            }
            private void RemoveCooldown() {
                Destroy(this);
            }
        }
        [Command("basebounty.setmain")]
        private void Command_BaseBounty_SetMain(IPlayer player, string command, string[] args) {
            var playerId = ulong.Parse(player.Id);
            var basePlayer = BasePlayer.FindByID(ulong.Parse(player.Id));
            ulong privId = Convert.ToUInt64(args[0]);
            var baseBountyCupboard = ToolcupboardTracker.Find(privId);
            if (baseBountyCupboard == null) {
                return;
            }
            var hasMainCupboard = ToolcupboardTracker.GetPlayerMainCupboard(basePlayer.userID) != null;
            Debug($"Main cupboard: {hasMainCupboard}");
            if (hasMainCupboard) {
                return;
            }
            var protectedCupboard = ToolcupboardTracker.Find(privId);
            if (protectedCupboard == null || protectedCupboard.Data.IsRemoved) {
                return;
            }
            Debug($"Checking ownership {playerId}");
            if (protectedCupboard.Data.AllOwnerIds.Contains(playerId)) {
                Debug($"Setting main");
                protectedCupboard.Data.IsMainCupboard = true;
                protectedCupboard.Data.PlayerRelations.ForEach((relationId) => {
                    var relationPlayer = BasePlayer.FindByID(relationId);
                    if (relationPlayer == null) {
                        return;
                    }
                    relationPlayer.ChatMessage($"<color=#c45508>[RustWipeDay]</color>: Your main cupboard has been set and raid protection has been enabled for this wipe.");
                    protectedCupboard.DepositPlayerHeldBounty(relationPlayer);
                }
                );
                CuiHelper.DestroyUi(basePlayer, "RaidProtectionControl");
                Gui.CreateRaidProtectionButton(basePlayer, privId, true);
                return;
            }
            //basePlayer.EndLooting();
            //basePlayer.ClientRPCPlayer(null, basePlayer, "OnDied");
            //OpenBaseBountyPanel(basePlayer, Convert.ToUInt64(args[0]));
        }
#region Harmony Patches
        [HarmonyPatch(typeof(VehicleEngineController<GroundVehicle>), "TickFuel")]
        public static class TickFuelPatch_GroundVehicle {
            // Prefix method to adjust fuel consumption before the original method executes
            static void Prefix(ref float fuelPerSecond, VehicleEngineController<GroundVehicle> __instance) {
                // Validate that the engine is associated with a vehicle
                if (__instance.owner is GroundVehicle vehicle) {
                    // Attempt to find the driver (BasePlayer) for the vehicle
                    BasePlayer driver = vehicle.GetDriver() as BasePlayer;
                    if (driver != null) {
                        // Get the player's fuel perk level
                        int fuelPerkLevel = GetPlayerFuelPerkLevel(driver);
                        if (fuelPerkLevel > 0) {
                            // Reduce fuel consumption by a percentage based on the perk level
                            float multiplier = 1f - (fuelPerkLevel * 0.01f);
                            // Example: Each level reduces fuel by 1%
                            fuelPerSecond *= Mathf.Clamp(multiplier, 0.1f, 1f);
                            // Clamp multiplier to prevent zero or negative fuel usage
                        }
                    }
                }
            }
            // Example method to retrieve the player's fuel perk level
            static int GetPlayerFuelPerkLevel(BasePlayer basePlayer) {
                // Replace with your logic to fetch the player's fuel perk level
                return Instance.ToolcupboardTracker.GetHighestPerkLevel(basePlayer, BaseBountyPerk.BaseBountyPerkEnum.Fuel);
                //return 30; // ToolcupboardTracker.GetPlayerBaseBountyPerkLevel(userID, );
            }
        }
        [HarmonyPatch(typeof(VehicleEngineController<PlayerHelicopter>), "TickFuel")]
        public static class TickFuelPatch_PlayerHelicopter {
            // Prefix method to adjust fuel consumption before the original method executes
            static void Prefix(ref float fuelPerSecond, VehicleEngineController<PlayerHelicopter> __instance) {
                // Validate that the engine is associated with a vehicle
                if (__instance.owner is PlayerHelicopter vehicle) {
                    // Attempt to find the driver (BasePlayer) for the vehicle
                    BasePlayer driver = vehicle.GetDriver();
                    if (driver != null) {
                        // Get the player's fuel perk level
                        int fuelPerkLevel = GetPlayerFuelPerkLevel(driver);
                        if (fuelPerkLevel > 0) {
                            // Reduce fuel consumption by a percentage based on the perk level
                            float multiplier = 1f - (fuelPerkLevel * 0.01f);
                            // Example: Each level reduces fuel by 1%
                            fuelPerSecond *= Mathf.Clamp(multiplier, 0.1f, 1f);
                            // Clamp multiplier to prevent zero or negative fuel usage
                        }
                    }
                }
            }
            // Example method to retrieve the player's fuel perk level
            static int GetPlayerFuelPerkLevel(BasePlayer basePlayer) {
                // Replace with your logic to fetch the player's fuel perk level
                return Instance.ToolcupboardTracker.GetHighestPerkLevel(basePlayer, BaseBountyPerk.BaseBountyPerkEnum.Fuel);
            }
        }
        [HarmonyPatch(typeof(BuildingPrivlidge), "CalculateBuildingTaxRate", new Type[] {
        }
        )] public class BuildingPrivlidge_CalculateBuildingTaxRate {
            private static bool Prefix(BuildingPrivlidge __instance, ref float __result) {
                BuildingManager.Building building = __instance.GetBuilding();
                if (building == null) {
                    __result = Instance.GetBuildingPriviledgeUpkeepRate(__instance, ConVar.Decay.bracket_0_costfraction);
                    return false;
                }
                if (!building.HasBuildingBlocks()) {
                    __result = Instance.GetBuildingPriviledgeUpkeepRate(__instance, ConVar.Decay.bracket_0_costfraction);
                    return false;
                }
                int count = building.buildingBlocks.Count;
                int num = count;
                for (int i = 0; i < upkeepBrackets.Length; i++) {
                    UpkeepBracket upkeepBracket = upkeepBrackets[i];
                    upkeepBracket.blocksTaxPaid = 0f;
                    if (num > 0) {
                        int num2 = 0;
                        num2 = ((i != upkeepBrackets.Length - 1) ? Mathf.Min(num, upkeepBrackets[i].objectsUpTo) : num);
                        num -= num2;
                        upkeepBracket.blocksTaxPaid = (float)num2 * upkeepBracket.fraction;
                    }
                }
                float num3 = 0f;
                for (int j = 0; j < upkeepBrackets.Length; j++) {
                    UpkeepBracket upkeepBracket2 = upkeepBrackets[j];
                    if (!(upkeepBracket2.blocksTaxPaid > 0f)) {
                        break;
                    }
                    num3 += upkeepBracket2.blocksTaxPaid;
                }
                __result = Instance.GetBuildingPriviledgeUpkeepRate(__instance, num3 / (float)count);
                return false;
            }
        }
        /* [HarmonyPatch(typeof(BasePlayer), "SendMarkersToClient", new Type[] { })]
        public class BasePlayer_SendMarkersToClient
        {
            private static bool Prefix(BasePlayer __instance)
            {
                MapNoteList mapNoteList = Facepunch.Pool.Get<MapNoteList>();
                mapNoteList.notes = Facepunch.Pool.GetList<MapNote>();
                if (__instance.ServerCurrentDeathNote != null)
                {
                    mapNoteList.notes.Add(__instance.ServerCurrentDeathNote);
                }
                if (__instance.State.pointsOfInterest != null)
                {
                    mapNoteList.notes.AddRange(__instance.State.pointsOfInterest);
                }

                mapNoteList.notes.AddRange(Instance.ToolcupboardTracker.BaseBounties.Values.Where(tc => tc.Bounty >= 150 && tc.MapNote != null).OrderByDescending(tc => tc.Bounty).Select(tc => tc.MapNote).Take(3));
                __instance.ClientRPCPlayer(null, __instance, "Client_ReceiveMarkers", mapNoteList);
                mapNoteList.notes.Clear();
                return false;
            }
        } */
        [HarmonyPatch(typeof(AutoTurret), "UpdateInterference", new Type[] {
        }
        )] public class AutoTurret_UpdateInterference {
            private static bool Prefix(AutoTurret __instance) {
                if (!__instance.IsOn()) {
                    return false;
                }
                float num = 0f;
                foreach (AutoTurret nearbyTurret in __instance.nearbyTurrets) {
                    if (!nearbyTurret.isClient && nearbyTurret.IsValid() && nearbyTurret.gameObject.activeSelf && !nearbyTurret.EqualNetID(__instance.net.ID) && nearbyTurret.IsOn() && !nearbyTurret.HasInterference()) {
                        num += 1f;
                    }
                }
                __instance.SetFlag(BaseEntity.Flags.OnFire, num >= Instance.GetSentryInterference(__instance));
                return false;
            }
        }
        [HarmonyPatch(typeof(ItemCrafter), "ServerUpdate")]
        public class ItemCrafter_ServerUpdate {
            private static bool Prefix(ItemCrafter __instance, float delta) {
                var player = __instance.owner;
                var highestCraftingLevel = Instance.ToolcupboardTracker.GetHighestPerkLevel(player, BaseBountyPerk.BaseBountyPerkEnum.Crafting);
                if (highestCraftingLevel == 0) {
                    return true;
                }
                if (__instance.queue.Count == 0) {
                    return false;
                }
                ItemCraftTask value = __instance.queue.First.Value;
                if (value.cancelled) {
                    __instance.owner.Command("note.craft_done", value.taskUID, 0);
                    __instance.queue.RemoveFirst();
                    return false;
                }
                float currentCraftLevel = __instance.owner.currentCraftLevel;
                if (value.endTime > UnityEngine.Time.realtimeSinceStartup) {
                    return false;
                }
                if (value.endTime == 0f) {
                    float scaledDuration = Math.Max(ItemCrafter.GetScaledDuration(value.blueprint, currentCraftLevel, __instance.owner.IsInTutorial) * (float)(1 - (0.02 * highestCraftingLevel)), 0f);
                    value.endTime = UnityEngine.Time.realtimeSinceStartup + scaledDuration;
                    value.workbenchEntity = __instance.owner.GetCachedCraftLevelWorkbench();
                    if (__instance.owner != null) {
                        __instance.owner.Command("note.craft_start", value.taskUID, scaledDuration, value.amount);
                        if (__instance.owner.IsAdmin && Craft.instant) {
                            value.endTime = UnityEngine.Time.realtimeSinceStartup + 1f;
                        }
                    }
                }
                else {
                    __instance.FinishCrafting(value);
                    if (value.amount <= 0) {
                        __instance.queue.RemoveFirst();
                    }
                    else {
                        value.endTime = 0f;
                    }
                }
                return false;
            }
        }
        private float GetBuildingPriviledgeUpkeepRate(BuildingPrivlidge buildingPrivlidge, float cost) {
            if (buildingPrivlidge == null) {
                return cost;
            }
            BaseBountyCupboard baseBountyCupboard = ToolcupboardTracker.FindOrCreate(buildingPrivlidge);
            var level = baseBountyCupboard.Level;
            return cost * (float)(1 - level * 0.02);
        }
        private float GetSentryInterference(AutoTurret autoTurret) {
            var buildingPrivlidge = autoTurret.GetNearestBuildingPrivledge();
            var sentryInterference = Sentry.maxinterference;
            if (buildingPrivlidge == null) {
                return sentryInterference;
            }
            BaseBountyCupboard baseBountyCupboard = ToolcupboardTracker.FindOrCreate(buildingPrivlidge);
            var level = baseBountyCupboard.Level;
            var limit = CalculateTurretLimit(level);
            return limit + sentryInterference;
        }
#endregion
        public void Debug(string message) {
            if (_debugMode) {
                Puts(message);
            }
        }
 
// ... [Code preview truncated due to length. Full source in attached file] ...

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