using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.0", FrameworkDisplayName = "")] [assembly: AssemblyCompany("Erenshor.RolledLootDistribution")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1")] [assembly: AssemblyProduct("Erenshor.RolledLootDistribution")] [assembly: AssemblyTitle("Erenshor.RolledLootDistribution")] [assembly: AssemblyVersion("1.0.1.0")] namespace ErenshorRolledLoot; [BepInPlugin("repdm.erenshor.rolledlootdistribution", "Rolled Loot Distribution", "1.0.1")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "repdm.erenshor.rolledlootdistribution"; public const string PluginName = "Rolled Loot Distribution"; public const string PluginVersion = "1.0.1"; internal static ConfigEntry EnabledSetting; internal static ConfigEntry RollMaximumSetting; internal static ConfigEntry ChatColorSetting; internal static IRandomRollProvider RollProvider = new UnityRandomRollProvider(); private Harmony _harmony; private void Awake() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown EnabledSetting = ((BaseUnityPlugin)this).Config.Bind("General", "Enable Rolled Distribution", true, "Adds the Rolled Distribution target to the native loot distribution window."); RollMaximumSetting = ((BaseUnityPlugin)this).Config.Bind("General", "Roll Maximum", 100, new ConfigDescription("Inclusive maximum for loot rolls.", (AcceptableValueBase)(object)new AcceptableValueRange(2, 100000), new object[0])); ChatColorSetting = ((BaseUnityPlugin)this).Config.Bind("General", "Chat Color", "#00B2B7", "HTML color used for roll messages."); _harmony = new Harmony("repdm.erenshor.rolledlootdistribution"); _harmony.PatchAll(typeof(Plugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Rolled Loot Distribution 1.0.1 loaded."); } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); } } } internal interface IRandomRollProvider { int Roll(int inclusiveMaximum); } internal sealed class UnityRandomRollProvider : IRandomRollProvider { public int Roll(int inclusiveMaximum) { return Random.Range(1, inclusiveMaximum + 1); } } internal sealed class DistributionState { internal RaidLootDist Distribution; internal ItemIcon RollSlot; internal Item RolledItem; internal SimPlayer Winner; internal RectTransform NativeSlotRect; internal RectTransform RollSlotRect; internal RectTransform NormalLabelRect; internal RectTransform RollLabelRect; internal float HorizontalOffset; internal readonly Dictionary OriginalColors = new Dictionary(); } internal static class RolledLootController { private const string WinnerMarker = " [ROLL WINNER]"; private static readonly Dictionary States = new Dictionary(); internal static void Initialize(RaidLootDist distribution) { //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) if (!Plugin.EnabledSetting.Value || (Object)(object)distribution == (Object)null || (Object)(object)distribution.AwardSlot == (Object)null || States.ContainsKey(distribution)) { return; } GameObject val = Object.Instantiate(((Component)distribution.AwardSlot).gameObject, ((Component)distribution.AwardSlot).transform.parent, false); ((Object)val).name = "Rolled Distribution Slot"; ItemIcon component = val.GetComponent(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val); return; } component.MyItem = GameData.PlayerInv.Empty; component.DistSlot = true; component.DisplayOnly = false; component.UpdateSlotImage(); Transform transform = ((Component)distribution.AwardSlot).transform; RectTransform val2 = (RectTransform)(object)((transform is RectTransform) ? transform : null); Transform transform2 = ((Component)component).transform; RectTransform val3 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null); float num; if ((Object)(object)val2 != (Object)null) { Rect rect = val2.rect; if (((Rect)(ref rect)).width > 0f) { rect = val2.rect; num = ((Rect)(ref rect)).width; goto IL_00eb; } } num = 64f; goto IL_00eb; IL_00eb: float num2 = num; float num3 = num2 + 24f; IgnoreAutomaticLayout(((Component)distribution.AwardSlot).gameObject); IgnoreAutomaticLayout(val); if ((Object)(object)val3 != (Object)null && (Object)(object)val2 != (Object)null) { val3.anchoredPosition = val2.anchoredPosition + new Vector2(num3, 0f); } RectTransform val4 = (RectTransform)(((Object)(object)distribution.DistWindow != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val4 != (Object)null) { val4.sizeDelta += new Vector2(num2 + 22f, 0f); } RectTransform normalLabelRect = CreateLabel(distribution, ((Component)distribution.AwardSlot).transform, "Normal\nDistribution", new Vector2(0f, num2 * 0.78f)); RectTransform rollLabelRect = CreateLabel(distribution, ((Component)component).transform, "Rolled\nDistribution", new Vector2(0f, num2 * 0.78f)); States.Add(distribution, new DistributionState { Distribution = distribution, RollSlot = component, NativeSlotRect = val2, RollSlotRect = val3, NormalLabelRect = normalLabelRect, RollLabelRect = rollLabelRect, HorizontalOffset = num3 }); } private static void IgnoreAutomaticLayout(GameObject target) { LayoutElement val = target.GetComponent(); if ((Object)(object)val == (Object)null) { val = target.AddComponent(); } val.ignoreLayout = true; } private static RectTransform CreateLabel(RaidLootDist distribution, Transform slot, string text, Vector2 offset) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(text + " Label", new Type[2] { typeof(RectTransform), typeof(TextMeshProUGUI) }); val.transform.SetParent(slot.parent, false); IgnoreAutomaticLayout(val); RectTransform val2 = (RectTransform)val.transform; RectTransform val3 = (RectTransform)(object)((slot is RectTransform) ? slot : null); val2.anchorMin = val3.anchorMin; val2.anchorMax = val3.anchorMax; val2.pivot = new Vector2(0.5f, 0.5f); val2.anchoredPosition = val3.anchoredPosition + offset; val2.sizeDelta = new Vector2(76f, 38f); TextMeshProUGUI component = val.GetComponent(); ((TMP_Text)component).text = text; ((TMP_Text)component).alignment = (TextAlignmentOptions)514; ((TMP_Text)component).fontSize = 13f; ((TMP_Text)component).enableWordWrapping = false; ((TMP_Text)component).overflowMode = (TextOverflowModes)0; ((Graphic)component).raycastTarget = false; if ((Object)(object)distribution.LootDistButton != (Object)null) { ((TMP_Text)component).font = ((TMP_Text)distribution.LootDistButton).font; ((Graphic)component).color = ((Graphic)distribution.LootDistButton).color; } return val2; } internal static void Tick(RaidLootDist distribution) { if (States.TryGetValue(distribution, out var value) && !((Object)(object)value.RollSlot == (Object)null)) { EnforceLayout(value); Item val = (((Object)(object)GameData.PlayerInv != (Object)null) ? GameData.PlayerInv.Empty : null); Item myItem = value.RollSlot.MyItem; if ((Object)(object)myItem != (Object)null && (Object)(object)myItem != (Object)(object)val) { ClearWinner(value); ProcessItem(value, myItem, val); } if ((Object)(object)value.RolledItem != (Object)null && (Object)(object)distribution.AwardSlot.MyItem != (Object)(object)value.RolledItem) { ClearWinner(value); value.RolledItem = null; } ApplyWinnerHighlight(value); } } private static void EnforceLayout(DistributionState state) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)state.NativeSlotRect == (Object)null) && !((Object)(object)state.RollSlotRect == (Object)null)) { Vector2 anchoredPosition = state.NativeSlotRect.anchoredPosition; state.RollSlotRect.anchoredPosition = anchoredPosition + new Vector2(state.HorizontalOffset, 0f); if ((Object)(object)state.NormalLabelRect != (Object)null) { state.NormalLabelRect.anchoredPosition = anchoredPosition + new Vector2(0f, 50f); } if ((Object)(object)state.RollLabelRect != (Object)null) { state.RollLabelRect.anchoredPosition = state.RollSlotRect.anchoredPosition + new Vector2(0f, 50f); } } } private static void ProcessItem(DistributionState state, Item item, Item empty) { state.RollSlot.MyItem = empty; state.RollSlot.UpdateSlotImage(); state.Distribution.AwardSlot.MyItem = item; state.Distribution.AwardSlot.UpdateSlotImage(); state.RolledItem = item; if (!IsSupportedGear(item)) { AddChat("Rolled Distribution only supports equippable gear; " + item.ItemName + " was moved to Normal Distribution."); return; } List interestedPlayers = GetInterestedPlayers(state.Distribution, item); if (interestedPlayers.Count == 0) { AddChat("No SimPlayers are interested in " + item.ItemName + ". It remains available for Normal Distribution."); return; } if (interestedPlayers.Count == 1) { state.Winner = interestedPlayers[0]; AddChat(GetName(state.Winner) + " is the only SimPlayer interested in " + item.ItemName + " and wins by default."); return; } AddChat("Rolling 1-" + Plugin.RollMaximumSetting.Value + " for " + item.ItemName + "."); List list = RollRound(interestedPlayers, tieBreak: false); while (list.Count > 1) { AddChat("Tie between " + JoinNames(list) + ". Rerolling tied leaders."); list = RollRound(list, tieBreak: true); } state.Winner = list[0]; AddChat(GetName(state.Winner) + " wins " + item.ItemName + ". Use the highlighted native Give row to award it."); } private static List RollRound(List entrants, bool tieBreak) { int num = 0; List list = new List(); for (int i = 0; i < entrants.Count; i++) { int num2 = Plugin.RollProvider.Roll(Plugin.RollMaximumSetting.Value); AddChat(GetName(entrants[i]) + " rolls " + num2 + (tieBreak ? " (tiebreak)." : ".")); if (num2 > num) { num = num2; list.Clear(); list.Add(entrants[i]); } else if (num2 == num) { list.Add(entrants[i]); } } return list; } private static List GetInterestedPlayers(RaidLootDist distribution, Item item) { List result = new List(); if (distribution.UseGroup) { SimPlayerTracking[] groupMembers = GameData.GroupMembers; if (groupMembers != null) { for (int i = 0; i < groupMembers.Length; i++) { TryAddInterested(result, (groupMembers[i] != null) ? groupMembers[i].MyAvatar : null, item); } } } else if ((Object)(object)GameData.RaidManager != (Object)null && GameData.RaidManager.Raiders != null) { for (int j = 0; j < GameData.RaidManager.Raiders.Count; j++) { RaidMemberSlot val = GameData.RaidManager.Raiders[j]; TryAddInterested(result, ((Object)(object)val != (Object)null) ? val.AssignedAvatar : null, item); } } return result; } private static void TryAddInterested(List result, SimPlayer player, Item item) { if ((Object)(object)player != (Object)null && !result.Contains(player) && player.IsThatAnUpgrade(item)) { result.Add(player); } } private static bool IsSupportedGear(Item item) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)item == (Object)null || item.SimPlayersCantGet || Convert.ToInt32(item.RequiredSlot) == 0) { return false; } if ((Object)(object)item.TeachSpell != (Object)null || (Object)(object)item.TeachSkill != (Object)null || item.Stackable) { return false; } if ((Object)(object)GameData.GM != (Object)null && ((Object)(object)item == (Object)(object)GameData.GM.Sivak || (Object)(object)item == (Object)(object)GameData.GM.Planar)) { return false; } return true; } private static void ApplyWinnerHighlight(DistributionState state) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)state.Winner == (Object)null || state.Distribution.Recipients == null) { return; } for (int i = 0; i < state.Distribution.Recipients.Count; i++) { LootAwardSlot val = state.Distribution.Recipients[i]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val.SP != (Object)(object)state.Winner) && ((Component)val).gameObject.activeInHierarchy && !((Object)(object)val.AwardButtonTxt == (Object)null)) { if (!state.OriginalColors.ContainsKey(val)) { state.OriginalColors.Add(val, ((Graphic)val.AwardButtonTxt).color); } if (!((TMP_Text)val.AwardButtonTxt).text.Contains(" [ROLL WINNER]")) { TextMeshProUGUI awardButtonTxt = val.AwardButtonTxt; ((TMP_Text)awardButtonTxt).text = ((TMP_Text)awardButtonTxt).text + " [ROLL WINNER]"; } ((Graphic)val.AwardButtonTxt).color = Color.yellow; } } } internal static void Clear(RaidLootDist distribution) { if (!States.TryGetValue(distribution, out var value)) { return; } ClearWinner(value); value.RolledItem = null; if ((Object)(object)value.RollSlot != (Object)null && (Object)(object)GameData.PlayerInv != (Object)null) { Item myItem = value.RollSlot.MyItem; if ((Object)(object)myItem != (Object)null && (Object)(object)myItem != (Object)(object)GameData.PlayerInv.Empty && (Object)(object)distribution.AwardSlot != (Object)null && (Object)(object)distribution.AwardSlot.MyItem == (Object)(object)GameData.PlayerInv.Empty) { distribution.AwardSlot.MyItem = myItem; distribution.AwardSlot.UpdateSlotImage(); } value.RollSlot.MyItem = GameData.PlayerInv.Empty; value.RollSlot.UpdateSlotImage(); } } private static void ClearWinner(DistributionState state) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair originalColor in state.OriginalColors) { if ((Object)(object)originalColor.Key != (Object)null && (Object)(object)originalColor.Key.AwardButtonTxt != (Object)null) { ((TMP_Text)originalColor.Key.AwardButtonTxt).text = ((TMP_Text)originalColor.Key.AwardButtonTxt).text.Replace(" [ROLL WINNER]", string.Empty); ((Graphic)originalColor.Key.AwardButtonTxt).color = originalColor.Value; } } state.OriginalColors.Clear(); state.Winner = null; } private static string GetName(SimPlayer player) { if ((Object)(object)player == (Object)null) { return "Unknown SimPlayer"; } NPC thisNPC = player.GetThisNPC(); if (!((Object)(object)thisNPC != (Object)null) || string.IsNullOrEmpty(((Object)thisNPC).name)) { return ((Object)player).name; } return ((Object)thisNPC).name; } private static string JoinNames(List players) { string[] array = new string[players.Count]; for (int i = 0; i < players.Count; i++) { array[i] = GetName(players[i]); } return string.Join(", ", array); } private static void AddChat(string message) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown UpdateSocialLog.LogAdd(new ChatLogLine("[LOOT ROLL] " + message, (LogType)4194304, Plugin.ChatColorSetting.Value)); } } [HarmonyPatch(typeof(RaidLootDist), "Start")] internal static class RaidLootStartPatch { private static void Postfix(RaidLootDist __instance) { RolledLootController.Initialize(__instance); } } [HarmonyPatch(typeof(RaidLootDist), "Update")] internal static class RaidLootUpdatePatch { private static void Postfix(RaidLootDist __instance) { RolledLootController.Tick(__instance); } } [HarmonyPatch(typeof(RaidLootDist), "CloseDistWindow")] internal static class RaidLootClosePatch { private static void Prefix(RaidLootDist __instance) { RolledLootController.Clear(__instance); } } [HarmonyPatch(typeof(RaidLootDist), "OpenCloseDistWindow")] internal static class RaidLootTogglePatch { private static void Prefix(RaidLootDist __instance) { if ((Object)(object)__instance.DistWindow != (Object)null && __instance.DistWindow.activeSelf) { RolledLootController.Clear(__instance); } } } [HarmonyPatch(typeof(LootAwardSlot), "AwardItemToSim")] internal static class AwardItemPatch { private static void Postfix() { if ((Object)(object)GameData.GroupLootDist != (Object)null) { RolledLootController.Clear(GameData.GroupLootDist); } } } [HarmonyPatch(typeof(LootAwardSlot), "AwardItemToSimPrim")] internal static class AwardPrimaryPatch { private static void Postfix() { if ((Object)(object)GameData.GroupLootDist != (Object)null) { RolledLootController.Clear(GameData.GroupLootDist); } } } [HarmonyPatch(typeof(LootAwardSlot), "AwardItemToSimSec")] internal static class AwardSecondaryPatch { private static void Postfix() { if ((Object)(object)GameData.GroupLootDist != (Object)null) { RolledLootController.Clear(GameData.GroupLootDist); } } }