C#:
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Configuration;
using ProtoBuf;
using Rust;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
// https://modhub.to
// This is a user submitted Rust Plugin checked and verified by ModHub
// ModHub is the largest Server Owner Trading Platform Online
namespace Oxide.Plugins
{
[Info("ChickenBow", "https://discord.gg/9vyTXsJyKR", "1.0.1")]
[Description("ChickenBow challenge")]
class ChickenBow : RustPlugin
{
#region Config
private Configuration config;
public class Configuration
{
[JsonProperty("How many chickens does a player need to kill to get the bow?")]
public int ChickenTarget = 100;
[JsonProperty("Send the player a message with an update on their progress when killing a chicken?")]
public bool UpdateKillProgress = true;
[JsonProperty("Remove the spawned chickens corpse after it dies?")]
public bool RemoveChickenOnDeath = true;
[JsonProperty("How long after death before we remove the corpse (1+ second is recommended)?")]
public float RemoveChickenDelay = 2;
[JsonProperty("Hunting bow Skin ID to use?")]
public ulong BowSkin = 2387980509;
[JsonProperty("What should we do with the chickens when the script is unloaded? [1 = delete them] [2 = Make them regular chickens]")]
public int UnloadChickens = 1;
[JsonProperty("Maximum chickens that each player can have spawned? [0 == unlimited]")]
public int max_user_chickens = 5;
[JsonProperty("Effects when a chicken dies - chosen randomly")]
public string[] dying_effects =
{
"assets/bundled/prefabs/fx/player/beartrap_scream.prefab",
"assets/prefabs/tools/c4/effects/c4_explosion.prefab",
"assets/prefabs/weapons/rocketlauncher/effects/rocket_explosion.prefab",
"assets/prefabs/weapons/rocketlauncher/effects/rocket_explosion_incendiary.prefab",
"assets/prefabs/weapons/satchelcharge/effects/satchel-charge-explosion.prefab",
"assets/prefabs/weapons/waterbucket/effects/waterimpact_explosion.prefab"
};
public string ToJson() => JsonConvert.SerializeObject(this);
public Dictionary<string, object> ToDictionary() => JsonConvert.DeserializeObject<Dictionary<string, object>>(ToJson());
}
protected override void LoadDefaultConfig() => config = new Configuration();
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<Configuration>();
if (config == null)
{
throw new JsonException();
}
if (!config.ToDictionary().Keys.SequenceEqual(Config.ToDictionary(x => x.Key, x => x.Value).Keys))
{
PrintToConsole("Configuration appears to be outdated; updating and saving");
SaveConfig();
}
}
catch
{
PrintToConsole($"Configuration file {Name}.json is invalid; using defaults");
LoadDefaultConfig();
}
}
protected override void SaveConfig()
{
PrintToConsole($"Configuration changes saved to {Name}.json");
Config.WriteObject(config, true);
}
#endregion
#region Data
PlayerEntity pcdData;
private DynamicConfigFile PCDDATA;
const string Prefix = "<color=#FDC24C>[Chicken Hunter]</color>";
void Init()
{
permission.RegisterPermission("chickenbow.admin", this);
permission.RegisterPermission("chickenbow.allow", this);
PCDDATA = Interface.Oxide.DataFileSystem.GetFile("chickenbow/chickenkills");
}
void Unload()
{
RemoveChickens();
SaveData();
}
void Loaded()
{
LoadData();
LoadConfig();
}
void SaveData()
{
PCDDATA.WriteObject(pcdData);
}
void LoadData()
{
try
{
pcdData = Interface.GetMod().DataFileSystem.ReadObject<PlayerEntity>("chickenbow/chickenkills");
}
catch
{
Puts("Couldn't load player data, creating new Playerfile");
pcdData = new PlayerEntity();
}
}
public List<uint> Spawnedchickens = new List<uint>();
class PlayerEntity
{
public Dictionary<ulong, PCDInfo> pEntity = new Dictionary<ulong, PCDInfo>();
public PlayerEntity() { }
}
class PCDInfo
{
public string name;
public int ChickensKilled = 0;
public List<uint> user_chickens = new List<uint>();
}
#endregion;
#region Hooks
private bool ChickenDied;
void OnPlayerAttack(BasePlayer attacker, HitInfo info)
{
TrySpawnChicken(attacker, info.HitPositionWorld);
}
private void OnEntitySpawned(BaseNetworkable entity)
{
if (!config.RemoveChickenOnDeath) return;
if (entity.ShortPrefabName.Contains("hicken"))
{
var chickenbody = entity as BaseCorpse;
if (chickenbody != null)
{
if (ChickenDied)
{
ChickenDied = false;
timer.Once(config.RemoveChickenDelay, () =>
{
chickenbody.Kill();
});
}
}
}
}
void OnEntityDeath(BaseCombatEntity entity, HitInfo info)
{
if (entity == null || info == null || entity.ShortPrefabName == null) return;
if (!entity.ShortPrefabName.Contains("hicken") || entity.ShortPrefabName.Contains("corpse")) return;
var chicken = entity as BaseEntity;
if (chicken == null) return;
if (!Spawnedchickens.Contains(chicken.net.ID))
{
BasePlayer attacker;
try
{
attacker = info.InitiatorPlayer;
if (attacker == null) return;
}
catch
{
return;
}
if (attacker.net?.connection?.authLevel >= 0)
{
if (!permission.UserHasPermission(attacker.UserIDString, "chickenbow.allow")) return;
if (!pcdData.pEntity.ContainsKey(attacker.userID))
{
pcdData.pEntity.Add(attacker.userID, new PCDInfo());
pcdData.pEntity[attacker.userID].name = attacker.displayName;
SaveData();
}
if (pcdData.pEntity[attacker.userID].name == null)
{
pcdData.pEntity[attacker.userID].name = attacker.displayName;
SaveData();
}
pcdData.pEntity[attacker.userID].ChickensKilled++;
if (config.UpdateKillProgress) PrintToChat(attacker, $"{Prefix} You have killed <color=#2DE9FF>{pcdData.pEntity[attacker.userID].ChickensKilled}/{config.ChickenTarget}</color> chickens.");
SaveData();
if (pcdData.pEntity[attacker.userID].ChickensKilled >= config.ChickenTarget)
{
SpawnChickenBow(attacker);
pcdData.pEntity[attacker.userID].ChickensKilled = 0;
SaveData();
}
}
return;
}
DoEffect(chicken.transform.position);
foreach (KeyValuePair<ulong, PCDInfo> kvp in pcdData.pEntity)
{
if (kvp.Value.user_chickens.Contains(chicken.net.ID))
{
kvp.Value.user_chickens.Remove(chicken.net.ID);
SaveData();
break;
}
}
Spawnedchickens.Remove(chicken.net.ID);
SaveData();
ChickenDied = true;
}
#endregion
#region Chatcommands
[ChatCommand("chickenkc")]
private void chickenkc(BasePlayer player)
{
if (!permission.UserHasPermission(player.UserIDString, "chickenbow.allow")) return;
if (!pcdData.pEntity.ContainsKey(player.userID))
{
pcdData.pEntity.Add(player.userID, new PCDInfo());
pcdData.pEntity[player.userID].name = player.displayName;
SaveData();
}
PrintToChat(player, $"{Prefix} You have killed <color=#2DE9FF>{pcdData.pEntity[player.userID].ChickensKilled}/{config.ChickenTarget}</color> chickens so far.");
}
[ChatCommand("chickenbow")]
private void chickenbow(BasePlayer player)
{
if (!permission.UserHasPermission(player.UserIDString, "chickenbow.admin"))
{
PrintToChat(player, $"{Prefix} You lack the authority to use this command, peasant!");
return;
}
SpawnChickenBow(player);
}
#endregion
#region Helpers
void SpawnChickenBow(BasePlayer player)
{
var chickenbow = ItemManager.CreateByItemID(1443579727, 1, config.BowSkin);
chickenbow.name = "Bow of the Chickens";
if (!player.inventory.containerBelt.IsFull())
{
chickenbow.MoveToContainer(player.inventory.containerBelt);
}
else
{
if (!player.inventory.containerMain.IsFull())
{
chickenbow.MoveToContainer(player.inventory.containerMain);
}
else
{
chickenbow.DropAndTossUpwards(player.transform.position, 5);
PrintToChat(player, "<color=#F3FF00>[Chicken Hunter]</color>You had no free slots so the bow was put onto the ground.");
}
}
PrintToChat(player, $"{Prefix} You received a <color=#FC2DFF>Bow of the Chickens</color> for killing {config.ChickenTarget} chickens.Don't lose it!");
}
private void DoEffect(Vector3 location)
{
Effect.server.Run(config.dying_effects.GetRandom(), location);
}
private void TrySpawnChicken(BasePlayer player, Vector3 location)
{
try
{
if (player.GetActiveItem().skin != config.BowSkin) return;
}
catch
{
return;
}
if (!pcdData.pEntity.ContainsKey(player.userID)) pcdData.pEntity.Add(player.userID, new PCDInfo());
var playerData = pcdData.pEntity[player.userID];
if (playerData.user_chickens.Count() >= config.max_user_chickens && !permission.UserHasPermission(player.UserIDString, "chickenbow.admin"))
{
PrintToChat(player, $"{Prefix} You have reached your spawn limit.Kill some of your chickens to spawn more.");
return;
}
var animal = GameManager.server.CreateEntity("assets/rust.ai/agents/chicken/chicken.prefab", location);
animal.Spawn();
Spawnedchickens.Add(animal.net.ID);
playerData.user_chickens.Add(animal.net.ID);
SaveData();
PrintToChat(player, $"{Prefix} You have spawned {playerData.user_chickens.Count()}/{config.max_user_chickens} chickens.");
}
void RemoveChickens()
{
var Chickens = Spawnedchickens;
if (config.UnloadChickens == 1)
{
var ChickenMono = UnityEngine.Object.FindObjectsOfType<Chicken>();
foreach (var mono in ChickenMono)
{
if (!Chickens.Contains(mono.net.ID)) continue;
PrintWarning($"Deleting {mono.ShortPrefabName} ({mono.net.ID})");
mono.GetComponent<Chicken>().Kill();
}
}
foreach (KeyValuePair<ulong, PCDInfo> kvp in pcdData.pEntity)
{
kvp.Value.user_chickens.Clear();
}
Spawnedchickens.Clear();
SaveData();
}
void ConvertChickens()
{
}
#endregion
#region API
bool IsSpawnedChicken(uint id)
{
if (Spawnedchickens.Count() == 0) return false;
return Spawnedchickens.Contains(id);
}
#endregion
}
}