using System; using System.Linq; using System.Reflection; using System.Collections.Generic; using UnityEngine; using Oxide.Core; using Oxide.Core.Plugins; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Facepunch; using Rust; #region Changelogs and ToDo /********************************************************************** * 1.4.0 - Optimised the skull and bone mechanics * - Added API private void OnAnimalSkullCrushReward(BasePlayer player , string itemName , ulong itemId , int amount) returning info * - Added API private void OnAnimalBonesReceived(BasePlayer player, string itemName , int amount , ulong skinId) returning info * * * API : private void OnAnimalSkullCrushReward(BasePlayer player , string itemName , ulong itemId , int amount) { Puts($"{player.displayName} received {amount} {itemName} with skin ID {itemId} from a skull crush!"); } private void OnAnimalBonesReceived(BasePlayer player, string itemName , int amount , ulong skinId) { Puts($"{player.displayName} Received {amount} of {itemName} with skin ID: {skinId}"); } **********************************************************************/ #endregion namespace Oxide.Plugins { [Info("SkinAndBones", "Krungh Crow", "1.4.0")] [Description("Core item Injection for animals")] class SkinAndBones : RustPlugin { #region Variables ulong chaticon = 0; string prefix; bool Debug = false; bool CanConvertBones = true; const string Admin_Perm = "skinandbones.admin"; #region Bone Skin Id's ulong SkinBoneBe = 2582006231; ulong SkinBoneBo = 2582018117; ulong SkinBoneCh = 2582002045; ulong SkinBoneFi = 2583801321; ulong SkinBoneHo = 2582022311; ulong SkinBoneWo = 2582021640; ulong SkinBoneSt = 2582020463; #endregion #region Bone Names const string BoneNameBe = "Bear Bones"; const string BoneNameBo = "Boar Bones"; const string BoneNameCh = "Chicken Bones"; const string BoneNameHo = "Horse Bones"; const string BoneNameSt = "Stag Bones"; const string BoneNameFi = "Fish Bones"; const string BoneNameWo = "Wolf Bones"; #endregion #region Skull skin Id's ulong SkinSkullBe; ulong SkinSkullBo; ulong SkinSkullCh; ulong SkinSkullSh; ulong SkinSkullHo; ulong SkinSkullWo; ulong SkinSkullSt; #endregion #region Skullcrush Amounts int CrushAmountBe; int CrushAmountBo; int CrushAmountCh; int CrushAmountSh; int CrushAmountHo; int CrushAmountSt; int CrushAmountWo; #endregion #region Skull Names const string SkullBe = "Bear Skull"; const string SkullBo = "Boar Skull"; const string SkullCh = "Chicken Skull"; const string SkullSh = "Shark jaws"; const string SkullHo = "Horse Skull"; const string SkullSt = "Stag Skull"; #endregion #endregion #region Init void Init() { if (!LoadConfigVariables()) { Puts("Config file issue detected. Please delete file, or check syntax and fix."); return; } Debug = configData.PlugCFG.Debug; prefix = "[Skin & Bones] "; chaticon = 0; CanConvertBones = configData.CanConvert; CheckSubscriptions(); #region Skull Skin Id's assign SkinSkullBe = configData.SkullId.Bear; SkinSkullBo = configData.SkullId.Boar; SkinSkullCh = configData.SkullId.Chicken; SkinSkullSh = configData.SkullId.Shark; SkinSkullHo = configData.SkullId.Horse; SkinSkullSt = configData.SkullId.Stag; #endregion #region Skullcrush Amounts CrushAmountBe = configData.Crushing.Bear; CrushAmountBo = configData.Crushing.Boar; CrushAmountCh = configData.Crushing.Chicken; CrushAmountSh = configData.Crushing.Shark; CrushAmountHo = configData.Crushing.Horse; CrushAmountSt = configData.Crushing.Stag; CrushAmountWo = configData.Crushing.Wolf; #endregion if (Debug) Puts($"[Debug] Debug is activated if unintentional disable this in the config !"); } #endregion #region Configuration private ConfigData configData; class ConfigData { [JsonProperty(PropertyName = "Main config")] public SettingsPlugin PlugCFG = new SettingsPlugin(); [JsonProperty(PropertyName = "Convert Bones")] public bool CanConvert = true; [JsonProperty(PropertyName = "FX on Fail Crush")] public string FX = "assets/prefabs/misc/halloween/skull_door_knocker/effects/door_knock_fx.prefab"; [JsonProperty(PropertyName = "Bones From Skullcrushing")] public SettingsCrush Crushing = new SettingsCrush(); [JsonProperty(PropertyName = "SkinID's Skulls")] public SettingsSkullID SkullId = new SettingsSkullID(); } class SettingsPlugin { [JsonProperty(PropertyName = "Debug")] public bool Debug = true; } class SettingsCrush { [JsonProperty(PropertyName = "Bear Bones")] public int Bear = 30; [JsonProperty(PropertyName = "Boar Bones")] public int Boar = 15; [JsonProperty(PropertyName = "Chicken Bones")] public int Chicken = 10; [JsonProperty(PropertyName = "Horse Bones")] public int Horse = 25; [JsonProperty(PropertyName = "Shark (fish)Bones")] public int Shark = 40; [JsonProperty(PropertyName = "Stag Bones")] public int Stag = 15; [JsonProperty(PropertyName = "Wolf Bones")] public int Wolf = 20; } class SettingsSkullID { [JsonProperty(PropertyName = "Bear Skull SkinID")] public ulong Bear = 2582058305; [JsonProperty(PropertyName = "Boar Skull SkinID")] public ulong Boar = 2582176436; [JsonProperty(PropertyName = "Chicken Skull SkinID")] public ulong Chicken = 2582166639; [JsonProperty(PropertyName = "Horse Skull SkinID")] public ulong Horse = 2582200089; [JsonProperty(PropertyName = "Shark Skull SkinID")] public ulong Shark = 2583809564; [JsonProperty(PropertyName = "Stag Skull SkinID")] public ulong Stag = 2582184045; } private bool LoadConfigVariables() { try { configData = Config.ReadObject(); } catch { return false; } SaveConf(); return true; } protected override void LoadDefaultConfig() { Puts("Fresh install detected Creating a new config file."); configData = new ConfigData(); SaveConf(); } void SaveConf() => Config.WriteObject(configData, true); #endregion #region LanguageAPI protected override void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary { ["CommandBones"] = "/bones {animalname} {amount} : Gives the animals bones and amounts\n(bear,boar,chicken,fish,horse,stag,wolf)", ["CommandSkull"] = "/skull {animalname} {amount} : Gives the animals skull and amounts\n(bear,boar,chicken,shark,horse,stag,wolf)", ["CrushMessage"] = "You crushed a {0} into {1} {2}", ["CrushMessageFail"] = "You failed crushing the {0}.\nTry crushing them from your inventory", ["GiveMessage"] = "You where given {0}x {1}", ["GiveErrorAmount"] = "Value needs to be higher then 0", ["GiveErrorBones"] = "The server uses normal :bone.fragments: bone.fragments", ["InvalidInput"] = "Please enter a valid command!", ["NoPermission"] = "You do not have permission to use that command!", }, this); } #endregion #region Commands [ChatCommand("bones")] private void cmdBones(BasePlayer player, string command, string[] args) { if (!HasPerm(player, Admin_Perm)) { Player.Message(player, prefix + string.Format(msg("NoPermission", player.UserIDString)), chaticon); return; } int amount; if (args.Length == 0 || (args.Length != 2 && args.Length != 3)) { Player.Message(player, prefix + string.Format(msg("InvalidInput", player.UserIDString)), chaticon); return; } int.TryParse(args[1], out amount); if (amount <= 0) { Player.Message(player, prefix + string.Format(msg("GiveErrorAmount", player.UserIDString)), chaticon); return; } if (CanConvertBones == false) { Player.Message(player, prefix + string.Format(msg("GiveErrorBones", player.UserIDString)), chaticon); return; } else { if (args[0].ToLower() == "bear") { GiveSkinnedBones(player, amount, BoneNameBe, SkinBoneBe); return; } else if (args[0].ToLower() == "boar") { GiveSkinnedBones(player, amount, BoneNameBo, SkinBoneBo); return; } else if (args[0].ToLower() == "chicken") { GiveSkinnedBones(player, amount, BoneNameCh, SkinBoneCh); return; } else if (args[0].ToLower() == "horse") { GiveSkinnedBones(player, amount, BoneNameHo, SkinBoneHo); return; } else if (args[0].ToLower() == "stag") { GiveSkinnedBones(player, amount, BoneNameSt, SkinBoneSt); return; } else if (args[0].ToLower() == "fish") { GiveSkinnedBones(player, amount, BoneNameFi, SkinBoneFi); return; } else if (args[0].ToLower() == "wolf") { GiveSkinnedBones(player, amount, BoneNameWo, SkinBoneWo); return; } else { Player.Message(player, prefix + string.Format(msg("InvalidInput", player.UserIDString)), chaticon); return; } } } [ChatCommand("skull")] private void cmdSkull(BasePlayer player, string command, string[] args) { if (!HasPerm(player, Admin_Perm)) { Player.Message(player, prefix + string.Format(msg("NoPermission", player.UserIDString)), chaticon); return; } int amount; if (args.Length == 0 || (args.Length != 2 && args.Length != 3)) { Player.Message(player, prefix + string.Format(msg("InvalidInput", player.UserIDString)), chaticon); return; } int.TryParse(args[1], out amount); if (amount <= 0) { Player.Message(player, prefix + string.Format(msg("GiveErrorAmount", player.UserIDString)), chaticon); return; } else { if (args[0].ToLower() == "bear") { GiveSkinnedSkull(player, amount, SkullBe, SkinSkullBe); return; } else if (args[0].ToLower() == "boar") { GiveSkinnedSkull(player, amount, SkullBo, SkinSkullBo); return; } else if (args[0].ToLower() == "chicken") { GiveSkinnedSkull(player, amount, SkullCh, SkinSkullCh); return; } else if (args[0].ToLower() == "horse") { GiveSkinnedSkull(player, amount, SkullHo, SkinSkullHo); return; } else if (args[0].ToLower() == "stag") { GiveSkinnedSkull(player, amount, SkullSt, SkinSkullSt); return; } else if (args[0].ToLower() == "shark") { GiveSkinnedSkull(player, amount, SkullSh, SkinSkullSh); return; } else if (args[0].ToLower() == "wolf") { GiveSkinnedSkull(player, amount, null, 0); return; } else { Player.Message(player, prefix + string.Format(msg("InvalidInput", player.UserIDString)), chaticon); return; } } } #endregion #region Helpers bool HasPerm(BasePlayer player, string perm) { return permission.UserHasPermission(player.UserIDString, perm); } void CheckSubscriptions() { permission.RegisterPermission(Admin_Perm, this); timer.Once(3f, () => { if (configData.CanConvert == false) { Unsubscribe(nameof(OnItemAction)); if (Debug) Puts($"Unsubscribed to OnItemAction"); } Puts("Checked Subscriptions"); }); } void ConvertItem(BasePlayer player, Item item , string _name , ulong _id) { item.name = _name; item.skin = _id; item.MarkDirty(); if (Debug) Puts($"{player} Converted {item.amount} [{_name}]"); Interface.CallHook("OnAnimalBonesReceived", player , _name , item.amount, _id); } void ConvertCrush(BasePlayer player, Item item, int _amount, string _name, ulong _id) { if(item.GetRootContainer() != player.inventory.containerMain) return; item.UseItem(); Item bones = ItemManager.CreateByName("bone.fragments", 1); bones.amount = _amount; bones.name = _name; bones.skin = _id; bones.MarkDirty(); player.inventory.GiveItem(bones, null); Interface.CallHook("OnAnimalSkullCrushReward" , player , _name , _id , _amount); if (Debug) Puts($"{player.displayName} crushed a {item.name} into X{_amount}[{bones.name}]"); Player.Message(player, prefix + string.Format(msg($"CrushMessage", player.UserIDString), item.name, _amount, _name), chaticon); } void GiveSkinnedBones(BasePlayer player, int _amount, string _name, ulong _id)//Bones { Item bones = ItemManager.CreateByName("bone.fragments", 1); bones.amount = _amount; bones.name = _name; bones.skin = _id; bones.MarkDirty(); player.inventory.GiveItem(bones, null); if (Debug) Puts($"{player.displayName} was given {_amount}x {bones.name}"); Player.Message(player, prefix + string.Format(msg($"GiveMessage", player.UserIDString),_amount, bones.name), chaticon); } void GiveSkinnedSkull(BasePlayer player, int _amount, string _name, ulong _id)//skulls { Item bones = ItemManager.CreateByName("skull.wolf", 1); bones.amount = _amount; bones.name = _name; bones.skin = _id; bones.MarkDirty(); player.inventory.GiveItem(bones, null); if (Debug) Puts($"{player.displayName} was given {_amount}x {bones.name}"); Player.Message(player, prefix + string.Format(msg($"GiveMessage", player.UserIDString), _amount, bones.name), chaticon); } #endregion #region Hooks void OnEntitySpawned(BaseCorpse corpse) { if (corpse == null || corpse.IsDestroyed) return; var dispenser = corpse.GetComponent(); if (dispenser == null) return; var validCorpses = new List { "bear.corpse", "boar.corpse", "chicken.corpse", "horse.corpse", "shark.corpse", "stag.corpse" }; if (validCorpses.Any(corpseName => corpse.ToString().Contains(corpseName))) { Item skull = ItemManager.CreateByName("skull.wolf" , 1 , 0); if (Debug) Puts($"A {corpse} was injected with a Skull"); ItemAmount SkullInfo = new ItemAmount() { itemDef = skull.info , amount = 1 , startAmount = 1 }; dispenser.containedItems.Add(SkullInfo); dispenser.Initialize(); } } private Dictionary AnimalSkinMap; void InitializeAnimalSkinMap() { AnimalSkinMap = new Dictionary { { "bear.corpse", ("Bear Bones", SkinBoneBe, SkullBe, SkinSkullBe) }, { "polarbear.corpse", ("Bear Bones", SkinBoneBe, SkullBe, SkinSkullBe) }, { "boar.corpse", ("Boar Bones", SkinBoneBo, SkullBo, SkinSkullBo) }, { "chicken.corpse", ("chicken Bones", SkinBoneCh, SkullCh, SkinSkullCh) }, { "horse.corpse", ("Horse Bones", SkinBoneHo, SkullHo, SkinSkullHo) }, { "shark.corpse", ("Fish Bones", SkinBoneFi, SkullSh , SkinSkullSh) }, { "stag.corpse", ("Stag Bones", SkinBoneSt, SkullSt, SkinSkullSt) }, { "wolf.corpse", ("Wolf Bones", SkinBoneWo, null, 0) } // Only bone, no skull }; } void OnServerInitialized() { InitializeAnimalSkinMap(); } void OnDispenserGather(ResourceDispenser dispenser , BaseEntity entity , Item item) { BasePlayer player = entity.ToPlayer(); if (player == null || dispenser == null || item == null) return; string dispenserKey = dispenser.gameObject.ToBaseEntity()?.ShortPrefabName; if (AnimalSkinMap.TryGetValue(dispenserKey , out var skinData)) { if (item.info.itemid == 1719978075 && CanConvertBones) // Bone item ID { ConvertItem(player , item , skinData.BoneName , skinData.BoneSkin); } else if (item.info.itemid == 2048317869 && skinData.SkullName != null) // Skull item ID { ConvertItem(player , item , skinData.SkullName , skinData.SkullSkin); } } } private object OnItemAction(Item item, string action, BasePlayer player) { BasePlayer ownerPlayer = item.GetOwnerPlayer(); if (action == "crush") { try { if (item.info.shortname == "skull.wolf") { if (item.name == null) { item.name = "Wolf Skull"; } #region bear skull crush if (item.name.ToLower().Contains("bear skull") && item != null) { ConvertCrush(ownerPlayer, item, CrushAmountBe, BoneNameBe, SkinBoneBe); if (item.amount > 1) return true; return true; } #endregion #region boar skull crush if (item.name.ToLower().Contains("boar skull") && item != null) { ConvertCrush(ownerPlayer, item, CrushAmountBo, BoneNameBo, SkinBoneBo); if (item.amount > 1) return true; return true; } #endregion #region chicken skull crush if (item.name.ToLower().Contains("chicken skull") && item != null) { ConvertCrush(ownerPlayer, item, CrushAmountCh, BoneNameCh, SkinBoneCh); if (item.amount > 1) return true; return true; } #endregion #region horse skull crush if (item.name.ToLower().Contains("horse skull")) { ConvertCrush(ownerPlayer, item, CrushAmountHo, BoneNameHo, SkinBoneHo); if (item.amount > 1) return true; return true; } #endregion #region stag skull crush if (item.name.ToLower().Contains("stag skull")) { ConvertCrush(ownerPlayer, item, CrushAmountSt, BoneNameSt, SkinBoneSt); if (item.amount > 1) return true; return true; } #endregion #region shark skull crush if (item.name.ToLower().Contains("shark jaws")) { ConvertCrush(ownerPlayer, item, CrushAmountSh, BoneNameFi, SkinBoneFi); if (item.amount > 1) return true; return true; } #endregion #region wolf skull crush (default) if(item != null || ownerPlayer != null || item.name.ToLower().Contains("wolf skull")) { ConvertCrush(ownerPlayer, item, CrushAmountWo, BoneNameWo, SkinBoneWo); if (item.amount > 1) return true; return true; } #endregion } } catch { if (item.skin == 0) return null; if (Debug) Puts($"A {item.name} was crushed but the bone extraction was unsuccesfull]"); Player.Message(player, prefix + string.Format(msg($"CrushMessageFail", player.UserIDString), item.name), chaticon); Effect.server.Run(configData.FX, player.transform.position); return true; } } return null; } #endregion #region Message helper private string msg(string key, string id = null) => lang.GetMessage(key, this, id); #endregion } }