using System; using System.Linq; using System.Reflection; using System.Collections.Generic; using UnityEngine; using Oxide.Core; using Oxide.Core.Plugins; using Oxide.Game.Rust.Libraries; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Facepunch; using Rust.Ai.HTN; using Rust.Ai.Gen2; #region Changelogs and ToDo /********************************************************************** * * 1.0.0 : - Initial release * 1.0.1 : - Some performance tweeks and Nullchecks * - Added Omega spawn radius to config * 1.0.2 : - Added perm alphaanimals.marker * - Added perm alphaanimals.economics * - Added perm alphaanimals.serverrewards * - Added Mapmarker system * - Added support for Economics * - Added support for ServerRewards * - Added msg EngageSimpleKill to Language file * - Added msg EngageFullKill to Language file * - Added msg AlphaAnnounce to Language file * - Added Random omega animal Health settings * - Added Alpha spawn announcement settings to config * 1.0.3 - Updated gametip notifications * - Fixed Omega animals not getting random hp values * - Fixed Markers not initiating after serverstartup * - Removed damage to player when omegas appear * * 1.2.0 - Removed mapmarkers * - Cleanup * - Fixed economics handout * - Fixed ServerRewards handout * - Reworked the reward checks * - Added custom lootitem names * - Added AlwaysInclude for loot items (true/false) * - Added gametips for damage progression * - Monobehaviour changes * - Optimised adding the Omega animals * - Fixed animal effects * - New cfg file is generated (backup old version) * - Added severall hooks on alpha kills * - Added severall hooks on omega kills * - Added severall hooks on omega spawns * - Fix for Gametip not closing * 1.2.1 - Hotfix for wrong debug method * 1.2.2 - Added support for Wolf2 * 1.2.3 - Patched version number * - Possible fix for nullcheck on timer * 1.2.4 - patched for Dec rust update * * API // Pre definition trigger on Alpha/Omega animal kill (before the animal type is defined) void OnAlphaAnimalKilled(BaseAnimalNPC animal, HitInfo info); void OmegaAnimalKilled(BaseAnimalNPC animal, HitInfo info); // Alpha animal kills void OnAlphaBearKilled(BaseAnimalNPC animal, HitInfo info); void OnAlphaPolarbearKilled(BaseAnimalNPC animal, HitInfo info); void OnAlphaWolfKilled(BaseAnimalNPC animal, HitInfo info); // Omega animal kills void OnOmegaBearKilled(BaseAnimalNPC animal, HitInfo info); void OnOmegaPolarbearKilled(BaseAnimalNPC animal, HitInfo info); void OnOmegaWolfKilled(BaseAnimalNPC animal, HitInfo info); // Omega animal spawns void OnOmegaBearSpawned(BaseAnimalNPC animal); void OnOmegaPolarbearSpawned(BaseAnimalNPC animal); void OnOmegaWolfSpawned(BaseAnimalNPC animal); * **********************************************************************/ #endregion namespace Oxide.Plugins { [Info("AlphaAnimals", "Krungh Crow", "1.2.4")] [Description("Alpha Animal events")] class AlphaAnimals : RustPlugin { #region PluginReference [PluginReference] private Plugin Economics, ServerRewards; #endregion #region Variables public static AlphaAnimals instance; ulong chaticon = 0; string prefix; bool Debug = false; bool UseEconomics; bool UseSR; string _Wolf = "assets/rust.ai/agents/wolf/wolf.prefab"; string _Bear = "assets/rust.ai/agents/bear/bear.prefab"; string _PBear = "assets/rust.ai/agents/bear/polarbear.prefab"; string _WolfHowl = "assets/bundled/prefabs/fx/player/howl.prefab"; string _WaterSplash = "assets/bundled/prefabs/fx/explosions/water_bomb.prefab"; string _BearDeath = "assets/prefabs/npc/bear/sound/death.prefab"; string _AnimalType; int _Packsize; const string TipSimple = "alphaanimals.tipsimple"; const string TipFull = "alphaanimals.tipfull"; const string Eco_Perm = "alphaanimals.economics"; const string SR_Perm = "alphaanimals.serverrewards"; #endregion #region MonoBehaviour private class Animals : MonoBehaviour { private Vector3 home; private BaseNpc npc; private float distance; private float time; private void Awake() { npc = GetComponent(); if (npc == null) { instance.Puts("BaseAnimalNPC component is missing from this GameObject."); return; } home = npc.transform.position; distance = 10f; enabled = false; InvokeRepeating("CheckDistance" , 1f , 2f); InvokeRepeating("CheckBehaviour" , 1f , 2f); npc.SetFact(BaseNpc.Facts.Speed , (byte)BaseNpc.SpeedEnum.Walk , true , true); } private void CheckBehaviour() { if (npc == null || npc.IsDestroyed) return; npc.SetFact(BaseNpc.Facts.IsAfraid, 1, true, true); } private void CheckDistance() { if (npc == null || npc.IsDestroyed) { instance?.Puts("npc is null or destroyed in CheckDistance."); return; } Vector3 npcPosition = npc.transform.position; string npcName = npc.name; float distanceFromHome = Vector3.Distance(home , npcPosition); if (distanceFromHome < 2) { npc.CurrentBehaviour = BaseNpc.Behaviour.Idle; npc.StopMoving(); instance?.Puts($"{npcName} is at home spawn point {home}"); return; } if (distanceFromHome > distance) { npc.UpdateDestination(home); npc.CurrentBehaviour = BaseNpc.Behaviour.Wander; npc.SetFact(BaseNpc.Facts.Speed , (byte)BaseNpc.SpeedEnum.Walk , true , true); instance?.Puts($"Sending {npcName} home {home}"); } } public void DoDestroy() { if (npc != null) { npc.Kill(); } Destroy(this); } private void OnDestroy() { CancelInvoke("CheckDistance"); CancelInvoke("CheckBehaviour"); } } #endregion #region Configuration void Init() { if (!LoadConfigVariables()) { Puts("Config file issue detected. Please delete file, or check syntax and fix."); return; } Debug = configData.PlugCFG.Debug; UseEconomics = configData.Rewards.UseEco; UseSR = configData.RewardsSR.UseSR; prefix = configData.PlugCFG.Prefix; chaticon = configData.PlugCFG.Chaticon; permission.RegisterPermission(TipSimple, this); permission.RegisterPermission(TipFull, this); permission.RegisterPermission(Eco_Perm, this); permission.RegisterPermission(SR_Perm, this); if (Debug) Puts($"[Debug] trigger for Debug is true"); } private ConfigData configData; class ConfigData { [JsonProperty(PropertyName = "Plugin")] public SettingsPlugin PlugCFG = new SettingsPlugin(); [JsonProperty(PropertyName = "Economics")] public RewardingsEco Rewards = new RewardingsEco(); [JsonProperty(PropertyName = "ServerRewards")] public RewardingsSR RewardsSR = new RewardingsSR(); [JsonProperty(PropertyName = "Animals")] public AnimalData Animals = new AnimalData(); } class RewardingsSR { [JsonProperty(PropertyName = "Use ServerRewards")] public bool UseSR = false; [JsonProperty(PropertyName = "Alpha Bear points")] public int BearPoints = 300; [JsonProperty(PropertyName = "Omega Bear points")] public int OBearPoints = 100; [JsonProperty(PropertyName = "Alpha Polarbear points")] public int PBearPoints = 400; [JsonProperty(PropertyName = "Omega Polarbear points")] public int OPBearPoints = 150; [JsonProperty(PropertyName = "Alpha Wolf points")] public int WolfPoints = 200; [JsonProperty(PropertyName = "Omega Wolf points")] public int OWolfPoints = 50; } class RewardingsEco { [JsonProperty(PropertyName = "Use Economics")] public bool UseEco = false; [JsonProperty(PropertyName = "Alpha Bear points")] public double BearPoints = 300; [JsonProperty(PropertyName = "Omega Bear points")] public double OBearPoints = 100; [JsonProperty(PropertyName = "Alpha Polarbear points")] public double PBearPoints = 400; [JsonProperty(PropertyName = "Omega Polarbear points")] public double OPBearPoints = 150; [JsonProperty(PropertyName = "Alpha Wolf points")] public double WolfPoints = 200; [JsonProperty(PropertyName = "Omega Wolf points")] public double OWolfPoints = 50; } class AnimalData { [JsonProperty(PropertyName = "Life Duration (minutes)")] public float Lifetime = 5f; [JsonProperty(PropertyName = "Spawn Radius")] public int Radius = 12; [JsonProperty(PropertyName = "Bear Packsize")] public int PacksizeB = 2; [JsonProperty(PropertyName = "Bear settings")] public OmegaSettings OmegaB = new OmegaSettings(); [JsonProperty(PropertyName = "Polarbear Packsize")] public int PacksizePB = 2; [JsonProperty(PropertyName = "Polarbear settings")] public OmegaSettings OmegaPB = new OmegaSettings(); [JsonProperty(PropertyName = "Wolf Packsize")] public int PacksizeW = 5; [JsonProperty(PropertyName = "Wolf settings")] public OmegaSettings OmegaW = new OmegaSettings(); [JsonProperty(PropertyName = "Use Random Skins")] public bool RandomSkins = false; [JsonProperty(PropertyName = "Loot settings (Alphas)")] public LootSettings Loots = new LootSettings(); } class OmegaSettings { [JsonProperty(PropertyName = "Min HP")] public float MinHP = 350f; [JsonProperty(PropertyName = "Max HP")] public float MaxHP = 600f; } class SettingsPlugin { [JsonProperty(PropertyName = "Debug")] public bool Debug = false; [JsonProperty(PropertyName = "Chat Steam64ID")] public ulong Chaticon = 0; [JsonProperty(PropertyName = "Chat Prefix")] public string Prefix = "[AlphaAnimals] "; [JsonProperty(PropertyName = "Anounce Alpha spawns")] public bool Anounce = true; } class LootSettings { [JsonProperty(PropertyName = "Spawn Min Amount Items")] public int MinAmount = 1; [JsonProperty(PropertyName = "Spawn Max Amount Items")] public int MaxAmount = 3; [JsonProperty(PropertyName = "Loot Table" , ObjectCreationHandling = ObjectCreationHandling.Replace)] public List Loot { get; set; } = DefaultLoot; } 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 { ["AlphaAnnounce"] = "A {animal} was located around Grid {location}", ["EngageSimple"] = "carefull This is a {animal}", ["EngageFull"] = "carefull This is a {animal} {health} HP", ["EngageSimpleKill"] = "You killed the {animal}", ["EngageFullKill"] = "You got points killing the {animal}", ["EngageFull"] = "carefull This is a {animal} {health} HP", ["KillAlpha"] = "You Killed a {animal} and {packsize} Omega's are summoned", ["KillAlphaAll"] = "{player} Killed a {animal} and {packsize} Omega's are summoned", ["KillOmega"] = "You Killed the {animal}", }, this); } #endregion #region Oxide Hooks private void Unload() { RemoveOmegas(); } void OnEntityDeath(BaseEntity entity , HitInfo info) { if (entity is BaseAnimalNPC animal) { BasePlayer attacker = info?.InitiatorPlayer; if (attacker == null) return; double Reward = 0; int SRReward = 0; int _Packsize = 0; float MinHealth = 100.0f; float MaxHealth = 300.0f; string AnimalPrefab = null; if (animal.name.Contains("Alpha")) { Interface.CallHook("OnAlphaAnimalKilled" , animal , info); Reward = GetEcoRewardForAnimal(animal); SRReward = GetSRRewardForAnimal(animal); switch (animal) { case Bear _: Interface.CallHook("OnAlphaBearKilled" , animal , info); SpawnRadLoot(animal.transform.position + new Vector3(0f , 0.5f , 0f) , animal.transform.rotation , "Alpha Bear"); Effect.server.Run(_BearDeath , animal.transform.position); AnimalPrefab = _Bear; _Packsize = configData.Animals.PacksizeB; MinHealth = configData.Animals.OmegaB.MinHP; MaxHealth = configData.Animals.OmegaB.MaxHP; break; case Polarbear _: Interface.CallHook("OnAlphaPolarbearKilled" , animal , info); SpawnRadLoot(animal.transform.position + new Vector3(0f , 0.5f , 0f) , animal.transform.rotation , "Alpha Polarbear"); Effect.server.Run(_BearDeath , animal.transform.position); AnimalPrefab = _PBear; _Packsize = configData.Animals.PacksizePB; MinHealth = configData.Animals.OmegaPB.MinHP; MaxHealth = configData.Animals.OmegaPB.MaxHP; break; case Wolf _: Interface.CallHook("OnAlphaWolfKilled" , animal , info); SpawnRadLoot(animal.transform.position + new Vector3(0f , 0.5f , 0f) , animal.transform.rotation , "Alpha Wolf"); Effect.server.Run(_WolfHowl , animal.transform.position); AnimalPrefab = _Wolf; _Packsize = configData.Animals.PacksizeW; MinHealth = configData.Animals.OmegaW.MinHP; MaxHealth = configData.Animals.OmegaW.MaxHP; break; } for (int i = 0; i < _Packsize; i++) { SpawnAnimal(attacker.transform.position , AnimalPrefab , MinHealth , MaxHealth); } if (attacker != null) Player.Message(attacker , msg("KillAlpha").Replace("{animal}" , animal.name).Replace("{packsize}" , _Packsize.ToString()) , chaticon); Effect.server.Run(_WaterSplash , animal.transform.position); } if (animal.name.Contains("Omega")) { Interface.CallHook("OnOmegaAnimalKilled" , animal , info); switch (animal) { case Bear _: Interface.CallHook("OnOmegaBearKilled" , animal , info); Effect.server.Run(_BearDeath , animal.transform.position); break; case Polarbear _: Interface.CallHook("OnOmegaPolarBearKilled" , animal , info); Effect.server.Run(_BearDeath , animal.transform.position); break; case Wolf _: Interface.CallHook("OnOmegaWolfKilled" , animal , info); Effect.server.Run(_WolfHowl , animal.transform.position); break; } Reward = GetEcoRewardForAnimal(animal); SRReward = GetSRRewardForAnimal(animal); Effect.server.Run(_WaterSplash , animal.transform.position); } if (UseEconomics && Economics != null && HasPerm(attacker , Eco_Perm)) { if (Reward != 0) { Economics?.Call("Deposit" , attacker.userID , Reward); if (Debug) Puts($"{attacker.displayName} killed a {animal.name} and got {Reward} Economic points"); } } if (UseSR && ServerRewards != null && HasPerm(attacker , SR_Perm)) { if (SRReward != 0) { ServerRewards?.Call("AddPoints" , attacker.userID , SRReward); if (Debug) Puts($"{attacker.displayName} killed a {animal.name} and got {SRReward} ServerRewards points"); } } if (Debug && attacker != null) Puts($"Target : {animal} Event : {animal.name} killed by {attacker.displayName}"); if (IsAlphaOrOmega(animal.name)) { if (HasPerm(attacker , TipFull) && (HasPerm(attacker , Eco_Perm) || HasPerm(attacker , SR_Perm))) { TIP(attacker , Info("EngageFullKill").Replace("{animal}" , animal.name) , 16 , "white" , 0f); } else if (HasPerm(attacker , TipSimple)) { TIP(attacker , Info("EngageSimpleKill").Replace("{animal}" , animal.name) , 16 , "white" , 0f); } } } if (entity is BaseNPC2 npc) { BasePlayer attacker = info?.InitiatorPlayer; if (attacker == null) return; double Reward = 0; int SRReward = 0; int _Packsize = 0; float MinHealth = 100.0f; float MaxHealth = 300.0f; string AnimalPrefab = null; if (npc.name.Contains("Alpha")) { Interface.CallHook("OnAlphaAnimalKilled" , npc , info); Reward = GetEcoRewardForAnimal(npc); SRReward = GetSRRewardForAnimal(npc); switch (npc) { case Wolf2 _: Interface.CallHook("OnAlphaWolf2Killed" , npc , info); SpawnRadLoot(npc.transform.position + new Vector3(0f , 0.5f , 0f) , npc.transform.rotation , "Alpha Wolf2"); Effect.server.Run(_WolfHowl , npc.transform.position); AnimalPrefab = _Wolf; _Packsize = configData.Animals.PacksizeW; MinHealth = configData.Animals.OmegaW.MinHP; MaxHealth = configData.Animals.OmegaW.MaxHP; break; } for (int i = 0; i < _Packsize; i++) { SpawnAnimal(attacker.transform.position , AnimalPrefab , MinHealth , MaxHealth); } if (attacker != null) Player.Message(attacker , msg("KillAlpha").Replace("{animal}" , npc.name).Replace("{packsize}" , _Packsize.ToString()) , chaticon); Effect.server.Run(_WaterSplash , npc.transform.position); } if (npc.name.Contains("Omega")) { Interface.CallHook("OnOmegaAnimalKilled" , npc , info); switch (npc) { case Wolf2 _: Interface.CallHook("OnOmegaWolf2Killed" , npc , info); Effect.server.Run(_WolfHowl , npc.transform.position); break; } Reward = GetEcoRewardForAnimal(npc); SRReward = GetSRRewardForAnimal(npc); Effect.server.Run(_WaterSplash , npc.transform.position); } if (UseEconomics && Economics != null && HasPerm(attacker , Eco_Perm)) { if (Reward != 0) { Economics?.Call("Deposit" , attacker.userID , Reward); if (Debug) Puts($"{attacker.displayName} killed a {npc.name} and got {Reward} Economic points"); } } if (UseSR && ServerRewards != null && HasPerm(attacker , SR_Perm)) { if (SRReward != 0) { ServerRewards?.Call("AddPoints" , attacker.userID , SRReward); if (Debug) Puts($"{attacker.displayName} killed a {npc.name} and got {SRReward} ServerRewards points"); } } if (Debug && attacker != null) Puts($"Target : {npc} Event : {npc.name} killed by {attacker.displayName}"); if (IsAlphaOrOmega(npc.name)) { if (HasPerm(attacker , TipFull) && (HasPerm(attacker , Eco_Perm) || HasPerm(attacker , SR_Perm))) { TIP(attacker , Info("EngageFullKill").Replace("{animal}" , npc.name) , 16 , "white" , 0f); } else if (HasPerm(attacker , TipSimple)) { TIP(attacker , Info("EngageSimpleKill").Replace("{animal}" , npc.name) , 16 , "white" , 0f); } } } } void OnEntitySpawned(BaseEntity entity) { if (entity is BaseAnimalNPC animal) { var animalEntity = animal; timer.Once(1f , () => { if (animalEntity != null && (animalEntity.name.Contains("Alpha") || animalEntity.name.Contains("Omega"))) { if (Debug) Puts($"Target : {animalEntity} ({(int)animalEntity.health}HP) Event : {animalEntity.name} Spawned"); if (animalEntity.name.Contains("Alpha") && configData.PlugCFG.Anounce) { foreach (var player in BasePlayer.activePlayerList) { Player.Message(player , msg("AlphaAnnounce") .Replace("{animal}" , animalEntity.name) .Replace("{location}" , GetGrid(animalEntity.transform.position)) , chaticon); } } } }); } else if (entity is BaseNPC2 npc) { var npcEntity = npc; timer.Once(1f , () => { if (npcEntity != null && (npcEntity.name.Contains("Alpha") || npcEntity.name.Contains("Omega"))) { if (Debug) Puts($"Target : {npcEntity} ({(int)npcEntity.health}HP) Event : {npcEntity.name} Spawned"); if (npcEntity.name.Contains("Alpha") && configData.PlugCFG.Anounce) { foreach (var player in BasePlayer.activePlayerList) { Player.Message(player , msg("AlphaAnnounce") .Replace("{animal}" , npcEntity.name) .Replace("{location}" , GetGrid(npcEntity.transform.position)) , chaticon); } } } }); } } void OnEntityTakeDamage(BaseEntity entity , HitInfo info) { if (entity is BaseAnimalNPC animalEntity) { HandleAnimalDamage(animalEntity , info); } else if (entity is BaseNPC2 npcEntity) { HandleNpcDamage(npcEntity , info); } } void HandleAnimalDamage(BaseAnimalNPC animalEntity , HitInfo info) { if (animalEntity == null || info?.InitiatorPlayer == null) return; BasePlayer player = info.InitiatorPlayer; if (animalEntity.name.Contains("Alpha") || animalEntity.name.Contains("Omega")) { var Type = animalEntity.name; if (HasPerm(player , TipFull)) { var Health = Convert.ToInt32(animalEntity.health); var MaxHealth = Convert.ToInt32(animalEntity._maxHealth); string FullHealth = $"{Health}/{MaxHealth}"; WARNING(player , Info("EngageFull").Replace("{animal}" , Type).Replace("{health}" , FullHealth) , 16 , "blue" , 0f); } else if (HasPerm(player , TipSimple)) { WARNING(player , Info("EngageSimple").Replace("{animal}" , Type) , 16 , "blue" , 0f); } } } void HandleNpcDamage(BaseNPC2 npcEntity , HitInfo info) { if (npcEntity == null || info?.InitiatorPlayer == null) return; BasePlayer player = info.InitiatorPlayer; if (npcEntity.name.Contains("Alpha") || npcEntity.name.Contains("Omega")) { var Type = npcEntity.name; if (HasPerm(player , TipFull)) { var Health = Convert.ToInt32(npcEntity.health); var MaxHealth = Convert.ToInt32(npcEntity._maxHealth); string FullHealth = $"{Health}/{MaxHealth}"; WARNING(player , Info("EngageFull").Replace("{animal}" , Type).Replace("{health}" , FullHealth) , 16 , "blue" , 0f); } else if (HasPerm(player , TipSimple)) { WARNING(player , Info("EngageSimple").Replace("{animal}" , Type) , 16 , "blue" , 0f); } } } #endregion #region Helpers bool IsAlphaOrOmega(string animalName) { return animalName.Contains("Alpha") || animalName.Contains("Omega"); } double GetEcoRewardForAnimal(BaseEntity entity) { bool isAlpha = entity.name.Contains("Alpha"); bool isOmega = entity.name.Contains("Omega"); switch (entity) { // BaseAnimalNPC types (Bear, Polarbear, Wolf) case BaseAnimalNPC animal when animal is Bear _ && isAlpha: return configData.Rewards.BearPoints; case BaseAnimalNPC animal when animal is Bear _ && isOmega: return configData.Rewards.OBearPoints; case BaseAnimalNPC animal when animal is Polarbear _ && isAlpha: return configData.Rewards.PBearPoints; case BaseAnimalNPC animal when animal is Polarbear _ && isOmega: return configData.Rewards.OPBearPoints; case BaseAnimalNPC animal when animal is Wolf _ && isAlpha: return configData.Rewards.WolfPoints; case BaseAnimalNPC animal when animal is Wolf _ && isOmega: return configData.Rewards.OWolfPoints; // BaseNPC2 types (like Wolf2) case BaseNPC2 npc when npc is Wolf2 _ && isAlpha: return configData.Rewards.WolfPoints; case BaseNPC2 npc when npc is Wolf2 _ && isOmega: return configData.Rewards.OWolfPoints; default: return 0; } } int GetSRRewardForAnimal(BaseEntity entity) { bool isAlpha = entity.name.Contains("Alpha"); bool isOmega = entity.name.Contains("Omega"); switch (entity) { // BaseAnimalNPC types (Bear, Polarbear, Wolf) case BaseAnimalNPC animal when animal is Bear _ && isAlpha: return configData.RewardsSR.BearPoints; case BaseAnimalNPC animal when animal is Bear _ && isOmega: return configData.RewardsSR.OBearPoints; case BaseAnimalNPC animal when animal is Polarbear _ && isAlpha: return configData.RewardsSR.PBearPoints; case BaseAnimalNPC animal when animal is Polarbear _ && isOmega: return configData.RewardsSR.OPBearPoints; case BaseAnimalNPC animal when animal is Wolf _ && isAlpha: return configData.RewardsSR.WolfPoints; case BaseAnimalNPC animal when animal is Wolf _ && isOmega: return configData.RewardsSR.OWolfPoints; // BaseNPC2 types (like Wolf2) case BaseNPC2 npc when npc is Wolf2 _ && isAlpha: return configData.RewardsSR.WolfPoints; case BaseNPC2 npc when npc is Wolf2 _ && isOmega: return configData.RewardsSR.OWolfPoints; default: return 0; } } private static string GetGrid(Vector3 position) => MapHelper.PositionToString(position); bool HasPerm(BasePlayer player,string perm) { return permission.UserHasPermission(player.UserIDString, perm); } private void RemoveOmegas() { foreach (var animal in UnityEngine.Object.FindObjectsOfType().ToList()) { if (animal.name.Equals("Omega bear")|| animal.name.Equals("Omega polarbear") || animal.name.Equals("Omega wolf")) { Puts($"removed {animal.name}"); animal.DoDestroy(); } } } private void SpawnAnimal(Vector3 position , string Type , float MinHealth , float MaxHealth) { var RandomHealth = UnityEngine.Random.Range(MinHealth , MaxHealth); int radius = configData.Animals.Radius; Vector3 pos = position + UnityEngine.Random.onUnitSphere * radius; pos.y = TerrainMeta.HeightMap.GetHeight(pos); BaseAnimalNPC animal = (BaseAnimalNPC)GameManager.server.CreateEntity(Type , pos , new Quaternion() , true); if (!animal) { return; } // Determine if the animal is Bear, PolarBear, or Wolf and call appropriate hooks if (animal is Bear) { Interface.CallHook("OnOmegaBearSpawned" , animal); } else if (animal is Polarbear) { Interface.CallHook("OnOmegaPolarbearSpawned" , animal); } else if (animal is Wolf) { Interface.CallHook("OnOmegaWolfSpawned" , animal); } animal.Spawn(); animal.gameObject.AddComponent(); timer.Once(1f , () => { animal.InitializeHealth(RandomHealth , RandomHealth); }); animal.name = $"Omega {animal.ShortPrefabName}"; animal.SendNetworkUpdate(); timer.Once(configData.Animals.Lifetime * 60 , () => { if (animal != null) { Effect.server.Run(_WolfHowl , animal.transform.position); Effect.server.Run(_WaterSplash , animal.transform.position); animal.Kill(); } return; }); } #endregion #region Message helper private string msg(string key, string id = null) => prefix + lang.GetMessage(key, this, id); private string Info(string key, string id = null) => lang.GetMessage(key, this, id); void TIP(BasePlayer player, string message, int textsize, string textcolor, float dur) { if (player == null) return; string msg = Info(message); if (textsize == 0) textsize = 14; string newmsg = $"{msg}"; try { player.SendConsoleCommand("gametip.showtoast_translated" , 1 , "" , newmsg); if (dur != 0) timer.Once(dur, () => player?.SendConsoleCommand("gametip.hidegametip")); } catch { Puts("catched the gametip"); } } void WARNING(BasePlayer player, string message, int textsize, string textcolor, float dur) { if (player == null) return; string msg = Info(message); if (textsize == 0) textsize = 14; string newmsg = $"{msg}"; try { player.SendConsoleCommand("gametip.showtoast_translated", 1f, null, newmsg); player.SendConsoleCommand("gametip.showtoast_translated" , 1 , "" , newmsg); } catch { Puts("catched the toast"); } } #endregion #region Loot private Dictionary> Skins { get; set; } = new Dictionary>(); private static List DefaultLoot { get { return new List { new LootItems { shortname = "ammo.pistol", name = "", amount = 5, skin = 0, amountMin = 5, AlwaysInclude = false }, new LootItems { shortname = "ammo.pistol.fire", name = "", amount = 5, skin = 0, amountMin = 5, AlwaysInclude = false }, new LootItems { shortname = "ammo.pistol.hv", name = "", amount = 5, skin = 0, amountMin = 5, AlwaysInclude = false }, new LootItems { shortname = "ammo.rifle", name = "", amount = 5, skin = 0, amountMin = 5, AlwaysInclude = false }, new LootItems { shortname = "ammo.rifle.explosive", name = "", amount = 5, skin = 0, amountMin = 5, AlwaysInclude = false }, new LootItems { shortname = "ammo.rifle.hv", name = "", amount = 5, skin = 0, amountMin = 5, AlwaysInclude = false }, new LootItems { shortname = "ammo.rifle.incendiary", name = "", amount = 5, skin = 0, amountMin = 5, AlwaysInclude = false }, new LootItems { shortname = "ammo.rocket.basic.bp", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = true }, new LootItems { shortname = "ammo.rocket.fire.bp", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = true }, new LootItems { shortname = "ammo.rocket.hv.bp", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "ammo.shotgun", name = "", amount = 12, skin = 0, amountMin = 8, AlwaysInclude = false }, new LootItems { shortname = "explosive.timed", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "explosives", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "pistol.m92", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "rifle.ak.bp", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "rifle.bolt.bp", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "shotgun.spas12", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "smg.2.bp", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "smg.thompson.bp", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "weapon.mod.8x.scope.bp", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "weapon.mod.flashlight.bp", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "weapon.mod.holosight.bp", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "weapon.mod.lasersight.bp", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "weapon.mod.silencer.bp", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "weapon.mod.small.scope.bp", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "grenade.f1.bp", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "pickaxe", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "hatchet", name = "", amount = 1, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "can.beans", name = "", amount = 3, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "can.tuna", name = "", amount = 3, skin = 0, amountMin = 1, AlwaysInclude = false }, new LootItems { shortname = "black.raspberries", name = "", amount = 5, skin = 0, amountMin = 3, AlwaysInclude = false }, }; } } public class LootItems { [JsonProperty(PropertyName = "Item shortname")] public string shortname { get; set; } [JsonProperty(PropertyName = "Custom name")] public string name { get; set; } [JsonProperty(PropertyName = "Skin ID")] public ulong skin { get; set; } [JsonProperty(PropertyName = "Amount min")] public int amountMin { get; set; } [JsonProperty(PropertyName = "Amount max")] public int amount { get; set; } [JsonProperty(PropertyName = "Always add")] public bool AlwaysInclude { get; set; } } private void SpawnRadLoot(Vector3 pos , Quaternion rot , string animalType) { var backpack = GameManager.server.CreateEntity(StringPool.Get(1519640547) , pos , rot , true) as DroppedItemContainer; if (backpack == null) { if (Debug) Puts("Failed to create backpack entity."); return; } backpack.inventory = new ItemContainer(); backpack.inventory.ServerInitialize(null , 36); backpack.inventory.GiveUID(); backpack.inventory.entityOwner = backpack; backpack.inventory.SetFlag(ItemContainer.Flag.NoItemInput , true); backpack.Spawn(); if (Debug) Puts($"Spawned backpack at {pos} with rotation {rot}"); switch (animalType) { case "Alpha Wolf": case "Alpha Bear": case "Alpha Polarbear": SpawnLoot(backpack.inventory , configData.Animals.Loots.Loot.ToList() , animalType); break; case "Omega Wolf": case "Omega Bear": case "Omega Polarbear": // Add logic for Omega animals in the future //SpawnLoot(backpack.inventory , configData.Animals.Loots.Loot.ToList() , animalType); break; default: break; } } private void SpawnLoot(ItemContainer container , List loot , string AnimalType) { List alwaysIncludeItems = loot.Where(item => item.AlwaysInclude).ToList(); List randomLoot = loot.Where(item => !item.AlwaysInclude).ToList(); int totalItems = UnityEngine.Random.Range( Math.Min(randomLoot.Count + alwaysIncludeItems.Count , configData.Animals.Loots.MinAmount) , Math.Min(randomLoot.Count + alwaysIncludeItems.Count , configData.Animals.Loots.MaxAmount) ); if (Debug) Puts($"{AnimalType} total items: {totalItems}"); if (totalItems == 0) return; container.capacity = totalItems; foreach (var item in alwaysIncludeItems) { if (totalItems <= 0) break; AddLootItem(container , item); totalItems--; } for (int i = 0; i < totalItems; i++) { if (randomLoot.Count == 0) break; var lootItem = randomLoot.GetRandom(); randomLoot.Remove(lootItem); if (lootItem.amount <= 0) continue; AddLootItem(container , lootItem); } } private void AddLootItem(ItemContainer container , LootItems lootItem) { string shortname = lootItem.shortname; bool isBlueprint = shortname.EndsWith(".bp"); if (isBlueprint) shortname = shortname.Replace(".bp" , string.Empty); ItemDefinition def = ItemManager.FindItemDefinition(shortname); if (def == null) { Puts($"Invalid shortname: {lootItem.shortname}"); return; } ulong skin = lootItem.skin; if (configData.Animals.RandomSkins && skin == 0) { List skins = GetItemSkins(def); if (skins.Count > 0) skin = skins.GetRandom(); } int amount = lootItem.amount; if (lootItem.amountMin > 0 && lootItem.amountMin < lootItem.amount) { amount = UnityEngine.Random.Range(lootItem.amountMin , lootItem.amount); } Item item; if (isBlueprint) { item = ItemManager.CreateByItemID(-996920608 , 1 , 0); if (item == null) return; item.blueprintTarget = def.itemid; item.amount = amount; } else { item = ItemManager.Create(def , amount , skin); } if (!string.IsNullOrEmpty(lootItem.name)) { item.name = lootItem.name; } if (!item.MoveToContainer(container , -1 , false)) item.Remove(); } private List GetItemSkins(ItemDefinition def) { List skins; if (!Skins.TryGetValue(def.shortname , out skins)) { Skins[def.shortname] = skins = ExtractItemSkins(def , skins); } return skins; } private List ExtractItemSkins(ItemDefinition def , List skins) { skins = new List(); foreach (var skin in def.skins) { skins.Add(Convert.ToUInt64(skin.id)); } foreach (var asi in Rust.Workshop.Approved.All.Values) { if (!string.IsNullOrEmpty(asi.Skinnable.ItemName) && asi.Skinnable.ItemName == def.shortname) { skins.Add(Convert.ToUInt64(asi.WorkshopdId)); } } return skins; } #endregion } }