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
}
}