using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Dynamic.Core; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Bounce.ManagedCollections; using Bounce.Singletons; using Bounce.Unmanaged; using Dice; using GameChat.UI; using HarmonyLib; using ModdingTales; using Newtonsoft.Json; using RadialUI; using TMPro; using Unity.Mathematics; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("D20Plugin")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Nth Dimension")] [assembly: AssemblyProduct("D20Plugin")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("D20Plugin")] [assembly: ComVisible(false)] [assembly: Guid("c303405d-e66c-4316-9cdb-4e3ca15c6360")] [assembly: AssemblyFileVersion("3.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("3.0.0.0")] namespace LordAshes; [BepInPlugin("org.lordashes.plugins.d20", "D20 Plugin", "3.0.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class PluginD20 : BaseUnityPlugin { public static class Characters { public class SpecPair { public string key { get; set; } = "key"; public string value { get; set; } = "Undefined"; public SpecPair() { } public SpecPair(string key) { this.key = key; value = "Undefined"; } public SpecPair(string key, string value) { this.key = key; this.value = value; } } public class Spec { public string name { get; set; } = "Skill"; public string formula { get; set; } = null; public List extra { get; set; } = null; public string menu { get; set; } = null; public Spec(string name, string formula, List extra = null, string menu = null) { this.name = name; this.formula = formula; this.extra = extra; this.menu = menu; } public string Extra(string name) { return extra.Where((SpecPair e) => e.key == name).FirstOrDefault()?.value; } } public class CharacterSpecs { public string name { get; set; } = "Unnamed"; public string chainSources { get; set; } = null; public List specs { get; set; } = new List(); public void AddAbilityScore(string name, string value, string menu = null) { specs.Add(new Spec(name, ((int.Parse(value) >= 10) ? ((int.Parse(value) - 10) / 2) : ((int.Parse(value) - 11) / 2)).ToString(), new List { new SpecPair("type", "ability"), new SpecPair("value", value) }, menu)); } public void AddValue(string name, string value, string menu = null) { specs.Add(new Spec(name, value, new List { new SpecPair("type", "value") }, menu)); } public void AddSave(string name, string formula, string menu = null) { specs.Add(new Spec(name, formula, new List { new SpecPair("type", "save") }, menu)); } public void AddSkill(string name, string formula, string menu = null) { specs.Add(new Spec(name, formula, new List { new SpecPair("type", "skill") }, menu)); } public void AddSkill(string name, string formula, string opposed, string menu = null) { specs.Add(new Spec(name, formula, new List { new SpecPair("type", "skill"), new SpecPair("opposed", opposed) }, menu)); } public void AddAttack(string name, string formula, string opposed, string menu = null) { specs.Add(new Spec(name, formula, new List { new SpecPair("type", "attack"), new SpecPair("opposed", opposed) }, menu)); } public void AddDamage(string name, string formula, string damageType, string menu = null) { specs.Add(new Spec(name, formula, new List { new SpecPair("type", "damage"), new SpecPair("damageType", damageType) }, menu)); } public void AddHealing(string name, string formula, string menu = null) { specs.Add(new Spec(name, formula, new List { new SpecPair("type", "heal") }, menu)); } public void AddResistances(string name, string list, string damageType, string menu = null) { List list2 = new List(); string[] array = list.Split(new char[1] { ',' }); foreach (string text in array) { list2.Add(new SpecPair(text, text)); } specs.Add(new Spec("Resistances", list, list2, menu)); } public void AddImmunities(string name, string list, string damageType, string menu = null) { List list2 = new List(); string[] array = list.Split(new char[1] { ',' }); foreach (string text in array) { list2.Add(new SpecPair(text, text)); } specs.Add(new Spec("Immunities", list, list2, menu)); } public void AddVulnerabilities(string name, string list, string damageType, string menu = null) { List list2 = new List(); string[] array = list.Split(new char[1] { ',' }); foreach (string text in array) { list2.Add(new SpecPair(text, text)); } specs.Add(new Spec("Resistances", list, list2, menu)); } public void AddOrModifyValue(string name, string value, string menu = null) { Spec spec = FindFirst(name); if (spec == null) { specs.Add(new Spec(name, value, new List { new SpecPair("type", "value") }, menu)); } else { spec.formula = value; } } public string Resolve(string formula, int replacements = 0) { LoggingPlugin.LogTrace("Processing Resolve: Formula=" + (formula ?? "Empty Formula") + ", Max Replacements=" + replacements); if (formula == null || formula.Trim() == "") { return ""; } int num = 0; string text = ""; for (int i = 0; i < nestedResolve; i++) { foreach (Spec spec in specs) { foreach (SpecPair item in spec.extra) { LoggingPlugin.LogTrace("Processing Resolve: Replacing [" + spec.name + "." + item.key + "] With " + item.value); text = formula; formula = formula.Replace("[" + spec.name + "." + item.key + "]", item.value); if (text != formula) { num++; } if (replacements > 0 && num >= replacements) { LoggingPlugin.LogTrace("Processing Resolve: Max Replacement " + replacements + " Resolve: " + formula); return formula; } LoggingPlugin.LogTrace("Processing Resolve: Formula=" + formula + ", Replacements Count=" + num); } LoggingPlugin.LogTrace("Processing Resolve: Replacing [" + spec.name + "] With " + spec.formula.ToString()); text = formula; formula = formula.Replace("[" + spec.name + "]", spec.formula.ToString()); formula = formula.Replace("+-", "-").Replace("-+", "-").Replace("--", "+") .Replace("++", "+"); if (text != formula) { num++; } if (replacements > 0 && num >= replacements) { LoggingPlugin.LogTrace("Processing Resolve: Max Replacement " + replacements + " Resolve: " + formula); return formula; } LoggingPlugin.LogTrace("Processing Resolve: Formula=" + formula + ", Replacements Count=" + num); } } LoggingPlugin.LogTrace("Processing Resolve: Full Resolve: " + formula); return formula; } public Spec[] Find(string whereClause) { if (specs == null || specs.Count == 0 || string.IsNullOrWhiteSpace(whereClause)) { return null; } if (whereClause.IndexOf("=") < 0 && whereClause.IndexOf("<") < 0 && whereClause.IndexOf(">") < 0) { whereClause = "name==\"" + whereClause + "\""; } LoggingPlugin.LogTrace("Find: " + whereClause); return DynamicQueryableExtensions.Where(specs.AsQueryable(), whereClause, Array.Empty()).ToArray(); } public Spec FindFirst(string whereClause) { Spec[] array = Find(whereClause); LoggingPlugin.LogTrace("FindFirst: " + ((array != null) ? array.Length.ToString() : "0") + " Matches"); return (array != null && array.Count() > 0) ? array[0] : null; } public string FindFirstValue(string whereClause) { Spec spec = FindFirst(whereClause); LoggingPlugin.LogTrace("FindFirstValue: " + ((spec != null) ? (spec.name + "=" + spec.formula) : "Null")); return (spec != null) ? spec.formula : ""; } public string FindFirstExtraValue(string whereClause, string property) { Spec spec = FindFirst(whereClause); return (spec != null) ? spec.extra.Where((SpecPair p) => p.key == property).FirstOrDefault().value : ""; } public CreatureBoardAsset FindAsset() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return ((IEnumerable)(object)CreaturePresenter.GetTempReadOnlyViewOfAllCreatureAssets()).Where((CreatureBoardAsset a) => a.Name.Contains(name)).FirstOrDefault(); } public CreatureBoardAsset[] FindAssets() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return ((IEnumerable)(object)CreaturePresenter.GetTempReadOnlyViewOfAllCreatureAssets()).Where((CreatureBoardAsset a) => a.Name.Contains(name)).ToArray(); } } public class CharactersSpecs { public enum CheckType { Regular = 1, Opposed, Attack, Damage, Effect, Heal, Generic } private List sheets = new List(); private List builtPaths = new List(); public static Sprite fallbackSprite = Image.LoadSprite("org.lordashes.plugins.d20.character.png", (CacheType)999); public List All() { return sheets; } public void Add(CharacterSpecs specs) { sheets.Add(specs); } public void Remove(string name) { for (int i = 0; i < sheets.Count; i++) { if (sheets[i].name == name) { sheets.RemoveAt(i); i--; } } } public void LoadCharacters(bool reload = false) { //IL_00a0: 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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Expected O, but got Unknown sheets.Clear(); builtPaths.Clear(); string[] array = File.Find("org.lordashes.plugins.d20.character.", (CacheType)999); foreach (string text in array) { if (text.ToLower().EndsWith(".json")) { LoadCharacter(text); } } LoggingPlugin.LogInfo("Loaded " + _self.characters.sheets.Count + " Character Sheets"); if (!reload) { RadialUIPlugin.AddCustomButtonOnCharacter("org.lordashes.plugins.d20", new ItemArgs { Action = delegate { //IL_000e: Unknown result type (might be due to invalid IL or missing references) LoggingPlugin.LogTrace("Selected Character Menu. Triggering Deep Menu..."); CreatureBoardAsset val = null; CreaturePresenter.TryGetAsset(LocalClient.SelectedCreatureId, ref val); DeepMenusPlugin.NavigateTo(DiceRoller.StripTrailingInteger(val.Name)); }, CloseMenuOnActivate = true, FadeName = true, Icon = LoadSpriteOrDefault("org.lordashes.plugins.d20.character.png", fallbackSprite), Title = "Actions" }, (Func)delegate { //IL_000e: Unknown result type (might be due to invalid IL or missing references) CreatureBoardAsset instigator = null; CreaturePresenter.TryGetAsset(LocalClient.SelectedCreatureId, ref instigator); if ((Object)(object)instigator != (Object)null) { LoggingPlugin.LogDebug("Looking for Sheet For '" + DiceRoller.StripTrailingInteger(instigator.Name) + "'"); return _self.characters.sheets.Any((CharacterSpecs c) => c.name == DiceRoller.StripTrailingInteger(instigator.Name)); } return false; }); } foreach (CharacterSpecs character in sheets) { DeepMenusPlugin._self.CreateSubMenuItem("/" + character.name, DeepMenusPlugin._self.MakeItemEntry("Edit", (Action)delegate { LoadUserSettings(_self.characters.FindFirst(character.name)); menuEditOpen = true; GameInputEnabled(!menuEditOpen); }, LoadSpriteOrDefault("org.lordashes.plugins.d20.edit.png", fallbackSprite), false, true), (Func)(() => true)); foreach (Spec spec in character.specs) { LoggingPlugin.LogTrace("Considering Entry " + spec.name + " (" + spec.menu + ")"); if (spec.menu != null && spec.menu.Trim() != "") { BuildMenu(character.name, spec.menu); } } } } private static void LoadCharacter(string characterSheet) { string text = File.ReadAllText(characterSheet, (CacheType)999); text = text.TrimStart('\ufeff', '\u200b'); LoggingPlugin.LogInfo("Loading Character Sheet From " + characterSheet); try { CharacterSpecs characterSpecs = JsonConvert.DeserializeObject(text); string characterName = characterSpecs.name; if (!_self.characters.All().Any((CharacterSpecs cs) => cs.name == characterName)) { _self.characters.Add(characterSpecs); if (characterSpecs.chainSources == null || !(characterSpecs.chainSources != "")) { return; } LoggingPlugin.LogDebug("Chain Loading Set To " + characterSpecs.chainSources); LoggingPlugin.LogDebug(JsonConvert.SerializeObject((object)characterSpecs)); string[] array = characterSpecs.chainSources.Split(new char[1] { ',' }); string[] array2 = array; foreach (string text2 in array2) { LoggingPlugin.LogDebug("Chain Loading org.lordashes.plugins.d20.character." + text2); text = File.ReadAllText("org.lordashes.plugins.d20.common." + text2, (CacheType)999); text = text.TrimStart('\ufeff', '\u200b'); CharacterSpecs characterSpecs2 = JsonConvert.DeserializeObject(text); foreach (Spec spec in characterSpecs2.specs) { if (!characterSpecs.specs.Where((Spec s) => s.name == spec.name).Any()) { LoggingPlugin.LogDebug("Adding Chain Spec " + spec.name); characterSpecs.specs.Add(spec); } else { LoggingPlugin.LogDebug("Ignoring Chain Spec " + spec.name + " (Already Exists)"); } } } } else { LoggingPlugin.LogWarning("Duplicated Character Sheet For '" + characterName + "'"); SystemMessage.DisplayInfoText("D20 Plugin:\r\nDuplicate Character " + characterName, 2.5f, 0f, (Action)null); } } catch (Exception ex) { string fileName = Path.GetFileName(characterSheet); if (ex.Message.IndexOf("line") > -1) { string text3 = ex.Message.Substring(ex.Message.IndexOf("line") + 4).Trim(); text3 = text3.Substring(0, text3.IndexOf(",")).Trim(); LoggingPlugin.LogError("Error On Line " + text3.Substring(1) + " Of " + fileName + " (" + ex.Message + ")"); try { int num2 = int.Parse(text3); string[] array3 = text.Split(new string[1] { "\r\n" }, StringSplitOptions.None); LoggingPlugin.LogError("Problem Line: " + array3[num2].Trim()); } catch (Exception ex2) { LoggingPlugin.LogError("'" + text3 + "'"); LoggingPlugin.LogError(ex2.Message); } } else { LoggingPlugin.LogError(ex.Message); } string[] source = text.Split(new string[1] { "\r\n" }, StringSplitOptions.None); string text4 = string.Join("\r\n", source.Select((string line, int index) => $"Line {index + 1:0000}: {line}")); LoggingPlugin.LogInfo("Fault JSON:\r\n" + text4); } } public CharacterSpecs[] Find(string name) { if (name == "") { return null; } return DynamicQueryableExtensions.Where(sheets.AsQueryable(), "name==\"" + name + "\"", Array.Empty()).ToArray(); } public CharacterSpecs FindFirst(string name) { if (name == "") { return null; } return DynamicQueryableExtensions.Where(sheets.AsQueryable(), "name==\"" + name + "\"", Array.Empty()).FirstOrDefault(); } public string FindValue(string name, string whereClause) { return FindFirst(name)?.FindFirstValue(whereClause); } public static Sprite LoadSpriteOrDefault(string seekSprite, Sprite fallBackSprite) { if (File.Find(seekSprite, (CacheType)999).Any()) { return Image.LoadSprite(seekSprite, (CacheType)999); } return fallBackSprite; } private void BuildMenu(string characterName, string menu) { menu = "/" + characterName + menu; string text = menu.Substring(menu.LastIndexOf("/") + 1); string text2 = menu.Substring(0, menu.LastIndexOf("/")); string[] array = text2.Substring(1).Split(new char[1] { '/' }); string text3 = ""; for (int i = 0; i < array.Length; i++) { if (!builtPaths.Contains(text3 + ":" + array[i])) { LoggingPlugin.LogDebug("Building Path " + text3 + "/" + array[i]); DeepMenusPlugin._self.CreateSubMenu(text3, DeepMenusPlugin._self.MakeSubMenuEntry(array[i], (text3 != "") ? LoadSpriteOrDefault("org.lordashes.plugins.d20." + array[i] + ".png", fallbackSprite) : null, false, true), (Func)(() => true)); builtPaths.Add(text3 + ":" + array[i]); } text3 = text3 + "/" + array[i]; } LoggingPlugin.LogDebug("Building Leaf " + text3 + "/" + text); DeepMenusPlugin._self.CreateSubMenuItem(text3, DeepMenusPlugin._self.MakeItemEntry(text, (Action)delegate(string item, string m) { ((MonoBehaviour)_self).StartCoroutine(InitiateMenuAction(item, m)); }, LoadSpriteOrDefault("org.lordashes.plugins.d20." + text + ".png", fallbackSprite), false, true), (Func)(() => true)); } } public static CreatureBoardAsset[] GetCreatureAssets(CreatureGuid[] cids) { //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_0024: Unknown result type (might be due to invalid IL or missing references) List list = new List(); if (cids != null) { foreach (CreatureGuid val in cids) { CreatureBoardAsset val2 = null; CreaturePresenter.TryGetAsset(val, ref val2); if ((Object)(object)val2 != (Object)null) { list.Add(val2); } } } return list.ToArray(); } public static string[] GetCreatureNames(CreatureGuid[] cids) { return (from a in GetCreatureAssets(cids) select a.Name).ToArray(); } private static CreatureBoardAsset[] GetAffectedCreatures() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) List list = new List(); FieldInfo fieldInfo = (from i in typeof(CreatureBoardAsset).GetRuntimeFields() where i.Name == "_selected" select i).FirstOrDefault(); if (fieldInfo != null) { foreach (CreatureBoardAsset item2 in (IEnumerable)CreaturePresenter.GetTempReadOnlyViewOfAllCreatureAssets()/*cast due to .constrained prefix*/) { if ((Object)(object)item2 != (Object)null && (bool)fieldInfo.GetValue(item2)) { list.Add(item2); } } } if (!list.Any((CreatureBoardAsset c) => c.CreatureId == new CreatureGuid(RadialUIPlugin.GetLastRadialTargetCreature()))) { CreatureBoardAsset val = null; CreaturePresenter.TryGetAsset(new CreatureGuid(RadialUIPlugin.GetLastRadialTargetCreature()), ref val); if ((Object)(object)val != (Object)null) { list.Add(val); } } CreatureBoardAsset item = default(CreatureBoardAsset); CreaturePresenter.TryGetAsset(LocalClient.SelectedCreatureId, ref item); if (list.Contains(item)) { list.Remove(item); } return list.ToArray(); } public static IEnumerator InitiateMenuAction(string item, string menu, CreatureBoardAsset[] instigators = null, CreatureBoardAsset[] targets = null) { LoggingPlugin.LogDebug("---[ACTION SELECTED: " + item + " (" + menu + ")]---"); ((MonoBehaviour)_self).StartCoroutine(PatchCallCameraClick.preventClickCollection(1f)); yield return (object)new WaitForSeconds(0.1f); CreatureGuid[] selectedAssetsIds = null; LocalClient.TryGetLassoedCreatureIds(ref selectedAssetsIds); if (selectedAssetsIds == null) { instigators = GetCreatureAssets(selectedAssetsIds); } if (selectedAssetsIds == null) { instigators = GetCreatureAssets((CreatureGuid[])(object)new CreatureGuid[1] { LocalClient.SelectedCreatureId }); } if (targets == null) { targets = GetAffectedCreatures(); } LoggingPlugin.LogDebug("Instagators (" + instigators.Length + ") = " + string.Join(",", instigators.Select((CreatureBoardAsset a) => a.Name))); LoggingPlugin.LogDebug("Targets (" + targets.Length + ") = " + string.Join(",", targets.Select((CreatureBoardAsset a) => a.Name))); menu = menu.Substring(1); menu = menu.Substring(menu.IndexOf("/")); CreatureBoardAsset[] array = instigators; foreach (CreatureBoardAsset instigator in array) { LoggingPlugin.LogDebug("Current Pass Instinagtor: " + instigator.Name); LoggingPlugin.LogDebug("Current Targets (" + targets.Length + ") = " + string.Join(",", targets.Select((CreatureBoardAsset a) => a.Name))); if (!((Object)(object)instigator != (Object)null)) { continue; } CharacterSpecs stack = new CharacterSpecs(); CharacterSpecs sheet = _self.characters.FindFirst(DiceRoller.StripTrailingInteger(instigator.Name)); string action = sheet.FindFirstExtraValue("menu==\"" + menu + "/" + item + "\"", "type"); LoggingPlugin.LogDebug("Action: " + ((action != null) ? action : "Null")); if (action == null || action.Trim() == "") { action = "skill"; } Spec spec = sheet.specs.Where((Spec s) => s.menu == menu + "/" + item).FirstOrDefault(); if (spec == null) { continue; } LoggingPlugin.LogTrace("Getting Publicity"); string publicityStr = spec.Extra("message"); string text = publicityStr; string text2 = text; Scripts.MessagePublicity publicity = ((text2 == "private") ? Scripts.MessagePublicity.privateMessage : ((text2 == "semiprivate") ? Scripts.MessagePublicity.semiPrivateMessage : Scripts.MessagePublicity.publicMessage)); switch (action) { case "info": case "skill": case "attack": case "save": case "spell": { LoggingPlugin.LogDebug("Found Spec: " + (spec != null)); string opposed = spec.Extra("opposed"); LoggingPlugin.LogDebug("Found Opposed: " + (opposed != null)); LoggingPlugin.LogDebug("Expected Targets: " + ((spec.Extra("targets") != null) ? int.Parse(spec.Extra("targets")) : 0)); if (opposed != null && opposed != "" && new CreatureGuid(RadialUIPlugin.GetLastRadialTargetCreature()) != LocalClient.SelectedCreatureId) { LoggingPlugin.LogDebug("Processing " + instigator.Name + "'s " + item + " (" + action + ") As Opposed Skill With Selected Target."); CreatureBoardAsset targetAsset = null; CreaturePresenter.TryGetAsset(new CreatureGuid(RadialUIPlugin.GetLastRadialTargetCreature()), ref targetAsset); yield return Scripts.ProcessSequence(stack, (action == "attack" || action == "spell") ? CharactersSpecs.CheckType.Attack : CharactersSpecs.CheckType.Opposed, spec, instigator, (CreatureBoardAsset[])(object)new CreatureBoardAsset[1] { targetAsset }, publicity); } else if (opposed != null && opposed != "") { LoggingPlugin.LogDebug("Processing " + instigator.Name + "'s " + item + " (" + action + ") As Opposed Skill. Collecting Targets."); TargetsCollection obj = new TargetsCollection { targetsCollectingSpecType = action, targetsCollectingSpec = spec, targetsCollectingInstigator = instigator, targetsCollectingPublicity = publicity }; string t = spec.Extra("targets"); obj.targetsCollecting = int.Parse((t != null) ? t : int.MaxValue.ToString()); targetsCollection = obj; } else { LoggingPlugin.LogDebug("Processing " + instigator.Name + "'s " + item + " (" + action + ") As Skill"); yield return Scripts.ProcessSequence(stack, CharactersSpecs.CheckType.Regular, spec, instigator, null, publicity); } break; } case "effect": spec = sheet.specs.Where((Spec s) => s.menu == menu + "/" + item).FirstOrDefault(); LoggingPlugin.LogDebug("Found Spec: " + (spec != null)); LoggingPlugin.LogDebug("Processing " + instigator.Name + "'s " + item + " (" + action + ") As Damage"); yield return Scripts.ProcessEffectOnTarget(stack, CharactersSpecs.CheckType.Effect, spec, instigator, (targets.Length != 0) ? targets[0] : instigator, "Hit", publicity, spec.name); break; case "damage": spec = sheet.specs.Where((Spec s) => s.menu == menu + "/" + item).FirstOrDefault(); LoggingPlugin.LogDebug("Found Spec: " + (spec != null)); LoggingPlugin.LogDebug("Processing " + instigator.Name + "'s " + item + " (" + action + ") As Damage"); yield return Scripts.ProcessDamageOnTarget(stack, CharactersSpecs.CheckType.Damage, spec, instigator, (targets.Length != 0) ? targets[0] : instigator, "Hit", publicity, spec.name); break; case "heal": spec = sheet.specs.Where((Spec s) => s.menu == menu + "/" + item).FirstOrDefault(); LoggingPlugin.LogDebug("Found Spec: " + (spec != null)); LoggingPlugin.LogDebug("Processing " + instigator.Name + "'s " + item + " (" + action + ") As Heal"); yield return Scripts.ProcessHealOnTarget(stack, CharactersSpecs.CheckType.Heal, spec, instigator, (targets.Length != 0) ? targets[0] : instigator, publicity); break; default: spec = sheet.specs.Where((Spec s) => s.menu == menu + "/" + item).FirstOrDefault(); LoggingPlugin.LogDebug("Found Spec: " + (spec != null)); LoggingPlugin.LogDebug("Processing " + instigator.Name + "'s " + item + " (" + action + ") As Generic"); yield return Scripts.ProcessGeneric(stack, CharactersSpecs.CheckType.Generic, spec, instigator, (targets.Length != 0) ? targets[0] : instigator, publicity); break; } } LoggingPlugin.LogDebug("Action Processing Completed"); } } public static class DiceRoller { public class RollResult { public string name { get; set; } public string formula { get; set; } public string formulaResolved { get; set; } public string formulaDice { get; set; } public int total { get; set; } public int[] dice { get; set; } } public enum RollingMethod { randomGeneratorDice = 1, talespireDice } public static class RollSimplifier { public class RollParseResult { public string RollString { get; set; } public List AllDiceValues { get; set; } public List Totals { get; set; } } public static RollParseResult ParseRollResults(RollResults rollResults) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: 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_0032: Unknown result type (might be due to invalid IL or missing references) List allDiceValues = new List(); List list = new List(); List list2 = new List(); RollGroup[] array = rollResults.ResultsGroups.ToArray(); foreach (RollGroup val in array) { var (item, item2) = ProcessOperand(val.Result, allDiceValues); list.Add(item); list2.Add(item2); } return new RollParseResult { RollString = string.Join(" / ", list), AllDiceValues = allDiceValues, Totals = list2 }; } private static (string str, int total) ProcessOperand(RollOperand operand, List allDiceValues) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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_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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I8 //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) RollOperation val2 = default(RollOperation); RollResult val3 = default(RollResult); RollValue val4 = default(RollValue); Which val = ((RollOperand)(ref operand)).Get(ref val2, ref val3, ref val4); Which val5 = val; Which val6 = val5; if ((long)val6 <= 2L) { switch ((uint)val6) { case 0u: { RollOperand[] array2 = val2.Operands.ToArray(); if (array2.Length != 2) { throw new InvalidOperationException("Unexpected number of operands in RollOperation (expected 2)."); } (string, int) tuple = ProcessOperand(array2[0], allDiceValues); (string, int) tuple2 = ProcessOperand(array2[1], allDiceValues); int item2 = (((int)val2.Operator == 0) ? (tuple.Item2 + tuple2.Item2) : (tuple.Item2 - tuple2.Item2)); string text = (((int)val2.Operator == 0) ? "+" : "-"); return (str: tuple.Item1 + text + tuple2.Item1, total: item2); } case 1u: { int num = ((IEnumerable)val3.Results).Count(); string registeredName = ((DieKind)(ref val3.Kind)).RegisteredName; short[] array = val3.Results.ToArray(); allDiceValues.AddRange(array); int item = array.Sum((short r) => r); return (str: $"{num}{registeredName}", total: item); } case 2u: { short value = val4.Value; return (str: value.ToString(), total: val4.Value); } } } throw new InvalidOperationException("Unknown RollOperand type encountered."); } } private static readonly Random _rng = new Random(); private static readonly Regex TokenRegex = new Regex("(\\d+[dD]\\d+[aAdD]?|\\d+|[+\\-*/])", RegexOptions.Compiled); private static readonly Regex DiceRegex = new Regex("(\\d+)[dD](\\d+)([aAdD]?)", RegexOptions.Compiled); private static readonly string TermPattern = "(?:\\d+[dD]\\d+[aAdD]?|\\d+|[A-Za-z_][A-Za-z0-9_]*)"; public static TaskCompletionSource pendingRoll; public static async Task Roll(Characters.CharacterSpecs instigatorSheet, string rollName, string expression, RollingMethod? rollingStyle = null) { RollingMethod useRollingStyle = (rollingStyle.HasValue ? rollingStyle.Value : rollingStyleOffensive); RollResult rollResult = new RollResult { name = rollName, formula = expression, formulaResolved = SimplifyExpression(ComputeConstants(instigatorSheet.Resolve(expression))) }; RollResult rawRollResult; switch (useRollingStyle) { case RollingMethod.randomGeneratorDice: rawRollResult = RollRandomGeneratorDice(instigatorSheet, rollResult.formulaResolved); break; case RollingMethod.talespireDice: { string justDice = ExtractTalespireDiceRolls(rollResult.formulaResolved); rawRollResult = ((!(justDice.Trim() != "")) ? new RollResult { dice = new int[0] } : (await RollTalespireDice(instigatorSheet, rollName, justDice.Trim()))); break; } default: return null; } rollResult.formulaDice = ResolveDiceValues(rollResult.formulaResolved, rawRollResult.dice); rollResult.total = ResolveTotal(rollResult.formulaResolved, rawRollResult.dice); rollResult.dice = rawRollResult.dice; LoggingPlugin.LogDebug("Dice Roller: Name: " + rollResult.name); LoggingPlugin.LogDebug("Dice Roller: Formula: " + rollResult.formula); LoggingPlugin.LogDebug("Dice Roller: Roll: " + rollResult.formulaResolved); LoggingPlugin.LogDebug("Dice Roller: Dice: " + rollResult.formulaDice); LoggingPlugin.LogDebug("Dice Roller: Total: " + rollResult.total); return rollResult; } public static Task RollTalespireDice(Characters.CharacterSpecs instigatorSheet, string rollName, string expression) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) LoggingPlugin.LogDebug("Using Talespire Dice"); if (pendingRoll != null) { throw new InvalidOperationException("A virtual dice roll is already in progress."); } LoggingPlugin.LogDebug("Setting Dice Expecting Flag"); pendingRoll = new TaskCompletionSource(); string text = "talespire://dice/" + rollName + ":" + expression; LoggingPlugin.LogDebug("Requesting: " + text); LocalConnectionManager.ProcessTaleSpireUrl(text); return pendingRoll.Task; } public static RollResult RollRandomGeneratorDice(Characters.CharacterSpecs instigatorSheet, string expression) { LoggingPlugin.LogDebug("Using Random Generator Dice"); if (string.IsNullOrWhiteSpace(expression)) { throw new ArgumentException("Expression cannot be empty."); } List diceRolls = new List(); string expression2 = DiceRegex.Replace(expression, delegate(Match match) { int count = int.Parse(match.Groups[1].Value); int sides = int.Parse(match.Groups[2].Value); char c = ((match.Groups[3].Value.Length > 0) ? char.ToUpperInvariant(match.Groups[3].Value[0]) : '\0'); if (c == '\0') { return RollOnce().ToString(); } int val = RollOnce(); int val2 = RollOnce(); return ((c == 'A') ? Math.Max(val, val2) : Math.Min(val, val2)).ToString(); }); int total = EvaluateIntegerExpression(expression2); return new RollResult { formula = expression, formulaResolved = SimplifyExpression(ComputeConstants(instigatorSheet.Resolve(expression))), formulaDice = SimplifyExpression(ResolveDiceValues(ComputeConstants(instigatorSheet.Resolve(expression)), diceRolls.ToArray())), total = total, dice = diceRolls.ToArray() }; int RollOnce() { int num = 0; for (int i = 0; i < P_0.count; i++) { int num2 = _rng.Next(1, P_0.sides + 1); diceRolls.Add(num2); num += num2; } return num; } } public static string ResolveDiceValues(string formula, int[] dice) { if (string.IsNullOrWhiteSpace(formula)) { throw new ArgumentException("Expression cannot be empty."); } if (dice == null) { throw new ArgumentNullException("dice"); } int num = 0; StringBuilder stringBuilder = new StringBuilder(); int num2 = 0; foreach (Match item in DiceRegex.Matches(formula)) { stringBuilder.Append(formula.Substring(num2, item.Index - num2)); int num3 = int.Parse(item.Groups[1].Value); char c = ((item.Groups[3].Value.Length > 0) ? char.ToUpperInvariant(item.Groups[3].Value[0]) : '\0'); int num4 = ((c != 'A' && c != 'D') ? 1 : 2); int num5 = num3 * num4; if (num + num5 > dice.Length) { throw new ArgumentException("Not enough dice values provided."); } if (num4 > 1) { stringBuilder.Append("("); for (int i = 0; i < num5; i++) { if (i > 0) { stringBuilder.Append(","); } stringBuilder.Append(dice[num + i]); } stringBuilder.Append(")"); stringBuilder.Append(c); } else if (num3 == 1) { stringBuilder.Append(dice[num]); } else { stringBuilder.Append("("); for (int j = 0; j < num3; j++) { if (j > 0) { stringBuilder.Append(","); } stringBuilder.Append(dice[num + j]); } stringBuilder.Append(")"); } num += num5; num2 = item.Index + item.Length; } stringBuilder.Append(formula.Substring(num2)); return stringBuilder.ToString(); } public static int ResolveTotal(string formula, int[] dice) { int num = 0; StringBuilder stringBuilder = new StringBuilder(); foreach (Match item in TokenRegex.Matches(formula)) { string value = item.Value; Match match2 = DiceRegex.Match(value); if (match2.Success) { int num2 = int.Parse(match2.Groups[1].Value); char c = ((match2.Groups[3].Length > 0) ? char.ToUpperInvariant(match2.Groups[3].Value[0]) : '\0'); if (c == '\0') { if (num + num2 > dice.Length) { throw new ArgumentException("Not enough dice values supplied."); } int num3 = 0; for (int i = 0; i < num2; i++) { num3 += dice[num++]; } stringBuilder.Append(num3); continue; } int num4 = num2 * 2; if (num + num4 > dice.Length) { throw new ArgumentException("Not enough dice values supplied."); } int num5 = 0; for (int j = 0; j < num2; j++) { num5 += dice[num++]; } int num6 = 0; for (int k = 0; k < num2; k++) { num6 += dice[num++]; } int value2 = ((c == 'A') ? Math.Max(num5, num6) : Math.Min(num5, num6)); stringBuilder.Append(value2); } else { stringBuilder.Append(value); } } object value3 = new DataTable().Compute(stringBuilder.ToString(), null); return Convert.ToInt32(value3); } public static int ResolveMaxTotal(string expression) { if (string.IsNullOrWhiteSpace(expression)) { throw new ArgumentException("Expression cannot be empty."); } List list = new List(); foreach (Match item2 in DiceRegex.Matches(expression)) { int num = int.Parse(item2.Groups[1].Value); int num2 = int.Parse(item2.Groups[2].Value); string value = item2.Groups[3].Value; int item = num * num2; list.Add(item); if (!string.IsNullOrEmpty(value)) { list.Add(item); } } return ResolveTotal(expression, list.ToArray()); } public static string ExtractTalespireDiceRolls(string expression) { Regex regex = new Regex("(?[+\\-*/]?)\\s*(?\\d+[dD]\\d+)(?[aAdD]?)|\\d+", RegexOptions.Compiled); StringBuilder stringBuilder = new StringBuilder(); bool flag = true; foreach (Match item in regex.Matches(expression)) { if (!item.Groups["dice"].Success) { continue; } string value = item.Groups["op"].Value; string value2 = item.Groups["dice"].Value; string value3 = item.Groups["rep"].Value; int num = ((value3.Length <= 0) ? 1 : 2); for (int i = 0; i < num; i++) { if (!flag) { stringBuilder.Append((value.Length > 0) ? value : "+"); } stringBuilder.Append(value2); flag = false; } } return stringBuilder.ToString().Replace("-", "+").Replace("/", "+") .Replace("*", "+"); } public static string SimplifyExpression(string formula) { if (string.IsNullOrWhiteSpace(formula)) { return formula; } formula = Regex.Replace(formula, "(? targetsCollected = new List(); } [HarmonyPatch(typeof(UI_DiceRollGroup), "DisplayGroup")] public static class PatchSetResult { public static bool Prefix(UI_DiceRollGroup __instance, RollGroup resultsGroup, bool isFirst, TMP_Text ____headerText, FactoryInspectorSetup ____operatorFactory, RectTransform ____content, int ____contentGridWrapWidth, GridLayoutGroup ____contentGrid, RectTransform ____transform) { //IL_0021: 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_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) if (DiceRoller.pendingRoll != null) { string text = (isFirst ? "Rolled" : "And"); string name = resultsGroup.Name; if (!string.IsNullOrWhiteSpace(name)) { text = text + " " + name; } ____headerText.text = text; int num = (int)(from m in typeof(UI_DiceRollGroup).GetRuntimeMethods() where m.Name == "DisplayOperand" select m).FirstOrDefault().Invoke(__instance, new object[2] { resultsGroup.Result, true }); UI_DiceOperator val = ____operatorFactory.Hire(true); ((Component)val).transform.SetAsLastSibling(); if (((Transform)____content).childCount <= ____contentGridWrapWidth) { ____contentGrid.constraint = (Constraint)2; ____contentGrid.constraintCount = 1; RectTransformExtensions.SetHeight(____transform, 25f + ____contentGrid.cellSize.y); return false; } ____contentGrid.constraint = (Constraint)1; ____contentGrid.constraintCount = ____contentGridWrapWidth; float num2 = math.ceil((float)((Transform)____content).childCount / (float)____contentGrid.constraintCount) * (____contentGrid.cellSize.y + ____contentGrid.spacing.y); RectTransformExtensions.SetHeight(____transform, 25f + num2); return false; } return true; } } [HarmonyPatch(typeof(GUIManager), "PlayMode_OnStateChange")] public static class GUIManagerPlayModeOnStateChange { public static bool Prefix(State obj) { //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) if (((object)obj).ToString() == "PlayMode+TurnBased") { LoggingPlugin.LogDebug("Initiative Mode Selected"); AssetDataPlugin.SendInfo("org.lordashes.plugins.d20", "action:initiative"); ChatManager.SendChatMessageToBoard("[Roll Initiative!]\r\nCollecting Initiatives", LocalPlayer.Id.Value, (float3?)null, false); initiativeOrder.Clear(); } return true; } } [HarmonyPatch(typeof(UI_InitativeManager), "OpenEdit")] public class InitiativeManagerApplyEditPatch { private static void Postfix(bool value) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) LoggingPlugin.LogDebug("Applying Stored Initiatives"); InitiativeManager.SetEditQueue(initiativeOrder.Values.ToArray()); LoggingPlugin.LogDebug("Ending Initiative Collection"); if (collectingInitiative && summarizeInitiative) { string text = ""; foreach (KeyValuePair item in initiativeOrder) { CreatureBoardAsset val = null; CreaturePresenter.TryGetAsset(item.Value.CreatureGuid, ref val); if ((Object)(object)val != (Object)null) { text = text + item.Key + ": " + val.Name + "\r\n"; } } if (text != "") { text = text.Substring(0, text.Length - 2); ChatManager.SendChatMessageToBoard("[Initiative]\r\n" + text, LocalPlayer.Id.Value, (float3?)null, false); } } collectingInitiative = false; } } [HarmonyPatch(typeof(UIChatMessageManager), "AddChatMessage")] public static class PatchAddMessage { public static bool Prefix(string creatureName, Texture2D icon, string chatMessage, IChatFocusable focus = null) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) LoggingPlugin.LogDebug("Initiative Collection: " + collectingInitiative); if (collectingInitiative) { LoggingPlugin.LogDebug("Initiative Collection: Active"); LoggingPlugin.LogDebug("Initiative Collection: Caption: " + ((creatureName != null) ? creatureName : "None")); LoggingPlugin.LogDebug("Initiative Collection: Icon: " + (((Object)(object)icon != (Object)null && ((Object)icon).name != null) ? ((Object)icon).name : "None")); LoggingPlugin.LogDebug("Initiative Collection: Message: " + ((chatMessage != null) ? chatMessage.Replace("\r\n", "|") : "None")); CreatureBoardAsset val = null; CreaturePresenter.TryGetAsset(LocalClient.SelectedCreatureId, ref val); if (LocalClient.IsPartyGm) { LoggingPlugin.LogDebug("Initiative Collection: GM Client"); try { string text = chatMessage.Substring(chatMessage.LastIndexOf(" ") + 1); LoggingPlugin.LogDebug("Initiative Collection: Adding Roll: " + text + " For " + creatureName); initiativeOrder.Add(int.Parse(text), new QueueElement((ElementType)0, LocalClient.SelectedCreatureId)); } catch { SystemMessage.DisplayInfoText("D20 Plugin:\r\nRoll may be set to value instead of skill.", 2.5f, 0f, (Action)null); } } else { LoggingPlugin.LogDebug("Initiative Collection: Non-GM Client"); } } return true; } } [HarmonyPatch(typeof(UIChatMessageManager), "AddDiceResultMessage")] public static class PatchAddDiceResultMessage { public static bool Prefix(RollResults diceResult, ResultsOrigin origin, ClientGuid sender, bool hidden, IChatFocusable focus = null) { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) if (DiceRoller.pendingRoll != null) { DiceRoller.RollSimplifier.RollParseResult rollParseResult = DiceRoller.RollSimplifier.ParseRollResults(diceResult); int num = rollParseResult.Totals.Sum(); DiceRoller.RollResult result = new DiceRoller.RollResult { total = rollParseResult.Totals.Sum(), dice = ((IEnumerable)rollParseResult.AllDiceValues).Select((Func)((short s) => s)).ToArray() }; DiceRoller.pendingRoll?.TrySetResult(result); DiceRoller.pendingRoll = null; DiceRollManager val = Object.FindObjectOfType(); if ((Object)(object)val != (Object)null) { val.RemoveRoll(diceResult.RollId); } return false; } return true; } } [HarmonyPatch(typeof(BoardTool), "CallCameraClick")] public static class PatchCallCameraClick { public static bool preventClickCalls; public unsafe static bool Prefix(CameraClickEvent click) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) if (!preventClickCalls && targetsCollection.targetsCollecting > 0 && !((object)BoardToolManager.CurrentTool).ToString().Contains("RulerBoardTool")) { string[] obj = new string[6] { "Generic Click: User Click At ", null, null, null, null, null }; Vector2 position = click.position; obj[1] = ((object)(*(Vector2*)(&position))/*cast due to .constrained prefix*/).ToString(); obj[2] = " With Tool "; obj[3] = ((object)BoardToolManager.CurrentTool).ToString(); obj[4] = " And Collecting "; obj[5] = collecting; LoggingPlugin.LogDebug(string.Concat(obj)); preventClickCalls = true; ((MonoBehaviour)_self).StartCoroutine(preventClickCollection(1f)); CreatureBoardAsset val = null; float3 val2 = default(float3); PixelPickingManager.TryGetPickedCreature(ref val2, ref val); if ((Object)(object)val != (Object)null) { LoggingPlugin.LogDebug("Generic Click: Added Asset " + val.Name + " At " + ((object)(*(float3*)(&val2))/*cast due to .constrained prefix*/).ToString()); targetsCollection.targetsCollected.Add(val); if (targetsCollection.targetsCollected.Count >= targetsCollection.targetsCollecting) { ProcessSelection(); } } if (Input.GetMouseButtonDown(2)) { ProcessSelection(); } } return true; } public static void ProcessSelection() { Characters.CharacterSpecs stack = new Characters.CharacterSpecs(); ((MonoBehaviour)_self).StartCoroutine(preventClickCollection(2f)); ((MonoBehaviour)_self).StartCoroutine(Scripts.ProcessSequence(stack, (targetsCollection.targetsCollectingSpecType == "attack" || targetsCollection.targetsCollectingSpecType == "spell") ? Characters.CharactersSpecs.CheckType.Attack : Characters.CharactersSpecs.CheckType.Opposed, targetsCollection.targetsCollectingSpec, targetsCollection.targetsCollectingInstigator, targetsCollection.targetsCollected.ToArray(), targetsCollection.targetsCollectingPublicity)); ((MonoBehaviour)_self).StartCoroutine(holdAndClear(2f)); } public static IEnumerator holdAndClear(float delay) { yield return (object)new WaitForSeconds(delay); targetsCollection.targetsCollecting = 0; targetsCollection.targetsCollected.Clear(); } public static IEnumerator preventClickCollection(float delay) { preventClickCalls = true; yield return (object)new WaitForSeconds(delay); preventClickCalls = false; } } [HarmonyPatch(typeof(Ruler), "SetNewMode")] public static class PatchSetNewMode { public static bool Prefix(int newModeIndex, bool forceRecreate) { if (targetsCollection.targetsCollecting > 0) { LoggingPlugin.LogDebug("D20 Plugin: Ruler Mode Change To Type " + rulerTypes[newModeIndex] + " (" + newModeIndex + ")"); collecting = rulerTypes[newModeIndex]; } return true; } } [HarmonyPatch(typeof(Ruler), "OnClick")] public static class PatchOnClick { public static bool Prefix(Ruler __instance, int buttonId) { return true; } public unsafe static void Postfix(Ruler __instance, int buttonId) { //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_0553: Unknown result type (might be due to invalid IL or missing references) //IL_0558: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03e0: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_040b: Unknown result type (might be due to invalid IL or missing references) //IL_0410: Unknown result type (might be due to invalid IL or missing references) //IL_057a: Unknown result type (might be due to invalid IL or missing references) //IL_057f: Unknown result type (might be due to invalid IL or missing references) //IL_048c: Unknown result type (might be due to invalid IL or missing references) //IL_0491: Unknown result type (might be due to invalid IL or missing references) //IL_05c8: Unknown result type (might be due to invalid IL or missing references) //IL_05cd: Unknown result type (might be due to invalid IL or missing references) //IL_05f3: Unknown result type (might be due to invalid IL or missing references) //IL_05f8: Unknown result type (might be due to invalid IL or missing references) //IL_0615: Unknown result type (might be due to invalid IL or missing references) //IL_061c: Unknown result type (might be due to invalid IL or missing references) //IL_062d: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_0673: Unknown result type (might be due to invalid IL or missing references) //IL_0678: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) LoggingPlugin.LogDebug("Ruler " + ((Object)__instance).name + " Click: Button " + buttonId + ", Targets: " + targetsCollection.targetsCollecting + ", Collecting: " + PluginD20.collecting); if (PatchCallCameraClick.preventClickCalls || targetsCollection.targetsCollecting <= 0) { return; } List list = new List(); if (!(PluginD20.collecting != "")) { return; } List list2 = new List(); GameObject val = GameObject.Find(((Object)__instance).name); Vector3 val2; if ((Object)(object)val != (Object)null) { foreach (Transform item in ExtensionMethods.Children(val.transform)) { LoggingPlugin.LogDebug("Ruler " + ((Object)__instance).name + ": Found Child: " + ((Object)item).name + " While Searching For " + PluginD20.collecting + "Indicator(Clone)"); if (!(((Object)item).name == PluginD20.collecting + "Indicator(Clone)")) { continue; } LoggingPlugin.LogDebug("Ruler " + ((Object)__instance).name + ": Found " + ((Object)item).name + " With " + ExtensionMethods.Children(((Component)item).transform).Count() + " Children"); foreach (Transform item2 in ExtensionMethods.Children(((Component)item).transform)) { string collecting = PluginD20.collecting; val2 = item2.position; LoggingPlugin.LogDebug(collecting + " Point: " + ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString()); if (item2.position != Vector3.zero) { list.Add(item2.position); } } } } LoggingPlugin.LogDebug("Ruler " + ((Object)__instance).name + ": Collecting: " + PluginD20.collecting + ", Points: " + list.Count); string collecting2 = PluginD20.collecting; string text = collecting2; if (!(text == "Sphere")) { if (!(text == "Box") || list.Count != 2) { return; } LoggingPlugin.LogDebug("Ruler " + ((Object)__instance).name + ": Applying Selection Based On " + PluginD20.collecting); foreach (CreatureBoardAsset item3 in (IEnumerable)CreaturePresenter.GetTempReadOnlyViewOfAllCreatureAssets()/*cast due to .constrained prefix*/) { if (item3.CreatureId != LocalClient.SelectedCreatureId) { string[] obj = new string[8] { "Ruler ", ((Object)__instance).name, ": Asset ", item3.Name, " (", ((object)item3.CreatureId/*cast due to .constrained prefix*/).ToString(), ") At ", null }; val2 = ((Component)((MovableBoardAsset)item3).Rotator).transform.position; obj[7] = ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString(); LoggingPlugin.LogDebug(string.Concat(obj)); if (IsPointInsideBox(list[0], list[1], ((Component)((MovableBoardAsset)item3).Rotator).transform.position)) { LoggingPlugin.LogDebug("Ruler " + ((Object)__instance).name + ": Asset " + item3.Name + " (" + ((object)item3.CreatureId/*cast due to .constrained prefix*/).ToString() + ") Is Selected"); targetsCollection.targetsCollected.Add(item3); } } } PatchCallCameraClick.preventClickCalls = true; ((MonoBehaviour)_self).StartCoroutine(PatchCallCameraClick.preventClickCollection(1f)); ((MonoBehaviour)_self).StartCoroutine(closeRuler()); PluginD20.collecting = ""; } else { if (list.Count != 2) { return; } LoggingPlugin.LogDebug("Ruler " + ((Object)__instance).name + ": Applying Selection Based On " + PluginD20.collecting); val2 = list[0] - list[1]; float magnitude = ((Vector3)(ref val2)).magnitude; LoggingPlugin.LogDebug("Radius = " + magnitude); foreach (CreatureBoardAsset item4 in (IEnumerable)CreaturePresenter.GetTempReadOnlyViewOfAllCreatureAssets()/*cast due to .constrained prefix*/) { if (item4.CreatureId != LocalClient.SelectedCreatureId) { val2 = ((Component)((MovableBoardAsset)item4).Rotator).transform.position - list[0]; float magnitude2 = ((Vector3)(ref val2)).magnitude; string[] obj2 = new string[11] { "Ruler ", ((Object)__instance).name, ": Asset ", item4.Name, " (", ((object)item4.CreatureId/*cast due to .constrained prefix*/).ToString(), ") At ", null, null, null, null }; val2 = ((Component)((MovableBoardAsset)item4).Rotator).transform.position; obj2[7] = ((object)(*(Vector3*)(&val2))/*cast due to .constrained prefix*/).ToString(); obj2[8] = " Is "; obj2[9] = magnitude2.ToString(); obj2[10] = " away"; LoggingPlugin.LogDebug(string.Concat(obj2)); if (magnitude2 <= magnitude) { LoggingPlugin.LogDebug("Ruler " + ((Object)__instance).name + ": Asset " + item4.Name + " (" + ((object)item4.CreatureId/*cast due to .constrained prefix*/).ToString() + ") Is Selected"); targetsCollection.targetsCollected.Add(item4); } } } PatchCallCameraClick.preventClickCalls = true; ((MonoBehaviour)_self).StartCoroutine(PatchCallCameraClick.preventClickCollection(1f)); ((MonoBehaviour)_self).StartCoroutine(closeRuler()); PluginD20.collecting = ""; } } public static IEnumerator closeRuler() { UI_Rulers.EnableRulers(false); yield return (object)new WaitForSeconds(0.1f); UI_Rulers.EnableRulers(true); yield return (object)new WaitForSeconds(0.1f); UI_Rulers.EnableRulers(false); } public static bool IsPointInsideBox(Vector3 cornerA, Vector3 cornerB, Vector3 point) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Min(cornerA.x, cornerB.x); float num2 = Mathf.Max(cornerA.x, cornerB.x); float num3 = Mathf.Min(cornerA.y, cornerB.y); float num4 = Mathf.Max(cornerA.y, cornerB.y); float num5 = Mathf.Min(cornerA.z, cornerB.z); float num6 = Mathf.Max(cornerA.z, cornerB.z); return point.x >= num && point.x <= num2 && point.y >= num3 && point.y <= num4 && point.z >= num5 && point.z <= num6; } } public class RemoteQuerySpecs { public string name { get; set; } public string item { get; set; } } public class RemoteQueryRequest { public Guid id { get; set; } public RemoteQuerySpecs query { get; set; } public string requestor { get; set; } public string[] targetClients { get; set; } public string[] targetPlayers { get; set; } } public class RemoteQueryResponse { public Guid id { get; set; } public string response { get; set; } public string requestor { get; set; } public string client { get; set; } public string player { get; set; } } public static class RemoteQuery { public static string hold; public static TaskCompletionSource reactionToken; public static Task> MakeRequest(RemoteQuerySpecs query, TaskCompletionSource> token, string[] specificClients = null, string[] specificPlayers = null, int expectedResult = 0, int expectedResultsTimeout = 0) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) Guid guid = System.Guid.NewGuid(); results.Add(guid, new List()); string text = JsonConvert.SerializeObject((object)new RemoteQueryRequest { id = guid, query = query, requestor = ((object)LocalClient.Id/*cast due to .constrained prefix*/).ToString(), targetClients = specificClients, targetPlayers = specificPlayers }); LoggingPlugin.LogDebug("Sending Remote Request:" + text); AssetDataPlugin.SendInfo("org.lordashes.plugins.d20", text); if (expectedResult == 0 && expectedResultsTimeout > 0) { ((MonoBehaviour)_self).StartCoroutine(ProcessResultsAfterSetDelay(guid, token, expectedResultsTimeout)); } else if (expectedResult == 0 && expectedResultsTimeout == 0) { ((MonoBehaviour)_self).StartCoroutine(ProcessResultsAfterSetResponses(guid, token, expectedResult, 10)); } else { ((MonoBehaviour)_self).StartCoroutine(ProcessResultsAfterSetResponses(guid, token, expectedResult, expectedResultsTimeout)); } return token.Task; } public static async void ReceiveRemoteQueryResult(DatumChange datum) { LoggingPlugin.LogDebug("Remote Message:" + JsonConvert.SerializeObject((object)datum)); ChangeAction action = datum.action; ChangeAction val = action; ChangeAction val2 = val; if ((int)val2 != 0 && val2 - 2 > 1) { return; } LoggingPlugin.LogDebug("Remote Message: Checking Message Type"); if (datum.value.ToString().Contains("message:")) { SystemMessage.DisplayInfoText("D20 Plugin:\r\n" + datum.value.ToString().Substring("message:".Length), 2.5f, 0f, (Action)null); } else if (datum.value.ToString().Contains("action:")) { string action2 = datum.value.ToString().Substring("action:".Length); string text = action2; if (text == "initiative") { LoggingPlugin.LogDebug("Remote Message: Starting Initiative Collection"); collectingInitiative = true; } } else if (datum.value.ToString().Contains("query")) { LoggingPlugin.LogDebug("Remote Message: Is A Request"); RemoteQueryRequest request = JsonConvert.DeserializeObject(datum.value.ToString()); if ((request.targetClients != null && !request.targetClients.Contains(((object)LocalClient.Id/*cast due to .constrained prefix*/).ToString())) || (request.targetPlayers != null && !request.targetPlayers.Contains(((object)LocalPlayer.Id/*cast due to .constrained prefix*/).ToString()))) { return; } LoggingPlugin.LogDebug("Remote Message: Seeking Sheets Matching " + request.query.name); Characters.CharacterSpecs[] queryResults = _self.characters.Find(DiceRoller.StripTrailingInteger(request.query.name)); LoggingPlugin.LogDebug("Remote Message: Found " + ((queryResults == null) ? "0" : queryResults.Length.ToString()) + " Sheets"); bool foundMatch = false; if (queryResults == null || queryResults.Length == 0) { return; } Characters.CharacterSpecs[] array = queryResults; foreach (Characters.CharacterSpecs sheet in array) { LoggingPlugin.LogDebug("Remote Message: Opposed Options " + request.query.item); string msg = ""; string opposedOption = request.query.item; if (opposedOption.StartsWith("damage:")) { if (queryResults[0].FindFirstValue("Reaction") == "1") { LoggingPlugin.LogDebug("Delaying Response Until Opposing User Click Continue"); hold = "Damage Reaction"; await WaitForReaction(); } LoggingPlugin.LogDebug("Remote Message: Looking For Damage Adjustments"); string matchKeword = opposedOption.Substring("damage:".Length); LoggingPlugin.LogDebug("Remote Message: Looking For '" + matchKeword + "' Damage Adjustments"); Characters.Spec immunitiesSpec = sheet.specs.Where((Characters.Spec e) => e.name == "Immunities").FirstOrDefault(); Characters.Spec resistancesSpec = sheet.specs.Where((Characters.Spec e) => e.name == "Resistances").FirstOrDefault(); Characters.Spec reductionsSpec = sheet.specs.Where((Characters.Spec e) => e.name == "Reductions").FirstOrDefault(); Characters.Spec vulnerabilitiesSpec = sheet.specs.Where((Characters.Spec e) => e.name == "Vulnerabilities").FirstOrDefault(); string immunities = ((immunitiesSpec != null) ? sheet.Resolve(immunitiesSpec.formula) : ""); string resistances = ((resistancesSpec != null) ? sheet.Resolve(resistancesSpec.formula) : ""); string reductions = ((reductionsSpec != null) ? sheet.Resolve(reductionsSpec.formula) : ""); string vulnerabilities = ((vulnerabilitiesSpec != null) ? sheet.Resolve(vulnerabilitiesSpec.formula) : ""); LoggingPlugin.LogDebug("Remote Message: Collected Possible Damage Adjustments"); LoggingPlugin.LogDebug("Remote Message: Immunities = " + immunities); LoggingPlugin.LogDebug("Remote Message: Resistances = " + resistances); LoggingPlugin.LogDebug("Remote Message: Reductions = " + reductions); LoggingPlugin.LogDebug("Remote Message: Vulnerabilities = " + vulnerabilities); if (immunities != null && (immunities.Contains(matchKeword) || immunities.Contains("*"))) { msg = msg + opposedOption + "=Immunity,"; } else if (resistances != null && (resistances.Contains(matchKeword) || resistances.Contains("*"))) { msg = msg + opposedOption + "=Resistance,"; } else if (reductions == null || (!reductions.Contains(matchKeword) && !resistances.Contains("*"))) { msg = ((vulnerabilities == null || (!vulnerabilities.Contains(matchKeword) && !vulnerabilities.Contains("*"))) ? (msg + opposedOption + "=Regular,") : (msg + opposedOption + "=Vulnerability,")); } else { string amount = reductions.Substring(reductions.IndexOf(matchKeword)); amount = amount.Substring(amount.IndexOf("(") + 1); amount = amount.Substring(0, amount.IndexOf(")")); msg = msg + opposedOption + "=" + amount + ","; } } else { int bestScore = 0; string bestOptionName = ""; Characters.Spec bestOption = null; string[] array2 = opposedOption.Split(new char[1] { ',' }); foreach (string opposedOptionItem in array2) { if (queryResults[0].FindFirstValue("Reaction") == "1") { LoggingPlugin.LogDebug("Delaying Response Until Opposing User Click Continue"); hold = "Defense Reaction"; await WaitForReaction(); } LoggingPlugin.LogDebug("Remote Message: Trying To Find " + opposedOption); Characters.Spec seekResult = sheet.specs.Where((Characters.Spec e) => e.name == opposedOption).FirstOrDefault(); if (seekResult != null) { LoggingPlugin.LogDebug("Remote Message: Found " + seekResult.name + " (" + seekResult.formula + ")"); int score = DiceRoller.ResolveMaxTotal(sheet.Resolve(seekResult.formula)); if (score > bestScore) { bestScore = score; bestOptionName = opposedOptionItem; bestOption = seekResult; } } } CreatureBoardAsset target = null; try { target = ((IEnumerable)(object)CreaturePresenter.GetTempReadOnlyViewOfAllCreatureAssets()).Where((CreatureBoardAsset cba) => cba.Name == request.query.name).FirstOrDefault(); } catch { } DiceRoller.RollResult rollResult = await DiceRoller.Roll(sheet, bestOptionName, bestOption.formula, rollingStyleDefensive); Scripts.ProcessExtensions(Scripts.ExtensionType.targetSkillResult, null, target, null, sheet, null, bestOptionName, null, rollResult, delegate(DiceRoller.RollResult r) { rollResult = r; }); msg = msg + JsonConvert.SerializeObject((object)rollResult) + ","; } if (msg != "") { if (msg.IndexOf("=") < 0) { msg = "[" + msg.Substring(0, msg.Length - 1) + "]"; } foundMatch = true; if (msg.EndsWith(",")) { msg = msg.Substring(0, msg.Length - 1); } LoggingPlugin.LogDebug("Remote Message: Sending Result To Requestor " + request.requestor.ToString() + " Message '" + msg + "'"); RemoteQueryResponse response = new RemoteQueryResponse { id = request.id, requestor = request.requestor.ToString(), response = msg, client = ((object)LocalClient.Id/*cast due to .constrained prefix*/).ToString(), player = ((object)LocalPlayer.Id/*cast due to .constrained prefix*/).ToString() }; AssetDataPlugin.SendInfo("org.lordashes.plugins.d20", JsonConvert.SerializeObject((object)response)); } } if (!foundMatch) { SystemMessage.DisplayInfoText("Characte Sheet For " + request.query.name + " Is Missing " + request.query.item, 2.5f, 0f, (Action)null); } } else { LoggingPlugin.LogDebug("Remote Message: Is A Response"); RemoteQueryResponse result = JsonConvert.DeserializeObject(datum.value.ToString()); LoggingPlugin.LogDebug("Remote Message: Message Destined For Requestor " + result.requestor.ToString()); LoggingPlugin.LogDebug("Remote Message: Check: " + result.requestor + "=" + ((object)LocalClient.Id/*cast due to .constrained prefix*/).ToString() + ", Expecting Id=" + results.ContainsKey(result.id)); if (result.requestor == ((object)LocalClient.Id/*cast due to .constrained prefix*/).ToString() && results.ContainsKey(result.id)) { LoggingPlugin.LogDebug("Remote Message: Adding Response To Results List (" + result.response + ")"); results[result.id].Add(result); LoggingPlugin.LogDebug("Remote Message: Collected " + results[result.id].Count() + " Responses"); } } } public static async Task WaitForReaction() { try { reactionToken = new TaskCompletionSource(); await reactionToken.Task; LoggingPlugin.LogDebug("Reaction " + hold + " finished"); } catch (OperationCanceledException) { LoggingPlugin.LogDebug("Reaction " + hold + " was canceled"); } catch (Exception ex2) { Exception ex3 = ex2; Debug.LogException(ex3); } } public static IEnumerator ProcessResultsAfterSetDelay(Guid id, TaskCompletionSource> token, float delay) { LoggingPlugin.LogDebug("Wait: Waiting For Responses: Started Wait For Timeout Of " + delay); yield return (object)new WaitForSeconds(delay); LoggingPlugin.LogDebug("Wait: Triggering Set Delay Callback With " + results[id].Count + " results"); List returnResponse = results[id]; results.Remove(id); LoggingPlugin.LogDebug("Wait: Results Removed From Queue. Posting Results (Token: " + ((token == null) ? "Null" : "Ready") + ")"); token?.TrySetResult(returnResponse); token = null; } public static IEnumerator ProcessResultsAfterSetResponses(Guid id, TaskCompletionSource> token, int expectedResult, int delay) { if (delay == 0) { delay = int.MaxValue; } LoggingPlugin.LogDebug("Wait: Waiting For Responses: Started Wait For " + expectedResult + " Responses With Timeout Of " + delay); for (ulong i = 0uL; i < (ulong)((long)delay * 2L); i++) { if (results[id].Count >= expectedResult) { break; } yield return (object)new WaitForSeconds(0.5f); } LoggingPlugin.LogDebug("Wait: Triggering Set Responses Callback With " + results[id].Count + " results"); List returnResponse = results[id]; results.Remove(id); LoggingPlugin.LogDebug("Wait: Results Removed From Queue. Posting Results (Token: " + ((token == null) ? "Null" : "Ready") + ")"); token?.TrySetResult(returnResponse); token = null; } } public static class Scripts { public class Script { public string use { get; set; } public string gm { get; set; } public string instigator { get; set; } public string target { get; set; } public string others { get; set; } public string instigator_speech { get; set; } public string target_speech { get; set; } } public enum ExtensionType { instigatorSkillResult = 1, targetSkillResult, damageResult } public class ToggleCallaback { public ToggleRequired toggleOnWho { get; set; } public string toggleName { get; set; } public Func> callback { get; set; } } public enum ToggleRequired { instigator, target } public enum MessagePublicity { publicMessage, semiPrivateMessage, privateMessage } public static List