Иконка ресурса

FREE AlphaLoot : 3.1.3 3.1.3

Нет прав для скачивания
C#:
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using Steamworks;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Oxide.Plugins {
    [Info("AlphaLoot", "k1lly0u", "3.1.3")]
    class AlphaLoot : RustPlugin {
#region Fields
        [PluginReference]
        Plugin CustomLootSpawns, EventLoot, FancyDrop, SkinBox;
        private StoredData storedData;
        private StoredData bradleyData;
        private StoredData heliData;
        private DynamicConfigFile data, bradley, heli, skinData;
        private bool updateContainerCapacities = false;
        private static Hash<string, HashSet<SkinEntry>> weightedSkinIds;
        private static Hash<string, List<ulong>> importedSkinIds;
        private static Hash<string, int> defaultScrapAmounts;
        private const string ADMIN_PERMISSION = "alphaloot.admin";
        private const string HELI_CRATE = "heli_crate";
        private const string BRADLEY_CRATE = "bradley_crate";
#endregion
#region Oxide Hooks
        private void Loaded() {
            defaultScrapAmounts = new Hash<string, int>();
            permission.RegisterPermission(ADMIN_PERMISSION, this);
            LoadData();
            if (updateContainerCapacities) SetCapacityLimits();
        }
        private void OnServerInitialized() {
            PopulateContainerDefinitions(ref storedData, ref heliData, ref bradleyData);
            SaveData();
            Puts($"Loaded {storedData.loot_advanced.Count + storedData.loot_simple.Count} loot container definitions and {storedData.npcs_advanced.Count + storedData.npcs_simple.Count} npc loot definitions");
            Puts($"Loaded {heliData.loot_advanced.Count + heliData.loot_simple.Count} heli loot profiles");
            Puts($"Loaded {bradleyData.loot_advanced.Count + bradleyData.loot_simple.Count} bradley loot profiles");
            if (configData.AutoUpdate) AutoUpdateItemLists();
            if (configData.UseSkinboxSkins || configData.UseApprovedSkins) {
                if ((Steamworks.SteamInventory.Definitions?.Length ?? 0) == 0) {
                    PrintWarning("Waiting for Steamworks to initialize to load item skins");
                    Steamworks.SteamInventory.OnDefinitionsUpdated += LoadSkins;
                }
                else LoadSkins();
            }
            else RefreshLootContents();
        }
        private void OnEntitySpawned(BradleyAPC bradleyApc) {
            if (bradleyApc != null) bradleyApc.maxCratesToSpawn = configData.BradleyCrates;
        }
        private void OnEntitySpawned(BaseHelicopter baseHelicopter) {
            if (baseHelicopter != null) baseHelicopter.maxCratesToSpawn = configData.HelicopterCrates;
        }
        private object OnCorpsePopulate(BaseEntity entity, LootableCorpse corpse) {
            if (entity == null || corpse == null) return null;
            object obj = Interface.CallHook("CanPopulateLoot", entity, corpse);
            if (obj != null) return null;
            return PopulateLoot(entity, corpse) ? corpse : null;
        }
        private object OnLootSpawn(LootContainer container) {
            if (container == null) return null;
            if (CustomLootSpawns && (bool)CustomLootSpawns.Call("IsLootBox", container as BaseEntity)) return null;
            if (EventLoot && (bool)EventLoot.Call("IsEventLootContainer", container as BaseEntity)) return null;
            if (FancyDrop && container is SupplyDrop && !configData.OverrideFancyDrop) return null;
            object obj = Interface.CallHook("CanPopulateLoot", container);
            if (obj != null) return null;
            if (PopulateLoot(container)) return true;
            return null;
        }
        private void OnHammerHit(BasePlayer player, HitInfo info) {
            if (player == null || info == null) return;
            if (!permission.UserHasPermission(player.UserIDString, ADMIN_PERMISSION)) return;
            LootContainer lootContainer = info?.HitEntity?.GetComponent<LootContainer>();
            if (lootContainer == null) return;
            player.ChatMessage($"Viewing loot generation for: <color=#ffff00>{lootContainer.ShortPrefabName}</color>");
            lootContainer.gameObject.AddComponent<LootCycler>();
            player.inventory.loot.StartLootingEntity(lootContainer, false);
            player.inventory.loot.AddContainer(lootContainer.inventory);
            player.inventory.loot.SendImmediate();
            player.ClientRPCPlayer(null, player, "RPC_OpenLootPanel", lootContainer.panelName);
        }
        private void OnLootEntityEnd(BasePlayer player, StorageContainer container) {
            LootCycler lootCycler = container?.GetComponent<LootCycler>();
            if (lootCycler != null) UnityEngine.Object.Destroy(lootCycler);
        }
        private void Unload() {
            RefreshLootContents(null, true);
            configData = null;
            weightedSkinIds = null;
            importedSkinIds = null;
            defaultScrapAmounts = null;
        }
#endregion
#region Skins
        private void LoadSkins() {
            Steamworks.SteamInventory.OnDefinitionsUpdated -= LoadSkins;
            if (configData.UseSkinboxSkins) PopulateSkinListFromSkinBox();
            if (configData.UseApprovedSkins) PopulateSkinListFromApproved();
            RefreshLootContents();
        }
        private void PopulateSkinListFromSkinBox() {
            Dictionary<string, LinkedList<ulong>> dictionary = SkinBox?.Call("getSkincache") as Dictionary<string, LinkedList<ulong>>;
            if (dictionary != null) {
                importedSkinIds = new Hash<string, List<ulong>>();
                foreach(KeyValuePair<string, LinkedList<ulong>> kvp in dictionary) {
                    List<ulong> list = new List<ulong>();
                    list.AddRange(kvp.Value);
                    importedSkinIds[kvp.Key] = list;
                }
                Puts($"Imported {importedSkinIds.Sum(x => x.Value.Count)} skins from SkinBox");
            }
        }
        private void PopulateSkinListFromApproved() {
            if (importedSkinIds == null) importedSkinIds = new Hash<string, List<ulong>>();
            List<int> itemSkinDirectory = Pool.GetList<int>();
            itemSkinDirectory.AddRange(ItemSkinDirectory.Instance.skins.Select(x => x.id));
            int count = 0;
            foreach (InventoryDef item in Steamworks.SteamInventory.Definitions) {
                string shortname = item.GetProperty("itemshortname");
                if (string.IsNullOrEmpty(shortname) || item.Id < 100) continue;
                ulong wsid;
                if (itemSkinDirectory.Contains(item.Id)) wsid = (ulong)item.Id;
                else {
                    if (!ulong.TryParse(item.GetProperty("workshopid"), out wsid)) continue;
                }
                if (!importedSkinIds.ContainsKey(shortname)) importedSkinIds[shortname] = new List<ulong>();
                if (!importedSkinIds[shortname].Contains(wsid)) {
                    importedSkinIds[shortname].Add(wsid);
                    count++;
                }
            }
            Puts($"Imported {count} approved skins that weren't already in the list");
            Pool.FreeList(ref itemSkinDirectory);
        }
#endregion
#region Container Population
        private void RefreshLootContents(ConsoleSystem.Arg arg = null, bool setDefaultScrap = false) {
            LootContainer[] lootContainers = UnityEngine.Object.FindObjectsOfType<LootContainer>();
            if (arg != null) SendReply(arg, $"Repopulating loot for {lootContainers?.Length} containers");
            else Puts($"Repopulating loot for {lootContainers?.Length} containers");
            for (int i = 0; i < lootContainers?.Length; i++) {
                LootContainer lootContainer = lootContainers[i];
                if (lootContainer != null && !lootContainer.IsDestroyed) {
                    if (lootContainer.inventory == null) {
                        lootContainer.CreateInventory(true);
                        lootContainer.OnInventoryFirstCreated(lootContainer.inventory);
                    }
                    if (setDefaultScrap) {
                        int scrapAmount;
                        if (defaultScrapAmounts.TryGetValue(lootContainer.ShortPrefabName, out scrapAmount)) lootContainer.scrapAmount = scrapAmount;
                    }
                    lootContainer.inventory.capacity = lootContainer.inventorySlots;
                    lootContainer.CancelInvoke(lootContainer.SpawnLoot);
                    lootContainer.Invoke(lootContainer.SpawnLoot, UnityEngine.Random.Range(1f, 20f));
                }
            }
        }
        private void PopulateContainerDefinitions(ref StoredData storedData, ref StoredData heliData, ref StoredData bradleyData) {
            storedData.IsBaseLootTable = true;
            List<LootContainer> containers = Resources.FindObjectsOfTypeAll<LootContainer>().OrderBy(x => x.ShortPrefabName).ToList();
            for (int i = 0; i < containers.Count; i++) {
                LootContainer lootContainer = containers[i];
                if (!defaultScrapAmounts.ContainsKey(lootContainer.ShortPrefabName)) defaultScrapAmounts[lootContainer.ShortPrefabName] = lootContainer.scrapAmount;
                if (lootContainer.ShortPrefabName.Equals(HELI_CRATE)) {
                    BaseLootContainerProfile lootContainerProfile;
                    if (storedData.TryGetLootProfile(HELI_CRATE, out lootContainerProfile)) {
                        heliData.CloneLootProfile(HELI_CRATE, lootContainerProfile);
                        storedData.RemoveProfile(HELI_CRATE);
                        Debug.LogWarning($"Helicopter loot profiles have been removed from your loot table and placed in its own data file.(/data/AlphaLoot/LootProfiles/{configData.HeliProfileName}.json)");
                    }
                    else {
                        if (heliData.HasAnyProfiles) continue;
                        heliData.CreateDefaultLootProfile(lootContainer);
                    }
                }
                else if (lootContainer.ShortPrefabName.Equals(BRADLEY_CRATE)) {
                    BaseLootContainerProfile lootContainerProfile;
                    if (storedData.TryGetLootProfile(BRADLEY_CRATE, out lootContainerProfile)) {
                        bradleyData.CloneLootProfile(BRADLEY_CRATE, lootContainerProfile);
                        storedData.RemoveProfile(BRADLEY_CRATE);
                        Debug.LogWarning($"Bradley loot profiles have been removed from your loot table and placed in its own data file.(/data/AlphaLoot/LootProfiles/{configData.BradleyProfileName}.json)");
                    }
                    else {
                        if (bradleyData.HasAnyProfiles) continue;
                        bradleyData.CreateDefaultLootProfile(lootContainer);
                    }
                }
                else storedData.CreateDefaultLootProfile(containers[i]);
            }
            for (int i = 0; i < npcPrefabs.Count; i++) {
                string prefab = npcPrefabs[i];
                GameObject obj = GameManager.server.FindPrefab(prefab);
                prefab = ToShortName(prefab);
                HTNPlayer htnPlayer = obj.GetComponent<HTNPlayer>();
                if (htnPlayer != null) {
                    BaseNpcDefinition baseDefinition = htnPlayer.AiDefinition;
                    if (baseDefinition is Rust.Ai.HTN.Murderer.MurdererDefinition) {
                        storedData.CreateDefaultLootProfile(prefab, (baseDefinition as Rust.Ai.HTN.Murderer.MurdererDefinition).Loot);
                        continue;
                    }
                    if (baseDefinition is Rust.Ai.HTN.Scientist.ScientistDefinition) {
                        storedData.CreateDefaultLootProfile(prefab, (baseDefinition as Rust.Ai.HTN.Scientist.ScientistDefinition).Loot);
                        continue;
                    }
                    if (baseDefinition is Rust.Ai.HTN.NPCTurret.NPCTurretDefinition) {
                        storedData.CreateDefaultLootProfile(prefab, (baseDefinition as Rust.Ai.HTN.NPCTurret.NPCTurretDefinition).Loot);
                        continue;
                    }
                    if (baseDefinition is Rust.Ai.HTN.ScientistAStar.ScientistAStarDefinition) {
                        storedData.CreateDefaultLootProfile(prefab, (baseDefinition as Rust.Ai.HTN.ScientistAStar.ScientistAStarDefinition).Loot);
                        continue;
                    }
                    if (baseDefinition is Rust.Ai.HTN.ScientistJunkpile.ScientistJunkpileDefinition) {
                        storedData.CreateDefaultLootProfile(prefab, (baseDefinition as Rust.Ai.HTN.ScientistJunkpile.ScientistJunkpileDefinition).Loot);
                        continue;
                    }
                    continue;
                }
                global : : HumanNPC humanNPC = obj.GetComponent<global : : HumanNPC>();
                if (humanNPC != null) {
                    storedData.CreateDefaultLootProfile(prefab, humanNPC.LootSpawnSlots);
                    continue;
                }
                NPCMurderer npcMurderer = obj.GetComponent<NPCMurderer>();
                if (npcMurderer != null) {
                    storedData.CreateDefaultLootProfile(prefab, npcMurderer.LootSpawnSlots);
                    continue;
                }
                Scientist scientist = obj.GetComponent<Scientist>();
                if (scientist != null) {
                    storedData.CreateDefaultLootProfile(prefab, scientist.LootSpawnSlots);
                    continue;
                }
            }
        }
        private bool PopulateLoot(LootContainer container) {
            BaseLootContainerProfile lootProfile;
            if (container.ShortPrefabName.Equals(HELI_CRATE)) {
                if (heliData.GetRandomLootProfile(out lootProfile)) {
                    PopulateLootContainer(container, lootProfile);
                    return true;
                }
            }
            else if (container.ShortPrefabName.Equals(BRADLEY_CRATE)) {
                if (bradleyData.GetRandomLootProfile(out lootProfile)) {
                    PopulateLootContainer(container, lootProfile);
                    return true;
                }
            }
            else {
                if (storedData.TryGetLootProfile(container.ShortPrefabName, out lootProfile) && lootProfile.Enabled) {
                    PopulateLootContainer(container, lootProfile);
                    return true;
                }
            }
            return false;
        }
        private void PopulateLootContainer(LootContainer container, BaseLootContainerProfile lootProfile) {
            container.destroyOnEmpty = lootProfile.DestroyOnEmpty;
            lootProfile.PopulateLoot(container.inventory);
            container.CancelInvoke(container.SpawnLoot);
            if (lootProfile.ShouldRefreshContents) container.Invoke(container.SpawnLoot, UnityEngine.Random.Range(lootProfile.MinSecondsBetweenRefresh, lootProfile.MaxSecondsBetweenRefresh));
        }
        private bool PopulateLoot(BaseEntity entity, LootableCorpse corpse) {
            BaseLootProfile lootProfile;
            if (storedData.TryGetNPCProfile(entity.ShortPrefabName, out lootProfile)) {
                if (!lootProfile.Enabled) return false;
                lootProfile.PopulateLoot(corpse.containers[0]);
                return true;
            }
            return false;
        }
#endregion
#region Functions
        private string ToShortName(string name) {
            return name.Split('/').Last().Replace(".prefab", "");
        }
        private LootContainer FindContainer(BasePlayer player) {
            RaycastHit raycastHit;
            if (Physics.Raycast(player.eyes.HeadRay(), out raycastHit, 20f)) {
                LootContainer lootContainer = raycastHit.GetEntity() as LootContainer;
                return lootContainer;
            }
            return null;
        }
        private object WantsToHandleFancyDropLoot() => configData.OverrideFancyDrop ? (object)true : null;
#endregion
#region Auto-Updater
        private void AutoUpdateItemLists() {
            const string lastDefaultTable = "AlphaLoot/AutoUpdater/do_not_edit_this_file";
            ItemList lastItemList;
            if (Interface.Oxide.DataFileSystem.ExistsDatafile(lastDefaultTable)) {
                lastItemList = Interface.Oxide.DataFileSystem.GetFile(lastDefaultTable).ReadObject<ItemList>();
                if (lastItemList != null) {
                    if (lastItemList.protocol == Rust.Protocol.printable) {
                        Debug.Log("[AlphaLoot Auto Updater] - Last item list protocol matches current protocol.No new items added");
                        return;
                    }
                    List<int> newItems = Pool.GetList<int>();
                    ItemManager.itemList.ForEach(x => {
                        if (!lastItemList.itemIds.Contains(x.itemid)) newItems.Add(x.itemid);
                    }
                    );
                    if (newItems.Count > 0) {
                        int additions = 0;
                        Debug.Log($"[AlphaLoot Auto Updater] - Found {newItems.Count} new game items.Adding them to your loot table");
                        AddItemsToLootTable(newItems, out additions);
                        if (additions > 0) {
                            Debug.Log($"[AlphaLoot Auto Updater] - Added {additions} new loot definitions to the loot table");
                            SaveData();
                            Interface.Oxide.DataFileSystem.WriteObject<ItemList>(lastDefaultTable, new ItemList() {
                                itemIds = ItemManager.itemDictionary.Keys.ToList(), protocol = Rust.Protocol.printable
                            }
                            );
                        }
                    }
                    else Debug.Log("[AlphaLoot Auto Updater] - No new items in game");
                    Pool.FreeList(ref newItems);
                }
            }
            else {
                Debug.Log("[AlphaLoot Auto Updater] - Generating item list for auto-updater.Future game updates will automatically add new items to your loot table.You can disable this feature in the config");
                Interface.Oxide.DataFileSystem.WriteObject<ItemList>(lastDefaultTable, new ItemList() {
                    itemIds = ItemManager.itemDictionary.Keys.ToList(), protocol = Rust.Protocol.printable
                }
                );
            }
        }
        private void AddSpecifiedItemsToLootTable(params string[] args) {
            int additions = 0;
            List<int> items = Pool.GetList<int>();
            foreach(string str in args) {
                ItemDefinition itemDefinition = ItemManager.FindItemDefinition(str);
                if (itemDefinition != null) items.Add(itemDefinition.itemid);
            }
            if (items.Count > 0) {
                Debug.Log($"[AlphaLoot] - Adding {items.Count} specified items to your loot table");
                AddItemsToLootTable(items, out additions);
                if (additions > 0) {
                    Debug.Log($"[AlphaLoot] - Successfully added {additions} new loot definitions to the loot table");
                    SaveData();
                }
            }
            else Debug.Log("[AlphaLoot] - Failed to find item definitions for the shortname's supplied");
            Pool.FreeList(ref items);
        }
        private void AddItemsToLootTable(List<int> items, out int additions) {
            additions = 0;
            StoredData defaultLootTable = new StoredData();
            StoredData defaultHeliLootTable = new StoredData();
            StoredData defaultBradleyLootTable = new StoredData();
            PopulateContainerDefinitions(ref defaultLootTable, ref defaultHeliLootTable, ref defaultBradleyLootTable);
            foreach (KeyValuePair<string, AdvancedLootContainerProfile> kvp in defaultLootTable.loot_advanced) {
                foreach (int itemid in items) {
                    string shortname = ItemManager.itemDictionary[itemid].shortname;
                    NewLootItem newLootItem = new NewLootItem();
                    float score = 0;
                    int multiplier = 1;
                    foreach (LootSpawnSlot lootSpawnSlot in kvp.Value.LootSpawnSlots) {
                        FindItemAndCalculateScoreRecursive(lootSpawnSlot.LootDefinition, shortname, ref newLootItem, ref multiplier);
                        score += (lootSpawnSlot.Probability * newLootItem.Score) * lootSpawnSlot.NumberToSpawn;
                    }
                    if (score > 0) {
                        AdvancedLootContainerProfile advancedLootProfile;
                        if (storedData.loot_advanced.TryGetValue(kvp.Key, out advancedLootProfile)) {
                            LootSpawnSlot newLootSpawnSlot = new LootSpawnSlot {
                                LootDefinition = new LootSpawn() {
                                    Items = new ItemAmountRanged[] {
                                        newLootItem.Item
                                    }
                                    , SubSpawn = new LootSpawn.Entry[0]
                                }
                                , NumberToSpawn = 1, Probability = Mathf.Clamp01(score * multiplier)
                            }
                            ;
                            int index = advancedLootProfile.LootSpawnSlots.Length;
                            System.Array.Resize(ref advancedLootProfile.LootSpawnSlots, index + 1);
                            advancedLootProfile.LootSpawnSlots[index] = newLootSpawnSlot;
                            additions++;
                            Debug.Log($"[AlphaLoot] - Added {shortname} to advanced loot profile ({kvp.Key}) with a calculated probability of {newLootSpawnSlot.Probability}");
                        }
                        else {
                            SimpleLootContainerProfile simpleLootContainerProfile;
                            if (storedData.loot_simple.TryGetValue(kvp.Key, out simpleLootContainerProfile)) {
                                ItemAmountWeighted itemAmountWeighted = new ItemAmountWeighted() {
                                    BlueprintChance = newLootItem.Item.BlueprintChance, Condition = new ItemAmount.ConditionItem() {
                                        MinCondition = newLootItem.Item.Condition.MinCondition, MaxCondition = newLootItem.Item.Condition.MaxCondition
                                    }
                                    , MaxAmount = newLootItem.Item.MaxAmount, MinAmount = newLootItem.Item.MinAmount, Shortname = shortname, Weight = Mathf.Max(Mathf.RoundToInt(((float)simpleLootContainerProfile.Items.Sum(x => x.Weight) * score) * multiplier), 1)
                                }
                                ;
                                int index = simpleLootContainerProfile.Items.Length;
                                System.Array.Resize(ref simpleLootContainerProfile.Items, index + 1);
                                simpleLootContainerProfile.Items[index] = itemAmountWeighted;
                                additions++;
                                Debug.Log($"[AlphaLoot] - Added {shortname} to simple loot profile ({kvp.Key}) with a calculated weight of {itemAmountWeighted.Weight}");
                            }
                        }
                        continue;
                    }
                }
            }
            foreach (KeyValuePair<string, AdvancedLootContainerProfile> kvp in defaultHeliLootTable.loot_advanced) {
                foreach (int itemid in items) {
                    string shortname = ItemManager.itemDictionary[itemid].shortname;
                    NewLootItem newLootItem = new NewLootItem();
                    float score = 0;
                    int multiplier = 1;
                    foreach (LootSpawnSlot lootSpawnSlot in kvp.Value.LootSpawnSlots) {
                        FindItemAndCalculateScoreRecursive(lootSpawnSlot.LootDefinition, shortname, ref newLootItem, ref multiplier);
                        score += (lootSpawnSlot.Probability * newLootItem.Score) * lootSpawnSlot.NumberToSpawn;
                    }
                    if (score > 0) {
                        AdvancedLootContainerProfile advancedLootProfile;
                        if (heliData.loot_advanced.TryGetValue(kvp.Key, out advancedLootProfile)) {
                            LootSpawnSlot newLootSpawnSlot = new LootSpawnSlot {
                                LootDefinition = new LootSpawn() {
                                    Items = new ItemAmountRanged[] {
                                        newLootItem.Item
                                    }
                                    , SubSpawn = new LootSpawn.Entry[0]
                                }
                                , NumberToSpawn = 1, Probability = Mathf.Clamp01(score * multiplier)
                            }
                            ;
                            int index = advancedLootProfile.LootSpawnSlots.Length;
                            System.Array.Resize(ref advancedLootProfile.LootSpawnSlots, index + 1);
                            advancedLootProfile.LootSpawnSlots[index] = newLootSpawnSlot;
                            additions++;
                            Debug.Log($"[AlphaLoot] - Added {shortname} to advanced heli loot profile ({kvp.Key}) with a calculated probability of {newLootSpawnSlot.Probability}");
                        }
                        else {
                            SimpleLootContainerProfile simpleLootContainerProfile;
                            if (heliData.loot_simple.TryGetValue(kvp.Key, out simpleLootContainerProfile)) {
                                ItemAmountWeighted itemAmountWeighted = new ItemAmountWeighted() {
                                    BlueprintChance = newLootItem.Item.BlueprintChance, Condition = new ItemAmount.ConditionItem() {
                                        MinCondition = newLootItem.Item.Condition.MinCondition, MaxCondition = newLootItem.Item.Condition.MaxCondition
                                    }
                                    , MaxAmount = newLootItem.Item.MaxAmount, MinAmount = newLootItem.Item.MinAmount, Shortname = shortname, Weight = Mathf.Max(Mathf.RoundToInt(((float)simpleLootContainerProfile.Items.Sum(x => x.Weight) * score) * multiplier), 1)
                                }
                                ;
                                int index = simpleLootContainerProfile.Items.Length;
                                System.Array.Resize(ref simpleLootContainerProfile.Items, index + 1);
                                simpleLootContainerProfile.Items[index] = itemAmountWeighted;
                                additions++;
                                Debug.Log($"[AlphaLoot] - Added {shortname} to simple heli loot profile ({kvp.Key}) with a calculated weight of {itemAmountWeighted.Weight}");
                            }
                        }
                        continue;
                    }
                }
            }
            foreach (KeyValuePair<string, AdvancedLootContainerProfile> kvp in defaultBradleyLootTable.loot_advanced) {
                foreach (int itemid in items) {
                    string shortname = ItemManager.itemDictionary[itemid].shortname;
                    NewLootItem newLootItem = new NewLootItem();
                    float score = 0;
                    int multiplier = 1;
                    foreach (LootSpawnSlot lootSpawnSlot in kvp.Value.LootSpawnSlots) {
                        FindItemAndCalculateScoreRecursive(lootSpawnSlot.LootDefinition, shortname, ref newLootItem, ref multiplier);
                        score += (lootSpawnSlot.Probability * newLootItem.Score) * lootSpawnSlot.NumberToSpawn;
                    }
                    if (score > 0) {
                        AdvancedLootContainerProfile advancedLootProfile;
                        if (bradleyData.loot_advanced.TryGetValue(kvp.Key, out advancedLootProfile)) {
                            LootSpawnSlot newLootSpawnSlot = new LootSpawnSlot {
                                LootDefinition = new LootSpawn() {
                                    Items = new ItemAmountRanged[] {
                                        newLootItem.Item
                                    }
                                    , SubSpawn = new LootSpawn.Entry[0]
                                }
                                , NumberToSpawn = 1, Probability = Mathf.Clamp01(score * multiplier)
                            }
                            ;
                            int index = advancedLootProfile.LootSpawnSlots.Length;
                            System.Array.Resize(ref advancedLootProfile.LootSpawnSlots, index + 1);
                            advancedLootProfile.LootSpawnSlots[index] = newLootSpawnSlot;
                            additions++;
                            Debug.Log($"[AlphaLoot] - Added {shortname} to advanced bradley loot profile ({kvp.Key}) with a calculated probability of {newLootSpawnSlot.Probability}");
                        }
                        else {
                            SimpleLootContainerProfile simpleLootContainerProfile;
                            if (bradleyData.loot_simple.TryGetValue(kvp.Key, out simpleLootContainerProfile)) {
                                ItemAmountWeighted itemAmountWeighted = new ItemAmountWeighted() {
                                    BlueprintChance = newLootItem.Item.BlueprintChance, Condition = new ItemAmount.ConditionItem() {
                                        MinCondition = newLootItem.Item.Condition.MinCondition, MaxCondition = newLootItem.Item.Condition.MaxCondition
                                    }
                                    , MaxAmount = newLootItem.Item.MaxAmount, MinAmount = newLootItem.Item.MinAmount, Shortname = shortname, Weight = Mathf.Max(Mathf.RoundToInt(((float)simpleLootContainerProfile.Items.Sum(x => x.Weight) * score) * multiplier), 1)
                                }
                                ;
                                int index = simpleLootContainerProfile.Items.Length;
                                System.Array.Resize(ref simpleLootContainerProfile.Items, index + 1);
                                simpleLootContainerProfile.Items[index] = itemAmountWeighted;
                                additions++;
                                Debug.Log($"[AlphaLoot] - Added {shortname} to simple bradley loot profile ({kvp.Key}) with a calculated weight of {itemAmountWeighted.Weight}");
                            }
                        }
                        continue;
                    }
                }
            }
        }
        private void FindItemAndCalculateScoreRecursive(LootSpawn lootSpawn, string shortname, ref NewLootItem newLootItem, ref int multiplier) {
            if (lootSpawn.SubSpawn.Length > 0) {
                foreach(LootSpawn.Entry lootSpawnEntry in lootSpawn.SubSpawn) {
                    FindItemAndCalculateScoreRecursive(lootSpawnEntry.Category, shortname, ref newLootItem, ref multiplier);
                    if (newLootItem.HasItem) {
                        if (newLootItem.Score == 0) newLootItem.Score = (float)lootSpawnEntry.Weight / (float)lootSpawn.SubSpawn.Sum(x => x.Weight);
                        else newLootItem.Score *= (float)lootSpawnEntry.Weight / (float)lootSpawn.SubSpawn.Sum(x => x.Weight);
                        return;
                    }
                }
            }
            else if (lootSpawn.Items.Length > 0) {
                foreach(ItemAmountRanged itemAmountRanged in lootSpawn.Items) {
                    if (itemAmountRanged.Shortname == shortname) {
                        if (newLootItem.HasItem) multiplier++;
                        newLootItem.Item = itemAmountRanged;
                    }
                }
            }
        }
        private class NewLootItem {
            public ItemAmountRanged Item;
            public float Score;
            public bool HasItem => Item != null;
            public void Clear() {
                Item = null;
                Score = 0;
            }
        }
        private class ItemList {
            public List<int> itemIds = new List<int>();
            public string protocol;
        }
#endregion
#region Components
        private class LootCycler : MonoBehaviour {
            private LootContainer lootContainer;
            private void Awake() {
                lootContainer = GetComponent<LootContainer>();
                InvokeHandler.InvokeRepeating(this, lootContainer.SpawnLoot, 3f, 3f);
            }
        }
#endregion
#region Commands
        [ChatCommand("aloot")]
        private void cmdRepopulateTarget(BasePlayer player, string command, string[] args) {
            if (!permission.UserHasPermission(player.UserIDString, ADMIN_PERMISSION)) {
                SendReply(player, "You do not have permission to use this command");
                return;
            }
            if (args == null || args.Length == 0) {
                SendReply(player, "/aloot repopulate - Repopulate the container you are looking at");
                SendReply(player, "/aloot view - List the contents of the container you are looking at");
                SendReply(player, "/aloot repopulateall - Repopulate every loot container on the map (can take upto 20 seconds)");
                return;
            }
            switch (args[0].ToLower()) {
                case "repopulate" : {
                    LootContainer lootContainer = FindContainer(player);
                    if (lootContainer != null) {
                        lootContainer.CancelInvoke(lootContainer.SpawnLoot);
                        lootContainer.SpawnLoot();
                        SendReply(player, $"Refreshed loot contents for {lootContainer.ShortPrefabName}");
                    }
                    else SendReply(player, "No loot container found");
                }
                return;
                case "view" : {
                    LootContainer lootContainer = FindContainer(player);
                    if (lootContainer != null) {
                        SendReply(player, $"Loot contents for {lootContainer.ShortPrefabName};");
                        SendReply(player, lootContainer.inventory.itemList.Select(x => $"{x.info.displayName.english} x{x.amount}").ToSentence());
                    }
                    else SendReply(player, "No loot container found");
                }
                return;
                case "repopulateall" : {
                    SendReply(player, "Refreshing all loot containers...");
                    RefreshLootContents();
                }
                return;
                default : SendReply(player, "Invalid syntax!");
                break;
            }
        }
        [ConsoleCommand("al.repopulateall")]
        private void ccmdRepopulateAll(ConsoleSystem.Arg arg) {
            if (arg.Connection != null) {
                BasePlayer player = arg.Player();
                if (player != null && !permission.UserHasPermission(player.UserIDString, ADMIN_PERMISSION)) {
                    SendReply(arg, "You do not have permission to use this command");
                    return;
                }
            }
            RefreshLootContents(arg);
        }
        [ConsoleCommand("al.additems")]
        private void ccmdAddItemsl(ConsoleSystem.Arg arg) {
            if (arg.Connection != null) {
                BasePlayer player = arg.Player();
                if (player != null && !permission.UserHasPermission(player.UserIDString, ADMIN_PERMISSION)) {
                    SendReply(arg, "You do not have permission to use this command");
                    return;
                }
            }
            if (arg.Args == null || arg.Args.Length == 0) {
                SendReply(arg, "al.additems <shortname> <opt:shortname> <opt:shortname>...- Add the specified item(s) to your loot table.\nThis finds the containers the items are in from the default loot table, calculates a score and adds it to your existing loot table.\nYou can enter as many shortnames as you like");
                return;
            }
            AddSpecifiedItemsToLootTable(arg.Args);
        }
        [ConsoleCommand("al.search")]
        private void ccmdSearchItem(ConsoleSystem.Arg arg) {
            if (arg.Connection != null) {
                BasePlayer player = arg.Player();
                if (player != null && !permission.UserHasPermission(player.UserIDString, ADMIN_PERMISSION)) {
                    SendReply(arg, "You do not have permission to use this command");
                    return;
                }
            }
            string shortname = arg.GetString(0);
            if (string.IsNullOrEmpty(shortname) || !ItemManager.itemDictionaryByName.ContainsKey(shortname)) {
                SendReply(arg, "You must enter a valid item shortname to search");
                return;
            }
            Hash<string, int> containers = new Hash<string, int>();
            foreach (KeyValuePair<string, AdvancedLootContainerProfile> profile in storedData.loot_advanced) {
                int count = 0;
                foreach (LootSpawnSlot lootSpawnSlot in profile.Value.LootSpawnSlots) {
                    FindItemCountRecursive(lootSpawnSlot.LootDefinition, shortname, ref count);
                }
                if (count > 0) containers[profile.Key] = count;
            }
            foreach (KeyValuePair<string, AdvancedNPCLootProfile> profile in storedData.npcs_advanced) {
                int count = 0;
                foreach (LootSpawnSlot lootSpawnSlot in profile.Value.LootSpawnSlots) {
                    FindItemCountRecursive(lootSpawnSlot.LootDefinition, shortname, ref count);
                }
                if (count > 0) containers[profile.Key] = count;
            }
            foreach (KeyValuePair<string, SimpleLootContainerProfile> profile in storedData.loot_simple) {
                int count = 0;
                foreach (ItemAmountWeighted itemAmountWeighted in profile.Value.Items) {
                    if (itemAmountWeighted.Shortname == shortname) count++;
                }
                if (count > 0) containers[profile.Key] = count;
            }
            foreach (KeyValuePair<string, SimpleNPCLootProfile> profile in storedData.npcs_simple) {
                int count = 0;
                foreach (ItemAmountWeighted itemAmountWeighted in profile.Value.Items) {
                    if (itemAmountWeighted.Shortname == shortname) count++;
                }
                if (count > 0) containers[profile.Key] = count;
            }
            if (containers.Count == 0) {
                SendReply(arg, $"The item {shortname} was not found in any loot profiles");
                return;
            }
            else {
                SendReply(arg, $"Found item {shortname} {containers.Sum(x => x.Value)} times in {containers.Count} loot profiles;{containers.Select(x => $"\n {
                    x.Key
                }
                (x {
                    x.Value
                }
                )").ToSentence()}");
                return;
            }
        }
        private void FindItemCountRecursive(LootSpawn lootSpawn, string shortname, ref int count) {
            if (lootSpawn.SubSpawn.Length > 0) {
                foreach (LootSpawn.Entry lootSpawnEntry in lootSpawn.SubSpawn) FindItemCountRecursive(lootSpawnEntry.Category, shortname, ref count);
            }
            else if (lootSpawn.Items.Length > 0) {
                foreach (ItemAmountRanged itemAmountRanged in lootSpawn.Items) {
                    if (itemAmountRanged.Shortname == shortname) count++;
                }
            }
        }
        [ConsoleCommand("al.setloottable")]
        private void ccmdChangeConfig(ConsoleSystem.Arg arg) {
            if (arg.Connection != null) {
                BasePlayer player = arg.Player();
                if (player != null && !permission.UserHasPermission(player.UserIDString, ADMIN_PERMISSION)) {
                    SendReply(arg, "You do not have permission to use this command");
                    return;
                }
            }
            if (arg.Args == null || arg.Args.Length != 1) {
                SendReply(arg, "Invalid arguments supplied! al.setloottable \"file name\"");
                return;
            }
            if (!Interface.Oxide.DataFileSystem.ExistsDatafile($"AlphaLoot/LootProfiles/{arg.Args[0]}")) {
                SendReply(arg, $"Unable to find a loot table with the name {arg.Args[0]}");
                return;
            }
            configData.ProfileName = arg.Args[0];
            SaveConfig();
            SendReply(arg, $"Loot table set to: {configData.ProfileName}");
            LoadLootTable();
            RefreshLootContents(arg);
        }
        [ConsoleCommand("al.setheliloottable")]
        private void ccmdChangeHeliConfig(ConsoleSystem.Arg arg) {
            if (arg.Connection != null) {
                BasePlayer player = arg.Player();
                if (player != null && !permission.UserHasPermission(player.UserIDString, ADMIN_PERMISSION)) {
                    SendReply(arg, "You do not have permission to use this command");
                    return;
                }
            }
            if (arg.Args == null || arg.Args.Length != 1) {
                SendReply(arg, "Invalid arguments supplied! al.setheliloottable \"heli file name\"");
                return;
            }
            if (!Interface.Oxide.DataFileSystem.ExistsDatafile($"AlphaLoot/LootProfiles/{arg.Args[0]}")) {
                SendReply(arg, $"Unable to find a heli loot table with the name {arg.Args[0]}");
                return;
            }
            configData.HeliProfileName = arg.Args[0];
            SaveConfig();
            SendReply(arg, $"Heli Loot table set to: {configData.HeliProfileName}");
            LoadHeliTable();
        }
        [ConsoleCommand("al.setbradleyloottable")]
        private void ccmdChangeBradleyConfig(ConsoleSystem.Arg arg) {
            if (arg.Connection != null) {
                BasePlayer player = arg.Player();
                if (player != null && !permission.UserHasPermission(player.UserIDString, ADMIN_PERMISSION)) {
                    SendReply(arg, "You do not have permission to use this command");
                    return;
                }
            }
            if (arg.Args == null || arg.Args.Length != 1) {
                SendReply(arg, "Invalid arguments supplied! al.setbradleyloottable \"heli file name\"");
                return;
            }
            if (!Interface.Oxide.DataFileSystem.ExistsDatafile($"AlphaLoot/LootProfiles/{arg.Args[0]}")) {
                SendReply(arg, $"Unable to find a bradley loot table with the name {arg.Args[0]}");
                return;
            }
            configData.BradleyProfileName = arg.Args[0];
            SaveConfig();
            SendReply(arg, $"Bradley Loot table set to: {configData.BradleyProfileName}");
            LoadBradleyTable();
        }
        [ConsoleCommand("al.generatetable")]
        private void ccmdGenerateTable(ConsoleSystem.Arg arg) {
            if (arg.Connection != null) {
                BasePlayer player = arg.Player();
                if (player != null && !permission.UserHasPermission(player.UserIDString, ADMIN_PERMISSION)) {
                    SendReply(arg, "You do not have permission to use this command");
                    return;
                }
            }
            if (arg.Args == null || arg.Args.Length < 3) {
                SendReply(arg, "al.generatetable <filename> <heli_filename> <bradley_filename> - Generate the default loot table to the specified file");
                return;
            }
            string fileName = arg.GetString(0);
            if (fileName.Equals(configData.ProfileName, System.StringComparison.OrdinalIgnoreCase)) {
                SendReply(arg, "The filename you entered is the same as the loot table currently being used.Change the filename to something else");
                return;
            }
            string heliFileName = arg.GetString(1);
            if (fileName.Equals(configData.HeliProfileName, System.StringComparison.OrdinalIgnoreCase)) {
                SendReply(arg, "The heli filename you entered is the same as the heli loot table currently being used.Change the filename to something else");
                return;
            }
            string bradleyFileName = arg.GetString(2);
            if (fileName.Equals(configData.BradleyProfileName, System.StringComparison.OrdinalIgnoreCase)) {
                SendReply(arg, "The bradley filename you entered is the same as the bradley loot table currently being used.Change the filename to something else");
                return;
            }
            StoredData storedData = new StoredData();
            StoredData heliData = new StoredData();
            StoredData bradleyData = new StoredData();
            PopulateContainerDefinitions(ref storedData, ref heliData, ref bradleyData);
            Interface.Oxide.DataFileSystem.WriteObject<StoredData>($"AlphaLoot/LootProfiles/{fileName}", storedData);
            Interface.Oxide.DataFileSystem.WriteObject<StoredData>($"AlphaLoot/LootProfiles/{heliFileName}", heliData);
            Interface.Oxide.DataFileSystem.WriteObject<StoredData>($"AlphaLoot/LootProfiles/{bradleyFileName}", bradleyData);
            SendReply(arg, $"Generated a default loot table to /oxide/data/AlphaLoot/LootProfiles/ ({fileName}.json, {heliFileName}.json and {bradleyFileName}.json)");
        }
        [ConsoleCommand("al.skins")]
        private void ccmdALSkins(ConsoleSystem.Arg arg) {
            if (arg.Connection != null) {
                BasePlayer player = arg.Player();
                if (player != null && !permission.UserHasPermission(player.UserIDString, ADMIN_PERMISSION)) {
                    SendReply(arg, "You do not have permission to use this command");
                    return;
                }
            }
            if (arg.Args == null || arg.Args.Length == 0) {
                SendReply(arg, "al.skins add <shortname> <skinid> <opt:weight> - Add a single skin to the random skin list, with a optional argument to specify the weight of this skin");
                SendReply(arg, "al.skins remove <shortname> - Remove all skins for the specified item");
                SendReply(arg, "al.skins remove <shortname> <skinid> - Remove an individual skin");
                return;
            }
            switch (arg.Args[0].ToLower()) {
                
// ... [Code preview truncated due to length. Full source in attached file] ...

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху