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

FREE SharkAttack : 1.0.0 1.0.0

Нет прав для скачивания
C#:
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("SharkAttack", "DAKARAT", "1.0.0")]
    [Description("Event: a pack of sharks invades the waters around your players. Full despawn when it ends.")]
    public class SharkAttack : RustPlugin
    {
        // --------------------------------------------------------------------
        // Sharks are spawned near players first and anywhere deep enough as a
        // fallback, so the event still fires on an empty or land-heavy map.
        // Every spawned shark is tracked and killed when the event stops or the
        // plugin unloads - an event that leaves creatures behind is worse than
        // no event at all.
        // --------------------------------------------------------------------

        private const string PermAdmin = "sharkattack.admin";

        private bool _active;
        private readonly List<BaseEntity> _sharks = new List<BaseEntity>();

        #region Configuration

        private Configuration _config;

        private class Configuration
        {
            // simpleshark.prefab is the real shark agent. The obvious-looking
            // ".../shark/shark.prefab" simply does not exist in the game files.
            [JsonProperty("Shark prefab")]
            public string SharkPrefab = "assets/rust.ai/agents/fish/simpleshark.prefab";

            [JsonProperty("Number of sharks to spawn")] public int TotalSharks = 15;
            [JsonProperty("Spawn radius around players (m)")] public float SpawnRadius = 60f;
            [JsonProperty("Minimum water depth to spawn (m)")] public float MinWaterDepth = 1.5f;
            [JsonProperty("Chat prefix")] public string Prefix = "<color=#1c6ea4>[Sharks]</color>";
        }

        protected override void LoadDefaultConfig() => _config = new Configuration();

        protected override void LoadConfig()
        {
            base.LoadConfig();
            try
            {
                _config = Config.ReadObject<Configuration>();
                if (_config == null) LoadDefaultConfig();
            }
            catch
            {
                PrintWarning("Configuration file is invalid, loading defaults.");
                LoadDefaultConfig();
            }
            SaveConfig();
        }

        protected override void SaveConfig() => Config.WriteObject(_config);

        #endregion

        #region Localisation

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["NoPermission"] = "You are not allowed to use this command.",
                ["Started"] = "<color=#ce422b>SHARK ATTACK!</color> Sharks are flooding the waters - <color=#ffffff>get out of the sea!</color>",
                ["Ended"] = "The sharks return to the deep. The water is safe... for now.",
                ["NoWater"] = "...the sea is too calm, no shark found anywhere to spawn.",
                ["AlreadyActive"] = "A shark attack is already running.",
                ["Usage"] = "Usage: /sharks [start|stop]"
            }, this);

            lang.RegisterMessages(new Dictionary<string, string>
            {
                ["NoPermission"] = "Tu n'as pas la permission d'utiliser cette commande.",
                ["Started"] = "<color=#ce422b>LES DENTS DE LA MER !</color> Des requins envahissent les eaux - <color=#ffffff>sortez de l'eau !</color>",
                ["Ended"] = "Les requins regagnent les profondeurs. L'eau est sure... pour l'instant.",
                ["NoWater"] = "...l'eau est trop calme, aucun requin n'a trouve ou apparaitre.",
                ["AlreadyActive"] = "Une attaque de requins est deja en cours.",
                ["Usage"] = "Usage : /sharks [start|stop]"
            }, this, "fr");
        }

        private string L(string key, BasePlayer player = null)
            => lang.GetMessage(key, this, player == null ? null : player.UserIDString);

        #endregion

        #region Lifecycle

        private void Init() => permission.RegisterPermission(PermAdmin, this);

        // Safety: never leave sharks swimming around after a reload.
        private void Unload() => StopEvent(false);

        #endregion

        #region Commands and API

        [ChatCommand("sharks")]
        private void CmdSharks(BasePlayer player, string cmd, string[] args)
        {
            if (player == null) return;
            if (!player.IsAdmin && !permission.UserHasPermission(player.UserIDString, PermAdmin))
            {
                PrintToChat(player, $"{_config.Prefix} {L("NoPermission", player)}");
                return;
            }

            string sub = args != null && args.Length > 0 ? args[0].ToLower() : "start";
            switch (sub)
            {
                case "stop":
                    StopEvent(true);
                    break;
                case "start":
                    if (_active) PrintToChat(player, $"{_config.Prefix} {L("AlreadyActive", player)}");
                    else StartEvent();
                    break;
                default:
                    PrintToChat(player, $"{_config.Prefix} {L("Usage", player)}");
                    break;
            }
        }

        [ConsoleCommand("sharks")]
        private void ConsoleSharks(ConsoleSystem.Arg arg)
        {
            if (arg.Player() != null && !arg.Player().IsAdmin) return;
            string sub = arg.HasArgs(1) ? arg.GetString(0).ToLower() : "start";
            if (sub == "stop") StopEvent(true); else StartEvent();
        }

        // Public API for other plugins.
        private void StartSharkAttack() => StartEvent();
        private void StopSharkAttack() => StopEvent(true);
        private bool IsSharkAttackActive() => _active;

        #endregion

        #region Event

        private void StartEvent()
        {
            if (_active) return;
            _active = true;
            _sharks.Clear();

            Announce("Started");

            int target = Mathf.Max(1, _config.TotalSharks);
            int spawned = 0, attempts = 0;

            // Bounded retries: on a map with very little water we must give up
            // rather than loop forever looking for a valid spot.
            while (spawned < target && attempts < target * 25)
            {
                attempts++;
                Vector3 pos;
                if (TryFindWaterSpawn(out pos) && SpawnShark(pos)) spawned++;
            }

            Puts($"SharkAttack: {spawned}/{target} sharks spawned.");

            if (spawned == 0)
            {
                Announce("NoWater");
                _active = false;
                return;
            }

            Interface.CallHook("OnSharkAttackStarted", spawned);
        }

        private void StopEvent(bool announce)
        {
            if (!_active) return;
            _active = false;

            int killed = 0;
            foreach (var shark in _sharks)
                if (shark != null && !shark.IsDestroyed) { shark.Kill(); killed++; }
            _sharks.Clear();

            if (announce) Announce("Ended");
            Puts($"SharkAttack: event stopped, {killed} sharks despawned.");
            Interface.CallHook("OnSharkAttackEnded", killed);
        }

        private bool TryFindWaterSpawn(out Vector3 pos)
        {
            pos = Vector3.zero;
            if (TerrainMeta.HeightMap == null) return false;

            var players = BasePlayer.activePlayerList;

            // Prefer water near a random player, so the event happens where
            // someone can actually see it.
            if (players.Count > 0)
            {
                var p = players[UnityEngine.Random.Range(0, players.Count)];
                if (p != null)
                {
                    Vector2 offset = UnityEngine.Random.insideUnitCircle * Mathf.Max(10f, _config.SpawnRadius);
                    Vector3 candidate = p.transform.position + new Vector3(offset.x, 0f, offset.y);
                    if (IsWater(candidate)) { candidate.y = -1.5f; pos = candidate; return true; }
                }
            }

            // Fallback: anywhere deep enough on the map.
            float half = TerrainMeta.Size.x * 0.45f;
            var random = new Vector3(UnityEngine.Random.Range(-half, half), -1.5f, UnityEngine.Random.Range(-half, half));
            if (IsWater(random)) { pos = random; return true; }

            return false;
        }

        private bool IsWater(Vector3 pos)
        {
            float height = TerrainMeta.HeightMap.GetHeight(pos);
            return height < -Mathf.Max(0.5f, _config.MinWaterDepth);
        }

        private bool SpawnShark(Vector3 pos)
        {
            var ent = GameManager.server.CreateEntity(_config.SharkPrefab, pos, Quaternion.identity);
            if (ent == null)
            {
                PrintWarning($"Shark prefab not found: {_config.SharkPrefab}");
                return false;
            }
            ent.Spawn();
            _sharks.Add(ent);
            return true;
        }

        private void Announce(string key)
        {
            foreach (var p in BasePlayer.activePlayerList)
                if (p != null) PrintToChat(p, $"{_config.Prefix} {L(key, p)}");
        }

        #endregion
    }
}

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