using Oxide.Core.Plugins; using Oxide.Core; using Oxide.Core.Libraries.Covalence; using UnityEngine; using System.Collections.Generic; namespace Oxide.Plugins { [Info("Random Scarecrow Spawner", "Chernarust", "1.1.5")] [Description("Spawns scarecrows around players with a configurable random chance and allows one-hit headshot kills.")] public class RandomScarecrowSpawner : CovalencePlugin { private const string scarecrowPrefab = "assets/prefabs/npc/scarecrow/scarecrow.prefab"; private const string permissionName = "randomscarecrowspawner.use"; private PluginConfig config; private Dictionary playerScarecrowCount = new Dictionary(); private Dictionary scarecrowToPlayerMap = new Dictionary(); private class PluginConfig { public float SpawnChance { get; set; } public float CheckInterval { get; set; } public float SpawnDistance { get; set; } public int MaxScarecrowsPerPlayer { get; set; } public bool OneHitHeadshotKill { get; set; } public static PluginConfig DefaultConfig() { return new PluginConfig { SpawnChance = 0.1f, CheckInterval = 60.0f, SpawnDistance = 20.0f, MaxScarecrowsPerPlayer = 3, OneHitHeadshotKill = true }; } } protected override void LoadDefaultConfig() => config = PluginConfig.DefaultConfig(); private void Init() { permission.RegisterPermission(permissionName, this); } private void OnServerInitialized() { LoadConfig(); timer.Every(config.CheckInterval, () => SpawnScarecrowsForPlayers()); } private void SpawnScarecrowsForPlayers() { foreach (var player in players.Connected) { if (!player.HasPermission(permissionName)) continue; BasePlayer basePlayer = player.Object as BasePlayer; if (!basePlayer.IsAlive() || basePlayer.IsSleeping() || basePlayer.InSafeZone() || IsInToolCupboardRange(basePlayer)) continue; string playerId = player.Id; if (!playerScarecrowCount.ContainsKey(playerId)) playerScarecrowCount[playerId] = 0; if (playerScarecrowCount[playerId] >= config.MaxScarecrowsPerPlayer) continue; if (UnityEngine.Random.value < config.SpawnChance) { Vector3 randomDirection = UnityEngine.Random.insideUnitSphere * config.SpawnDistance; randomDirection.y = 0; Vector3 spawnPosition = basePlayer.transform.position + randomDirection; spawnPosition.y = TerrainMeta.HeightMap.GetHeight(spawnPosition); SpawnScarecrow(spawnPosition, playerId); } } } private void SpawnScarecrow(Vector3 position, string playerId) { var scarecrow = GameManager.server.CreateEntity(scarecrowPrefab, position, Quaternion.identity); if (scarecrow != null) { scarecrow.Spawn(); playerScarecrowCount[playerId]++; scarecrowToPlayerMap[scarecrow.net.ID] = playerId; Puts($"Spawned a scarecrow at {position} for player {playerId}"); } } private bool IsInToolCupboardRange(BasePlayer player) { var buildingPrivileges = player.GetBuildingPrivilege(); return buildingPrivileges != null && buildingPrivileges.IsAuthed(player); } [HookMethod("OnEntityTakeDamage")] private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitInfo) { if (entity?.ShortPrefabName != "scarecrow" || hitInfo == null || !config.OneHitHeadshotKill) return; if (hitInfo.isHeadshot) { entity.Die(); // Kill the entity instantly on a headshot } } private void LoadConfig() { config = Config.ReadObject(); if (config?.SpawnChance == null) { LoadDefaultConfig(); } SaveConfig(); } protected override void SaveConfig() => Config.WriteObject(config); [HookMethod("OnEntityDeath")] private void OnEntityDeath(BaseEntity entity) { if (entity?.ShortPrefabName != "scarecrow") return; if (scarecrowToPlayerMap.TryGetValue(entity.net.ID, out string playerId)) { playerScarecrowCount[playerId]--; scarecrowToPlayerMap.Remove(entity.net.ID); } } } }