Decompiled source of Unofficial EpicLoot BountyAdditions v1.3.0

plugins/UnofficialEpicLootBountyAdditions/UnofficialEpicLootBountyAdditions.dll

Decompiled 5 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using EpicLoot;
using EpicLoot.Adventure;
using EpicLoot.Adventure.Feature;
using EpicLoot.Biomes;
using HarmonyLib;
using Jotunn.Managers;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyCompany("UnofficialEpicLootBountyAdditions")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.3.0.0")]
[assembly: AssemblyInformationalVersion("1.3.0")]
[assembly: AssemblyProduct("UnofficialEpicLootBountyAdditions")]
[assembly: AssemblyTitle("UnofficialEpicLootBountyAdditions")]
[assembly: AssemblyVersion("1.3.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace VanillaBounties
{
	[BepInPlugin("vapok.mods.unofficialepiclootbountyadditions", "Unofficial EpicLoot BountyAdditions", "1.3.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	[SynchronizationMode(/*Could not decode attribute arguments.*/)]
	public sealed class VanillaBountiesPlugin : BaseUnityPlugin
	{
		public const string PluginId = "vapok.mods.unofficialepiclootbountyadditions";

		public const string PluginName = "Unofficial EpicLoot BountyAdditions";

		public const string PluginVersion = "1.3.0";

		private Harmony _harmony;

		internal static ConfigEntry<int> VanillaBossDropMultiplier { get; private set; }

		internal static ConfigEntry<bool> GuaranteeEpicLootItem { get; private set; }

		internal static ManualLogSource LogSource { get; private set; }

		private void Awake()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Expected O, but got Unknown
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Expected O, but got Unknown
			LogSource = ((BaseUnityPlugin)this).Logger;
			ConfigurationManagerAttributes val = new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			};
			VanillaBossDropMultiplier = ((BaseUnityPlugin)this).Config.Bind<int>("Boss Bounty Rewards", "Vanilla Drop Multiplier", 2, new ConfigDescription("Total multiplier for every vanilla drop from a bounty boss, including trophies, boss keys and Wishbones.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), new object[1] { val }));
			GuaranteeEpicLootItem = ((BaseUnityPlugin)this).Config.Bind<bool>("Boss Bounty Rewards", "Guarantee Epic Loot Item", true, new ConfigDescription("Guarantees that the first eligible Epic Loot gear result from a bounty boss remains an enchanted item instead of being converted to materials, a shard or an unidentified item. Does not add another loot-table roll.", (AcceptableValueBase)null, new object[1] { val }));
			_harmony = new Harmony("vapok.mods.unofficialepiclootbountyadditions");
			_harmony.PatchAll();
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class BossBountyRewards
	{
		internal const string CompletionSentKey = "VanillaBounties.CompletionSent";

		internal const string RewardContextKey = "VanillaBounties.BossRewardContext";

		private const string BountyIdKey = "BountyID";

		private const string BountyDataKey = "BountyData";

		private const string MonsterIdKey = "MonsterID";

		private const string IsAddKey = "IsAdd";

		internal static bool IsBossBounty(Character character)
		{
			ZDO zdo;
			string monsterId;
			BountyInfo bounty;
			return TryGetBossBounty(character, out zdo, out monsterId, out bounty);
		}

		internal static bool TryGetBossBounty(Character character, out ZDO zdo, out string monsterId, out BountyInfo bounty)
		{
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			zdo = null;
			monsterId = null;
			bounty = null;
			if ((Object)(object)character == (Object)null)
			{
				return false;
			}
			ZNetView component = ((Component)character).GetComponent<ZNetView>();
			zdo = ((component != null) ? component.GetZDO() : null);
			if (zdo == null || string.IsNullOrWhiteSpace(zdo.GetString("BountyID", "")) || zdo.GetBool("IsAdd", false))
			{
				return false;
			}
			monsterId = zdo.GetString("MonsterID", "");
			object obj;
			if (!string.IsNullOrWhiteSpace(monsterId))
			{
				GameObject prefab = PrefabManager.Instance.GetPrefab(monsterId);
				obj = ((prefab != null) ? prefab.GetComponent<Character>() : null);
			}
			else
			{
				obj = null;
			}
			Character val = (Character)obj;
			if ((Object)(object)val == (Object)null || !val.IsBoss())
			{
				return false;
			}
			string text = zdo.GetString("BountyData", "");
			if (!string.IsNullOrWhiteSpace(text))
			{
				try
				{
					bounty = BountyInfo.FromPackage(new ZPackage(text));
				}
				catch (Exception ex)
				{
					VanillaBountiesPlugin.LogSource.LogWarning((object)("Could not read bounty data for " + monsterId + ": " + ex.Message));
				}
			}
			return true;
		}

		internal static bool IsProtectedBossDrop(GameObject prefab)
		{
			if ((Object)(object)prefab == (Object)null)
			{
				return true;
			}
			return false;
		}
	}
	internal static class BossBountyEpicLootReward
	{
		[ThreadStatic]
		private static bool _guaranteedItemPending;

		internal static void Begin(bool isBossBounty)
		{
			_guaranteedItemPending = isBossBounty && VanillaBountiesPlugin.GuaranteeEpicLootItem.Value;
		}

		internal static void End()
		{
			_guaranteedItemPending = false;
		}

		internal static bool TryConsumeFor(LootDrop lootDrop, bool isShardDrop)
		{
			if (!_guaranteedItemPending || isShardDrop || lootDrop == null || string.IsNullOrWhiteSpace(lootDrop.Item) || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return false;
			}
			GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(lootDrop.Item);
			ItemDrop val = ((itemPrefab != null) ? itemPrefab.GetComponent<ItemDrop>() : null);
			if ((Object)(object)val == (Object)null || !EpicLoot.IsAllowedMagicItemType(val.m_itemData))
			{
				return false;
			}
			_guaranteedItemPending = false;
			VanillaBountiesPlugin.LogSource.LogInfo((object)("Guaranteed bounty-boss Epic Loot item from resolved entry " + lootDrop.Item + "."));
			return true;
		}
	}
	[HarmonyPatch(typeof(LootRoller), "SelectDropType")]
	internal static class BossBountyEpicLootCategoryPatch
	{
		private static bool Prefix(LootDrop lootDrop, bool isShardDrop, ref LootDropType __result)
		{
			if (!BossBountyEpicLootReward.TryConsumeFor(lootDrop, isShardDrop))
			{
				return true;
			}
			__result = (LootDropType)0;
			return false;
		}
	}
	[HarmonyPatch(typeof(CharacterDrop), "OnDeath")]
	[HarmonyAfter(new string[] { "randyknapp.mods.epicloot" })]
	internal static class BossBountyInstantRewardContextPatch
	{
		private static void Prefix(CharacterDrop __instance)
		{
			BossBountyEpicLootReward.Begin(BossBountyRewards.IsBossBounty(((Component)__instance).GetComponent<Character>()));
		}

		private static void Postfix()
		{
			BossBountyEpicLootReward.End();
		}

		private static Exception Finalizer(Exception __exception)
		{
			BossBountyEpicLootReward.End();
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Ragdoll), "Setup")]
	[HarmonyAfter(new string[] { "randyknapp.mods.epicloot" })]
	internal static class BossBountyRagdollMarkerPatch
	{
		private static void Postfix(Ragdoll __instance, CharacterDrop characterDrop)
		{
			if (!((Object)(object)characterDrop != (Object)null) || !BossBountyRewards.IsBossBounty(((Component)characterDrop).GetComponent<Character>()))
			{
				return;
			}
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if (component != null)
			{
				ZDO zDO = component.GetZDO();
				if (zDO != null)
				{
					zDO.Set("VanillaBounties.BossRewardContext", true);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Ragdoll), "SpawnLoot")]
	[HarmonyAfter(new string[] { "randyknapp.mods.epicloot" })]
	internal static class BossBountyRagdollRewardContextPatch
	{
		private static void Prefix(Ragdoll __instance)
		{
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			ZDO val = ((component != null) ? component.GetZDO() : null);
			BossBountyEpicLootReward.Begin(val != null && val.GetBool("VanillaBounties.BossRewardContext", false));
		}

		private static void Postfix()
		{
			BossBountyEpicLootReward.End();
		}

		private static Exception Finalizer(Exception __exception)
		{
			BossBountyEpicLootReward.End();
			return __exception;
		}
	}
	[HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")]
	[HarmonyAfter(new string[] { "randyknapp.mods.epicloot" })]
	internal static class BossBountyVanillaDropsPatch
	{
		private static void Postfix(CharacterDrop __instance, ref List<KeyValuePair<GameObject, int>> __result)
		{
			int value = VanillaBountiesPlugin.VanillaBossDropMultiplier.Value;
			Character component = ((Component)__instance).GetComponent<Character>();
			if (value <= 1 || __result == null || !BossBountyRewards.IsBossBounty(component))
			{
				return;
			}
			for (int i = 0; i < __result.Count; i++)
			{
				KeyValuePair<GameObject, int> keyValuePair = __result[i];
				if (!BossBountyRewards.IsProtectedBossDrop(keyValuePair.Key))
				{
					int value2 = ((keyValuePair.Value > int.MaxValue / value) ? int.MaxValue : (keyValuePair.Value * value));
					__result[i] = new KeyValuePair<GameObject, int>(keyValuePair.Key, value2);
				}
			}
			VanillaBountiesPlugin.LogSource.LogInfo((object)$"Applied {value}x vanilla material drops to bounty boss {((Object)component).name}.");
		}
	}
	[HarmonyPatch(typeof(CharacterDrop), "OnDeath")]
	[HarmonyBefore(new string[] { "randyknapp.mods.epicloot" })]
	internal static class BossBountyCompletionPatch
	{
		private static void Postfix(CharacterDrop __instance)
		{
			Character component = ((Component)__instance).GetComponent<Character>();
			if (!BossBountyRewards.TryGetBossBounty(component, out var zdo, out var monsterId, out var bounty) || bounty == null || zdo.GetBool("VanillaBounties.CompletionSent", false))
			{
				return;
			}
			ZNetView component2 = ((Component)component).GetComponent<ZNetView>();
			if ((Object)(object)component2 == (Object)null || !component2.IsOwner() || ZRoutedRpc.instance == null)
			{
				return;
			}
			zdo.Set("VanillaBounties.CompletionSent", true);
			ReportSlain(bounty, monsterId, isAdd: false);
			int num = 0;
			foreach (BountyTargetInfo item in bounty.Adds ?? new List<BountyTargetInfo>())
			{
				for (int i = 0; i < item.Count; i++)
				{
					ReportSlain(bounty, item.MonsterID, isAdd: true);
					num++;
				}
			}
			VanillaBountiesPlugin.LogSource.LogInfo((object)$"Reported bounty boss {monsterId} slain and credited {num} encounter add(s).");
		}

		private static void ReportSlain(BountyInfo bounty, string monsterId, bool isAdd)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			ZPackage val = new ZPackage();
			bounty.ToPackage(val);
			ZRoutedRpc.instance.InvokeRoutedRPC(0L, "SlayBountyTarget", new object[3] { val, monsterId, isAdd });
		}
	}
	[HarmonyPatch(typeof(BountiesAdventureFeature), "GetAvailableBounties", new Type[]
	{
		typeof(int),
		typeof(bool),
		typeof(List<BountyFilterNote>)
	})]
	internal static class BountySelectionPatch
	{
		private const int BossRandomStream = 1;

		private static void Prefix(out List<BountyTargetConfig> __state)
		{
			__state = AdventureDataManager.Config?.Bounties?.Targets;
			if (__state != null)
			{
				AdventureDataManager.Config.Bounties.Targets = __state.Where((BountyTargetConfig target) => !IsBossTarget(target)).ToList();
			}
		}

		private static void Postfix(int interval, bool removeAcceptedBounties, ref List<BountyInfo> __result, List<BountyTargetConfig> __state)
		{
			RestoreTargets(__state);
			if (__state == null || __result == null || (Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null)
			{
				return;
			}
			List<IGrouping<string, BountyTargetConfig>> list = (from target in __state.Where(IsEligibleDefeatedBoss)
				group target by target.TargetID into @group
				orderby @group.Min((BountyTargetConfig target) => BiomeDataManager.GetOrder(target.GetBiome()))
				select @group).ThenBy<IGrouping<string, BountyTargetConfig>, string>((IGrouping<string, BountyTargetConfig> group) => group.Key, StringComparer.Ordinal).ToList();
			if (list.Count == 0)
			{
				return;
			}
			AdventureSaveData adventureSaveData = PlayerExtensions_Adventure.GetAdventureSaveData(Player.m_localPlayer);
			Random random = CreateBossRandom(interval);
			int num = PositiveModulo(interval, list.Count);
			for (int num2 = 0; num2 < list.Count; num2++)
			{
				List<BountyTargetConfig> list2 = list[(num + num2) % list.Count].ToList();
				BountyInfo val = CreateBounty(list2[random.Next(list2.Count)], interval, random);
				if (!removeAcceptedBounties || !adventureSaveData.HasAcceptedBounty(val.Interval, val.ID))
				{
					__result.Add(val);
					break;
				}
			}
		}

		private static Exception Finalizer(Exception __exception, List<BountyTargetConfig> __state)
		{
			RestoreTargets(__state);
			return __exception;
		}

		private static void RestoreTargets(List<BountyTargetConfig> targets)
		{
			if (targets != null && AdventureDataManager.Config?.Bounties != null)
			{
				AdventureDataManager.Config.Bounties.Targets = targets;
			}
		}

		private static bool IsBossTarget(BountyTargetConfig target)
		{
			if (target == null || string.IsNullOrWhiteSpace(target.TargetID))
			{
				return false;
			}
			GameObject prefab = PrefabManager.Instance.GetPrefab(target.TargetID);
			Character val = ((prefab != null) ? prefab.GetComponent<Character>() : null);
			if ((Object)(object)val != (Object)null)
			{
				return val.IsBoss();
			}
			return false;
		}

		private static bool IsEligibleDefeatedBoss(BountyTargetConfig target)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (!IsBossTarget(target))
			{
				return false;
			}
			Biome biome = target.GetBiome();
			if ((int)biome == 0)
			{
				return false;
			}
			IReadOnlyList<string> bossKeys = BiomeDataManager.GetBossKeys(biome);
			if (bossKeys.Count > 0)
			{
				return bossKeys.All((string key) => ZoneSystem.instance.GetGlobalKey(key));
			}
			return false;
		}

		private static Random CreateBossRandom(int interval)
		{
			int num = (int)Player.m_localPlayer.GetPlayerID();
			int refreshInterval = AdventureDataManager.Config.Bounties.RefreshInterval;
			return new Random(num + interval * 1000 + refreshInterval * 100 + 7919);
		}

		private static BountyInfo CreateBounty(BountyTargetConfig target, int interval, Random random)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Expected O, but got Unknown
			return new BountyInfo
			{
				Biome = target.GetBiome(),
				Interval = interval,
				PlayerID = Player.m_localPlayer.GetPlayerID(),
				Target = new BountyTargetInfo
				{
					MonsterID = target.TargetID,
					Level = GetTargetLevel(random, target.RewardGold > 0, isAdd: false),
					Count = 1
				},
				TargetName = BountiesAdventureFeature.GenerateTargetName(random),
				RewardIron = target.RewardIron,
				RewardGold = target.RewardGold,
				RewardCoins = target.RewardCoins,
				Adds = ((IEnumerable<BountyTargetAddConfig>)(target.Adds ?? new List<BountyTargetAddConfig>())).Select((Func<BountyTargetAddConfig, BountyTargetInfo>)((BountyTargetAddConfig add) => new BountyTargetInfo
				{
					MonsterID = add.ID,
					Count = add.Count,
					Level = GetTargetLevel(random, isGold: false, isAdd: true)
				})).ToList()
			};
		}

		private static int GetTargetLevel(Random random, bool isGold, bool isAdd)
		{
			BountiesConfig bounties = AdventureDataManager.Config.Bounties;
			int minValue = (isAdd ? bounties.AddsMinLevel : (isGold ? bounties.GoldMinLevel : bounties.IronMinLevel));
			int num = (isAdd ? bounties.AddsMaxLevel : (isGold ? bounties.GoldMaxLevel : bounties.IronMaxLevel));
			return random.Next(minValue, num + 1);
		}

		private static int PositiveModulo(int value, int divisor)
		{
			int num = value % divisor;
			if (num >= 0)
			{
				return num;
			}
			return num + divisor;
		}
	}
}