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

FREE MotorcycleCombat : 1.1.0 1.1.0

Нет прав для скачивания
C#:
using System;
using System.Collections.Generic;
using Oxide.Core;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using Facepunch;
using Network;
//  ____  _       _ _       
// / ___(_) __ _(_) | ___  
// \___ \| |/ _` | | |/ _ \ 
//  ___) | | (_| | | | (_) |
// |____/|_|\__, |_|_|\___/ 
//          |___/             
// ☽✧✵✧✵✧✵✧✵✧✵✧✵✧☾
// ✦    RUST PLUGINS   ✦
// ✦     https://sigilo.dev    ✦
// ☽✧✵✧✵✧✵✧✵✧✵✧✵✧☾
namespace Oxide.Plugins
{
    [Info("MotorcycleCombat", "Sigilo", "1.1.0")]
    [Description("Adds boost, jump, and minigun to motorcycles with crash explosion.")]
    public class MotorcycleCombat : RustPlugin
    {
        private class PluginConfig
        {
            public bool RequirePermission = true;
            public float BoostThrustMultiplier = 0.5f;
            public float BoostFuelDuration = 1.0f;
            public float BoostRechargeTime = 10.0f;
            public string BoostActivateSound = "assets/prefabs/npc/patrol helicopter/effects/rocket_fire.prefab";
            public string BoostLoopEffect = "assets/prefabs/ammo/rocket/rocket_basic.prefab";
            public float JumpForce = 15.0f;
            public float JumpCooldown = 3.0f;
            public string JumpSound = "assets/prefabs/locks/keypad/effects/lock.code.lock.prefab";
            public float MinigunDamage = 15.0f;
            public float MinigunRange = 300.0f;
            public float MinigunBulletVelocity = 400.0f;
            public float MinigunBulletGravity = 0.6f;
            public float MinigunAimconeDegrees = 0.6f;
            public float MinigunRoundsPerSecond = 8.0f;
            public int MinigunMagazineSize = 80;
            public float MinigunReloadTime = 25.0f;
            public bool MinigunEnableMuzzleFlash = true;
            public bool MinigunEnableSound = true;
            public string MinigunSoundEffect = "assets/prefabs/weapons/ak47u/effects/attack.prefab";
            public string MinigunMuzzleFlashEffect = "assets/prefabs/weapons/ak47u/effects/attack.prefab";
            public string MinigunImpactEffect = "assets/bundled/prefabs/fx/impacts/additive/explosion.prefab";
            public float CrashSpeedThreshold = 20.0f;
            public string CrashExplosionEffect = "assets/bundled/prefabs/fx/explosions/explosion_01.prefab";
            public string CrashFireEffect = "assets/bundled/prefabs/fx/fire/fire_v3_2x2.prefab";
            public bool EnableHUD = true;
            public bool UnlimitedFuel = true;
        }
        private PluginConfig config;
        private const string HUD_PANEL = "MotorcycleCombat_HUD";
        private const string PermissionUse = "motorcyclecombat.use";
        private static readonly int BulletLayerMask = ~((1 << 2) | (1 << 29));
        private readonly Dictionary<ulong, BoostState> boostByVehicle = new Dictionary<ulong, BoostState>();
        private readonly Dictionary<ulong, float> lastJumpTime = new Dictionary<ulong, float>();
        private readonly Dictionary<ulong, Timer> minigunTimersByPlayer = new Dictionary<ulong, Timer>();
        private readonly Dictionary<ulong, int> minigunAmmoByVehicle = new Dictionary<ulong, int>();
        private readonly Dictionary<ulong, bool> isMinigunReloading = new Dictionary<ulong, bool>();
        private readonly Dictionary<ulong, Timer> minigunReloadTimers = new Dictionary<ulong, Timer>();
        private readonly Dictionary<ulong, Timer> hudUpdateTimers = new Dictionary<ulong, Timer>();
        private readonly List<PendingBullet> pendingBullets = new List<PendingBullet>();
        private readonly HashSet<BasePlayer> activeRiders = new HashSet<BasePlayer>();
        private readonly HashSet<ulong> crashVulnerableVehicles = new HashSet<ulong>();
        private readonly Dictionary<ulong, BaseVehicle> spawnedBikesByPlayer = new Dictionary<ulong, BaseVehicle>();
        private class BoostState
        {
            public BaseVehicle Vehicle;
            public bool IsActive;
            public float FuelRemaining;
            public float RechargeTimer;
            public float LastEffectTime;
        }
        private class PendingBullet
        {
            public BasePlayer Owner;
            public BaseVehicle Vehicle;
            public Vector3 Origin;
            public Vector3 Velocity;
            public Vector3 CurrentPosition;
            public float SpawnTime;
            public float BaseDamage;
            public float MaxLifetime;
            public Vector3 LastPosition;
        }
        private void Init()
        {
            permission.RegisterPermission(PermissionUse, this);
        }
        private readonly Dictionary<ulong, float> lastMotoSpawn = new Dictionary<ulong, float>();
        private const float MOTO_SPAWN_COOLDOWN = 5f;
        [ChatCommand("moto")]
        private void CmdSpawnMoto(BasePlayer player, string command, string[] args)
        {
            if (!HasPermission(player))
            {
                player.ChatMessage("<color=#ff0000>You don't have permission to use this command.</color>");
                return;
            }
            if (player.IsDead())
            {
                player.ChatMessage("<color=#ff0000>You cannot spawn a motorcycle while dead.</color>");
                return;
            }
            if (player.isMounted)
            {
                player.ChatMessage("<color=#ff0000>You cannot spawn a motorcycle while mounted.</color>");
                return;
            }
            if (player.IsSwimming())
            {
                player.ChatMessage("<color=#ff0000>You cannot spawn a motorcycle in water.</color>");
                return;
            }
            if (player.IsBuildingBlocked())
            {
                player.ChatMessage("<color=#ff0000>You cannot spawn a motorcycle in a building blocked area.</color>");
                return;
            }
            float now = Time.realtimeSinceStartup;
            if (lastMotoSpawn.TryGetValue(player.userID, out float lastSpawn))
            {
                float remaining = MOTO_SPAWN_COOLDOWN - (now - lastSpawn);
                if (remaining > 0)
                {
                    player.ChatMessage($"<color=#ff0000>You must wait {remaining:F0} seconds before spawning another motorcycle.</color>");
                    return;
                }
            }
            if (spawnedBikesByPlayer.TryGetValue(player.userID, out BaseVehicle existingBike) && existingBike != null && !existingBike.IsDestroyed)
            {
                bool hasMountedPlayers = false;
                foreach (var mount in existingBike.allMountPoints)
                {
                    if (mount?.mountable != null && mount.mountable.GetMounted() != null)
                    {
                        hasMountedPlayers = true;
                        break;
                    }
                }
                if (hasMountedPlayers)
                {
                    player.ChatMessage("<color=#ff0000>Your previous motorcycle has players mounted. Dismount first.</color>");
                    return;
                }
                existingBike.Kill(BaseNetworkable.DestroyMode.None);
            }
            Vector3 spawnPos = player.transform.position + player.eyes.HeadForward() * 3f;
            spawnPos.y = player.transform.position.y;
            if (!Physics.Raycast(spawnPos + Vector3.up * 2f, Vector3.down, out RaycastHit hit, 5f, BulletLayerMask))
            {
                player.ChatMessage("<color=#ff0000>Invalid spawn location.</color>");
                return;
            }
            spawnPos = hit.point + Vector3.up * 0.5f;
            var moto = GameManager.server.CreateEntity("assets/content/vehicles/bikes/motorbike.prefab", spawnPos, Quaternion.LookRotation(player.eyes.HeadForward())) as BaseVehicle;
            if (moto == null)
            {
                player.ChatMessage("<color=#ff0000>Failed to spawn motorcycle.</color>");
                return;
            }
            moto.Spawn();
            spawnedBikesByPlayer[player.userID] = moto;
            lastMotoSpawn[player.userID] = now;
            player.ChatMessage("<color=#00ff00>Motorcycle spawned!</color>");
        }
        protected override void LoadDefaultConfig()
        {
            config = new PluginConfig();
            SaveConfig();
        }
        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                config = Config.ReadObject<PluginConfig>();
                if (config == null) throw new Exception("Config is null");
            }
            catch
            {
                PrintWarning("Invalid config, creating new...");
                LoadDefaultConfig();
            }
        }
        protected override void SaveConfig() => Config.WriteObject(config, true);
        private void OnServerInitialized()
        {
            config = Config.ReadObject<PluginConfig>();
            SaveConfig();
            Puts($"MotorcycleCombat v1.1.0 loaded");
        }
        private void OnTick()
        {
            ProcessPendingBullets();
            if (boostByVehicle.Count > 0) ProcessBoostPhysics();
        }
        private void Unload()
        {
            foreach (var player in BasePlayer.activePlayerList)
                DestroyHUD(player);
            foreach (var t in minigunTimersByPlayer.Values) t?.Destroy();
            minigunTimersByPlayer.Clear();
            foreach (var t in minigunReloadTimers.Values) t?.Destroy();
            minigunReloadTimers.Clear();
            foreach (var t in hudUpdateTimers.Values) t?.Destroy();
            hudUpdateTimers.Clear();
            pendingBullets.Clear();
        }
        private void OnPlayerInput(BasePlayer player, InputState input)
        {
            if (player == null || input == null || !player.IsConnected) return;
            var mounted = player.GetMountedVehicle();
            if (mounted == null) return;
            bool isMotorbike = mounted.ShortPrefabName.Contains("motorbike");
            if (!isMotorbike) return;
            if (!HasPermission(player)) return;
            bool isSidecar = mounted.ShortPrefabName.Contains("sidecar");
            bool isDriver = !isSidecar || IsDriver(player, mounted);
            bool isPassenger = isSidecar && !IsDriver(player, mounted);
            ulong vehicleId = mounted.net.ID.Value;
            if (config.EnableHUD)
                StartHUDUpdates(player, mounted, isDriver, isPassenger);
            if (isDriver)
            {
                if (input.IsDown(BUTTON.SPRINT))
                    HandleBoostInput(player, mounted, true);
                else
                    HandleBoostInput(player, mounted, false);
                if (input.WasJustPressed(BUTTON.RELOAD))
                    TryJump(player, mounted);
                var heldItem = player.GetActiveItem();
                bool hasWeapon = heldItem != null && (heldItem.info.category == ItemCategory.Weapon || heldItem.info.category == ItemCategory.Tool);
                if (!hasWeapon && input.IsDown(BUTTON.FIRE_PRIMARY))
                {
                    if (!IsMinigunReloading(vehicleId))
                        StartMinigunTimer(player, mounted);
                }
                else
                {
                    StopMinigunTimer(player.userID);
                }
            }
        }
        private void HandleBoostInput(BasePlayer player, BaseVehicle vehicle, bool isPressed)
        {
            ulong vehicleId = vehicle.net.ID.Value;
            if (!boostByVehicle.TryGetValue(vehicleId, out BoostState state))
            {
                state = new BoostState
                {
                    Vehicle = vehicle,
                    IsActive = false,
                    FuelRemaining = config.BoostFuelDuration,
                    RechargeTimer = 0f,
                    LastEffectTime = 0f
                };
                boostByVehicle[vehicleId] = state;
            }
            if (isPressed && state.FuelRemaining > 0f && state.RechargeTimer <= 0f && IsGrounded(vehicle))
            {
                if (!state.IsActive)
                {
                    state.IsActive = true;
                    crashVulnerableVehicles.Add(vehicleId);
                    Effect.server.Run(config.BoostActivateSound, vehicle.transform.position);
                }
            }
            else
            {
                if (state.IsActive)
                {
                    state.IsActive = false;
                    if (state.FuelRemaining <= 0f)
                    {
                        state.RechargeTimer = config.BoostRechargeTime;
                    }
                }
            }
        }
        private void ProcessBoostPhysics()
        {
            float dt = Time.deltaTime;
            float currentTime = Time.realtimeSinceStartup;
            List<ulong> toRemove = null;
            foreach (var kvp in boostByVehicle)
            {
                ulong vehicleId = kvp.Key;
                BoostState state = kvp.Value;
                var vehicle = state.Vehicle;
                if (vehicle == null || vehicle.IsDestroyed)
                {
                    if (toRemove == null) toRemove = new List<ulong>();
                    toRemove.Add(vehicleId);
                    continue;
                }
                if (state.RechargeTimer > 0f)
                {
                    state.RechargeTimer -= dt;
                    if (state.RechargeTimer <= 0f)
                    {
                        state.FuelRemaining = config.BoostFuelDuration;
                        state.RechargeTimer = 0f;
                        var driver = GetDriver(vehicle);
                        if (driver != null)
                            Effect.server.Run("assets/bundled/prefabs/fx/invite_notice.prefab", vehicle.transform.position);
                    }
                }
                if (state.IsActive && state.FuelRemaining > 0f)
                {
                    if (!IsGrounded(vehicle))
                    {
                        state.IsActive = false;
                        continue;
                    }
                    state.FuelRemaining -= dt;
                    var rb = vehicle.GetComponent<Rigidbody>();
                    if (rb != null)
                    {
                        Vector3 boostForce = vehicle.transform.forward * config.BoostThrustMultiplier * 50f;
                        rb.AddForce(boostForce, ForceMode.Acceleration);
                    }
                    if (currentTime - state.LastEffectTime > 0.2f)
                    {
                        Vector3 exhaustPos = vehicle.transform.position - vehicle.transform.forward * 1.0f;
                        Effect.server.Run(config.BoostLoopEffect, exhaustPos, -vehicle.transform.forward);
                        state.LastEffectTime = currentTime;
                    }
                    if (state.FuelRemaining <= 0f)
                    {
                        state.IsActive = false;
                        state.FuelRemaining = 0f;
                        state.RechargeTimer = config.BoostRechargeTime;
                    }
                }
                else if (!state.IsActive && state.RechargeTimer <= 0f && state.FuelRemaining >= config.BoostFuelDuration)
                {
                    crashVulnerableVehicles.Remove(vehicleId);
                }
            }
            if (toRemove != null)
                foreach (var id in toRemove)
                {
                    boostByVehicle.Remove(id);
                    crashVulnerableVehicles.Remove(id);
                }
        }
        private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
        {
            if (entity == null || info == null) return;
            var vehicle = entity as BaseVehicle;
            if (vehicle == null || !vehicle.ShortPrefabName.Contains("motorbike")) return;
            ulong vehicleId = vehicle.net.ID.Value;
            if (!crashVulnerableVehicles.Contains(vehicleId)) return;
            if (!boostByVehicle.TryGetValue(vehicleId, out BoostState state)) return;
            if (!state.IsActive) return;
            var rb = vehicle.GetComponent<Rigidbody>();
            float speed = rb != null ? rb.velocity.magnitude : 0f;
            if (speed < config.CrashSpeedThreshold) return;
            bool isCollision = info.damageTypes.Has(Rust.DamageType.Collision) ||
                              info.damageTypes.Has(Rust.DamageType.Blunt) ||
                              (info.Initiator == null && info.damageTypes.Total() > 0);
            if (!isCollision) return;
            TriggerCrashExplosion(vehicle, info.HitPositionWorld);
        }
        private void TriggerCrashExplosion(BaseVehicle vehicle, Vector3 crashPoint)
        {
            if (vehicle == null || vehicle.IsDestroyed) return;
            ulong vehicleId = vehicle.net.ID.Value;
            boostByVehicle.Remove(vehicleId);
            crashVulnerableVehicles.Remove(vehicleId);
            Vector3 pos = crashPoint != Vector3.zero ? crashPoint : vehicle.transform.position;
            for (int i = 0; i < 3; i++)
            {
                Vector3 offset = UnityEngine.Random.insideUnitSphere * 2f;
                Effect.server.Run(config.CrashExplosionEffect, pos + offset, Vector3.up);
            }
            Effect.server.Run(config.CrashFireEffect, pos, Vector3.up);
            Effect.server.Run(config.CrashFireEffect, pos + Vector3.up * 1f, Vector3.up);
            Effect.server.Run("assets/bundled/prefabs/fx/explosions/explosion_03.prefab", pos, Vector3.up);
            var driver = GetDriver(vehicle);
            if (driver != null)
            {
                activeRiders.Remove(driver);
                StopHUDUpdates(driver);
                DestroyHUD(driver);
            }
            timer.Once(0.1f, () =>
            {
                if (vehicle != null && !vehicle.IsDestroyed)
                {
                    vehicle.Kill(BaseNetworkable.DestroyMode.Gib);
                }
            });
        }
        private void TryJump(BasePlayer player, BaseVehicle vehicle)
        {
            ulong vehicleId = vehicle.net.ID.Value;
            float now = Time.realtimeSinceStartup;
            if (lastJumpTime.TryGetValue(vehicleId, out float lastTime))
            {
                float remaining = config.JumpCooldown - (now - lastTime);
                if (remaining > 0) return;
            }
            var rb = vehicle.GetComponent<Rigidbody>();
            if (rb == null) return;
            if (!IsGrounded(vehicle)) return;
            lastJumpTime[vehicleId] = now;
            rb.AddForce(Vector3.up * config.JumpForce, ForceMode.VelocityChange);
            Effect.server.Run(config.JumpSound, vehicle.transform.position);
        }
        private bool IsGrounded(BaseVehicle vehicle)
        {
            Vector3 pos = vehicle.transform.position;
            if (!Physics.Raycast(pos + Vector3.up * 0.3f, Vector3.down, 1.5f, BulletLayerMask))
                return false;
            var rb = vehicle.GetComponent<Rigidbody>();
            if (rb != null && Mathf.Abs(rb.velocity.y) > 5.0f)
                return false;
            return true;
        }
        private void StartMinigunTimer(BasePlayer player, BaseVehicle vehicle)
        {
            if (minigunTimersByPlayer.ContainsKey(player.userID)) return;
            float fireInterval = 1f / config.MinigunRoundsPerSecond;
            FireMinigun(player, vehicle);
            minigunTimersByPlayer[player.userID] = timer.Every(fireInterval, () =>
            {
                if (player == null || !player.IsConnected || player.IsDead())
                {
                    StopMinigunTimer(player.userID);
                    return;
                }
                var mounted = player.GetMountedVehicle();
                if (mounted == null || mounted != vehicle)
                {
                    StopMinigunTimer(player.userID);
                    return;
                }
                FireMinigun(player, vehicle);
            });
        }
        private void StopMinigunTimer(ulong playerId)
        {
            if (minigunTimersByPlayer.TryGetValue(playerId, out var t))
            {
                t?.Destroy();
                minigunTimersByPlayer.Remove(playerId);
            }
        }
        private void FireMinigun(BasePlayer player, BaseVehicle vehicle)
        {
            ulong vehicleId = vehicle.net.ID.Value;
            int ammo = GetMinigunAmmo(vehicleId);
            if (ammo <= 0)
            {
                StartMinigunReload(player, vehicle, vehicleId);
                StopMinigunTimer(player.userID);
                return;
            }
            minigunAmmoByVehicle[vehicleId] = ammo - 1;
            Vector3 muzzlePos = player.eyes.position + player.eyes.HeadForward() * 1.0f;
            Vector3 direction = player.eyes.HeadForward();
            float aimcone = config.MinigunAimconeDegrees * Mathf.Deg2Rad;
            direction = ApplyAimcone(direction, aimcone);
            Vector3 velocity = direction * config.MinigunBulletVelocity;
            if (config.MinigunEnableSound)
                Effect.server.Run(config.MinigunSoundEffect, muzzlePos);
            if (config.MinigunEnableMuzzleFlash)
                Effect.server.Run(config.MinigunMuzzleFlashEffect, muzzlePos);
            float maxLifetime = config.MinigunRange / config.MinigunBulletVelocity;
            pendingBullets.Add(new PendingBullet
            {
                Owner = player,
                Vehicle = vehicle,
                Origin = muzzlePos,
                Velocity = velocity,
                CurrentPosition = muzzlePos,
                SpawnTime = Time.realtimeSinceStartup,
                BaseDamage = config.MinigunDamage,
                MaxLifetime = maxLifetime,
                LastPosition = muzzlePos
            });
        }
        private Vector3 ApplyAimcone(Vector3 direction, float aimcone)
        {
            float x = UnityEngine.Random.Range(-aimcone, aimcone);
            float y = UnityEngine.Random.Range(-aimcone, aimcone);
            return Quaternion.Euler(x * Mathf.Rad2Deg, y * Mathf.Rad2Deg, 0) * direction;
        }
        private void ProcessPendingBullets()
        {
            if (pendingBullets.Count == 0) return;
            float dt = Time.deltaTime;
            float currentTime = Time.realtimeSinceStartup;
            for (int i = pendingBullets.Count - 1; i >= 0; i--)
            {
                var bullet = pendingBullets[i];
                float age = currentTime - bullet.SpawnTime;
                if (age > bullet.MaxLifetime)
                {
                    pendingBullets.RemoveAt(i);
                    continue;
                }
                bullet.Velocity.y -= config.MinigunBulletGravity * dt * 9.81f;
                bullet.LastPosition = bullet.CurrentPosition;
                bullet.CurrentPosition += bullet.Velocity * dt;
                Vector3 direction = bullet.CurrentPosition - bullet.LastPosition;
                float distance = direction.magnitude;
                if (distance > 0.01f && Physics.Raycast(bullet.LastPosition, direction.normalized, out RaycastHit hit, distance, BulletLayerMask))
                {
                    var entity = hit.GetEntity();
                    if (entity != null && entity != bullet.Vehicle)
                    {
                        var combatEntity = entity as BaseCombatEntity;
                        if (combatEntity != null)
                        {
                            var hitInfo = new HitInfo(bullet.Owner, combatEntity, Rust.DamageType.Bullet, bullet.BaseDamage, hit.point);
                            combatEntity.OnAttacked(hitInfo);
                        }
                        Effect.server.Run(config.MinigunImpactEffect, hit.point, hit.normal);
                    }
                    else if (entity == null)
                    {
                        Effect.server.Run(config.MinigunImpactEffect, hit.point, hit.normal);
                    }
                    pendingBullets.RemoveAt(i);
                }
            }
        }
        private int GetMinigunAmmo(ulong vehicleId)
        {
            if (!minigunAmmoByVehicle.TryGetValue(vehicleId, out int ammo))
            {
                ammo = config.MinigunMagazineSize;
                minigunAmmoByVehicle[vehicleId] = ammo;
            }
            return ammo;
        }
        private bool IsMinigunReloading(ulong vehicleId)
        {
            return isMinigunReloading.TryGetValue(vehicleId, out bool reloading) && reloading;
        }
        private void StartMinigunReload(BasePlayer player, BaseVehicle vehicle, ulong vehicleId)
        {
            if (IsMinigunReloading(vehicleId)) return;
            isMinigunReloading[vehicleId] = true;
            player.ChatMessage($"<color=#ffaa00>Reloading... {config.MinigunReloadTime}s</color>");
            if (minigunReloadTimers.TryGetValue(vehicleId, out var existingTimer))
                existingTimer?.Destroy();
            minigunReloadTimers[vehicleId] = timer.Once(config.MinigunReloadTime, () =>
            {
                minigunAmmoByVehicle[vehicleId] = config.MinigunMagazineSize;
                isMinigunReloading[vehicleId] = false;
                var v = BaseNetworkable.serverEntities.Find(new NetworkableId(vehicleId)) as BaseVehicle;
                if (v != null)
                {
                    Effect.server.Run("assets/bundled/prefabs/fx/invite_notice.prefab", v.transform.position);
                    var driver = GetDriver(v);
                    if (driver != null)
                        driver.ChatMessage("<color=#00ff00>Minigun reloaded!</color>");
                }
                minigunReloadTimers.Remove(vehicleId);
            });
        }
        private void StartHUDUpdates(BasePlayer player, BaseVehicle vehicle, bool isDriver, bool isPassenger)
        {
            if (hudUpdateTimers.ContainsKey(player.userID)) return;
            UpdateHUD(player, vehicle, isDriver, isPassenger);
            hudUpdateTimers[player.userID] = timer.Every(0.5f, () =>
            {
                if (player == null || !player.IsConnected)
                {
                    StopHUDUpdates(player);
                    return;
                }
                var mounted = player.GetMountedVehicle();
                if (mounted == null || !mounted.ShortPrefabName.Contains("motorbike"))
                {
                    StopHUDUpdates(player);
                    DestroyHUD(player);
                    return;
                }
                UpdateHUD(player, mounted, IsDriver(player, mounted), !IsDriver(player, mounted) && mounted.ShortPrefabName.Contains("sidecar"));
            });
        }
        private void StopHUDUpdates(BasePlayer player)
        {
            if (player == null) return;
            if (hudUpdateTimers.TryGetValue(player.userID, out var t))
            {
                t?.Destroy();
                hudUpdateTimers.Remove(player.userID);
            }
        }
        private void UpdateHUD(BasePlayer player, BaseVehicle vehicle, bool isDriver, bool isPassenger)
        {
            if (player == null || vehicle == null) return;
            if (!isDriver) return;
            ulong vehicleId = vehicle.net.ID.Value;
            CuiHelper.DestroyUi(player, HUD_PANEL);
            var elements = new CuiElementContainer();
            elements.Add(new CuiPanel
            {
                Image = { Color = "0 0 0 0" },
                RectTransform = { AnchorMin = "0.30 0.095", AnchorMax = "0.70 0.125" },
                CursorEnabled = false
            }, "Hud", HUD_PANEL);
            float boostFuel = config.BoostFuelDuration;
            bool boostRecharging = false;
            if (boostByVehicle.TryGetValue(vehicleId, out BoostState boostState))
            {
                boostFuel = boostState.FuelRemaining;
                boostRecharging = boostState.RechargeTimer > 0f;
            }
            float jumpCooldown = 0f;
            if (lastJumpTime.TryGetValue(vehicleId, out float lastTime))
                jumpCooldown = Mathf.Max(0, config.JumpCooldown - (Time.realtimeSinceStartup - lastTime));
            int ammo = GetMinigunAmmo(vehicleId);
            bool reloading = IsMinigunReloading(vehicleId);
            elements.Add(new CuiPanel
            {
                Image = { Color = "0.1 0.1 0.1 0.7" },
                RectTransform = { AnchorMin = "0.02 0.1", AnchorMax = "0.34 0.9" }
            }, HUD_PANEL, HUD_PANEL + "_BoostBG");
            string boostValue;
            if (boostRecharging)
            {
                boostValue = "<color=#ffaa00>RECHARGING</color>";
            }
            else
            {
                float boostPercent = (boostFuel / config.BoostFuelDuration) * 100f;
                string boostColor = boostPercent > 50 ? "#44aaff" : (boostPercent > 25 ? "#ffcc00" : "#ff4444");
                boostValue = $"<color={boostColor}>{boostPercent:F0}%</color>";
            }
            elements.Add(new CuiLabel
            {
                Text = { 
                    Text = $"<color=#cccccc>Boost:</color> {boostValue}", 
                    FontSize = 11, 
                    Align = TextAnchor.MiddleCenter, 
                    Color = "1 1 1 1",
                    Font = "robotocondensed-bold.ttf"
                },
                RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" }
            }, HUD_PANEL + "_BoostBG");
            elements.Add(new CuiPanel
            {
                Image = { Color = "0.1 0.1 0.1 0.7" },
                RectTransform = { AnchorMin = "0.35 0.1", AnchorMax = "0.65 0.9" }
            }, HUD_PANEL, HUD_PANEL + "_JumpBG");
            string jumpValue;
            if (jumpCooldown > 0)
            {
                jumpValue = $"<color=#ffaa00>{jumpCooldown:F1}s</color>";
            }
            else
            {
                jumpValue = "<color=#88ff88>READY</color>";
            }
            elements.Add(new CuiLabel
            {
                Text = { 
                    Text = $"<color=#cccccc>Jump:</color> {jumpValue}", 
                    FontSize = 11, 
                    Align = TextAnchor.MiddleCenter, 
                    Color = "1 1 1 1",
                    Font = "robotocondensed-bold.ttf"
                },
                RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" }
            }, HUD_PANEL + "_JumpBG");
            elements.Add(new CuiPanel
            {
                Image = { Color = "0.1 0.1 0.1 0.7" },
                RectTransform = { AnchorMin = "0.66 0.1", AnchorMax = "0.98 0.9" }
            }, HUD_PANEL, HUD_PANEL + "_AmmoBG");
            string ammoValue;
            if (reloading)
            {
                ammoValue = "<color=#ffaa00>RELOADING</color>";
            }
            else
            {
                string ammoColor = ammo > 30 ? "#88ff88" : (ammo > 10 ? "#ffcc00" : "#ff4444");
                ammoValue = $"<color={ammoColor}>{ammo}</color>";
            }
            elements.Add(new CuiLabel
            {
                Text = { 
                    Text = $"<color=#cccccc>Ammo:</color> {ammoValue}", 
                    FontSize = 11, 
                    Align = TextAnchor.MiddleCenter, 
                    Color = "1 1 1 1",
                    Font = "robotocondensed-bold.ttf"
                },
                RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" }
            }, HUD_PANEL + "_AmmoBG");
            CuiHelper.AddUi(player, elements);
        }
        private void DestroyHUD(BasePlayer player)
        {
            if (player == null) return;
            CuiHelper.DestroyUi(player, HUD_PANEL);
        }
        private void OnEntityDismounted(BaseMountable mountable, BasePlayer player)
        {
            if (player == null) return;
            activeRiders.Remove(player);
            StopMinigunTimer(player.userID);
            StopHUDUpdates(player);
            DestroyHUD(player);
        }
        private void OnPlayerDisconnected(BasePlayer player, string reason)
        {
            if (player == null) return;
            activeRiders.Remove(player);
            StopMinigunTimer(player.userID);
            StopHUDUpdates(player);
            DestroyHUD(player);
        }
        private void OnEntityKill(BaseNetworkable entity)
        {
            if (entity is BaseVehicle vehicle)
            {
                ulong vehicleId = vehicle.net.ID.Value;
                boostByVehicle.Remove(vehicleId);
                crashVulnerableVehicles.Remove(vehicleId);
                lastJumpTime.Remove(vehicleId);
                minigunAmmoByVehicle.Remove(vehicleId);
                isMinigunReloading.Remove(vehicleId);
                if (minigunReloadTimers.TryGetValue(vehicleId, out var t))
                {
                    t?.Destroy();
                    minigunReloadTimers.Remove(vehicleId);
                }
                ulong ownerToRemove = 0;
                foreach (var kvp in spawnedBikesByPlayer)
                {
                    if (kvp.Value == vehicle)
                    {
                        ownerToRemove = kvp.Key;
                        break;
                    }
                }
                if (ownerToRemove != 0)
                    spawnedBikesByPlayer.Remove(ownerToRemove);
            }
        }
        private object OnFuelCheck(EntityFuelSystem fuelSystem)
        {
            if (!config.UnlimitedFuel) return null;
            var vehicle = fuelSystem.GetFuelContainer()?.GetParentEntity() as BaseVehicle;
            if (vehicle != null && vehicle.ShortPrefabName.Contains("motorbike"))
                return true;
            return null;
        }
        private bool HasPermission(BasePlayer player)
        {
            if (!config.RequirePermission) return true;
            return permission.UserHasPermission(player.UserIDString, PermissionUse);
        }
        private bool IsDriver(BasePlayer player, BaseVehicle vehicle)
        {
            if (vehicle == null) return false;
            var driver = GetDriver(vehicle);
            return driver != null && driver == player;
        }
        private BasePlayer GetDriver(BaseVehicle vehicle)
        {
            if (vehicle == null) return null;
            foreach (var mount in vehicle.allMountPoints)
            {
                if (mount?.mountable != null && mount.isDriver)
                {
                    return mount.mountable.GetMounted() as BasePlayer;
                }
            }
            return null;
        }
    }
}

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