using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BTD_Mod_Helper; using BTD_Mod_Helper.Api; using BTD_Mod_Helper.Api.Components; using BTD_Mod_Helper.Api.Display; using BTD_Mod_Helper.Api.Helpers; using BTD_Mod_Helper.Api.Towers; using BTD_Mod_Helper.Api.UI; using BTD_Mod_Helper.Extensions; using ChaosMonkey.Btd6; using ChaosMonkey.Core; using Il2Cpp; using Il2CppAssets.Scripts.Models; using Il2CppAssets.Scripts.Models.Entities; using Il2CppAssets.Scripts.Models.GenericBehaviors; using Il2CppAssets.Scripts.Models.TowerSets; using Il2CppAssets.Scripts.Models.Towers; using Il2CppAssets.Scripts.Models.Towers.Behaviors; using Il2CppAssets.Scripts.Models.Towers.Behaviors.Attack; using Il2CppAssets.Scripts.Models.Towers.Filters; using Il2CppAssets.Scripts.Models.Towers.Projectiles; using Il2CppAssets.Scripts.Models.Towers.Projectiles.Behaviors; using Il2CppAssets.Scripts.Models.Towers.Weapons; using Il2CppAssets.Scripts.Simulation.Display; using Il2CppAssets.Scripts.Simulation.Objects; using Il2CppAssets.Scripts.Simulation.Towers; using Il2CppAssets.Scripts.Unity.Display; using Il2CppAssets.Scripts.Unity.UI_New.InGame; using Il2CppAssets.Scripts.Unity.UI_New.InGame.TowerSelectionMenu; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppTMPro; using MelonLoader; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: MelonInfo(typeof(ChaosMonkeyMod), "Chaos Monkey", "1.0.0", "Lauri", null)] [assembly: MelonGame("Ninja Kiwi", "BloonsTD6")] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("ChaosMonkey")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ChaosMonkey")] [assembly: AssemblyTitle("ChaosMonkey")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [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 ChaosMonkey.Btd6 { public sealed class ChaosDeveloperWindow : ModWindow { private const int ItemsPerPage = 10; private const string PanelTexture = "ChaosGachaVerticalPanel"; private const string TextFieldTexture = "ChaosTextField"; private readonly Dictionary slotTexts = new Dictionary(); private readonly List itemTexts = new List(); private EquipmentSlot selectedSlot; private int itemPage; private ModHelperText? selectedSlotText; private ModHelperText? statusText; private ModHelperText? pageText; private string status = "WÄHLE EINEN SLOT UND DANACH EIN TEST-ITEM."; public override int DefaultWidth => 1280; public override int DefaultHeight => 1440; public override bool AllowMultiple => false; public override bool AllowResizing => false; public override Info WindowInfo { get { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) Info result = default(Info); ((Info)(ref result))..ctor(((ModContent)this).Name); ((Info)(ref result)).set_Width((float)((ModWindow)this).DefaultWidth); ((Info)(ref result)).set_Height((float)((ModWindow)this).DefaultHeight); ((Info)(ref result)).set_Anchor(new Vector2(0.5f, 0.5f)); ((Info)(ref result)).set_Pivot(new Vector2(0.5f, 0.5f)); ((Info)(ref result)).set_Position(Vector2.zero); return result; } } public override void ModifyWindow(ModHelperWindow window) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) ((ModHelperComponent)window.content).AddImage(new Info("DeveloperPanel", 0f, 0f, 1150f, 1320f), ModContent.GetSpriteReference("ChaosGachaVerticalPanel").guidRef); AddTextField(window, "DeveloperHeader", 0f, 572f, 880f, 68f, "CHAOS MONKEY • DEVELOPER LOADOUT", 31f); AddTextField(window, "DeveloperWarning", 0f, 497f, 880f, 52f, "TEST-MODUS • KEINE ROLLS, PITYS ODER ACHIEVEMENTS", 22f); selectedSlotText = AddTextField(window, "DeveloperSelectedSlot", 195f, 414f, 600f, 50f, BuildSelectedSlotText(), 23f); float num = 352f; EquipmentSlot[] values = Enum.GetValues(); foreach (EquipmentSlot slot in values) { AddSlotButton(window, slot, num); num -= 114f; } for (int j = 0; j < 10; j++) { AddItemButton(window, j, 352f - (float)j * 84f); } AddPageButton(window, "DeveloperPreviousPage", -90f, -475f, "PREVIOUS PAGE", delegate { ChangePage(-1); }); pageText = AddTextField(window, "DeveloperPage", 245f, -475f, 300f, 46f, BuildPageText(), 19f); AddPageButton(window, "DeveloperNextPage", 580f, -475f, "NEXT PAGE", delegate { ChangePage(1); }); statusText = AddTextField(window, "DeveloperStatus", 0f, -540f, 930f, 62f, status, 20f); ((Graphic)GameObjectExt.AddButton(((Component)window.content).gameObject, new Info("DeveloperClose", 0f, -612f, 560f, 62f), "F8 • SCHLIESSEN", (Action)delegate { window.Close(); }).Image).color = new Color(1f, 1f, 1f, 0f); } public override void OnUpdate(ModHelperWindow window) { if (!ChaosMonkeyMod.IsDeveloperModeAvailable || !ChaosMonkeyMod.Session.IsChaosMonkeyPresent) { window.Close(); return; } ModHelperText? obj = selectedSlotText; if (obj != null) { obj.SetText(BuildSelectedSlotText()); } ModHelperText? obj2 = statusText; if (obj2 != null) { obj2.SetText(status); } ModHelperText? obj3 = pageText; if (obj3 != null) { obj3.SetText(BuildPageText()); } if (Input.GetKeyDown((KeyCode)280) || Input.GetKeyDown((KeyCode)276)) { ChangePage(-1); } if (Input.GetKeyDown((KeyCode)281) || Input.GetKeyDown((KeyCode)275)) { ChangePage(1); } foreach (var (slot, val2) in slotTexts) { val2.SetText(BuildSlotText(slot)); } IReadOnlyList developerItems = ChaosMonkeyMod.Session.GetDeveloperItems(selectedSlot); int num = itemPage * 10; for (int i = 0; i < itemTexts.Count; i++) { int num2 = num + i; itemTexts[i].SetText((num2 < developerItems.Count) ? BuildItemText(developerItems[num2]) : string.Empty); } } public override void OnClose(ModHelperWindow window) { slotTexts.Clear(); itemTexts.Clear(); selectedSlotText = null; statusText = null; pageText = null; itemPage = 0; } private void AddSlotButton(ModHelperWindow window, EquipmentSlot slot, float y) { //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) slotTexts[slot] = AddTextField(window, $"DeveloperSlot{slot}", -302f, y, 390f, 88f, BuildSlotText(slot), 22f); ((Graphic)GameObjectExt.AddButton(((Component)window.content).gameObject, new Info($"DeveloperSlotSelect{slot}", -302f, y, 408f, 94f), string.Empty, (Action)delegate { selectedSlot = slot; itemPage = 0; status = GetSlotName(slot) + " AUSGEWÄHLT • RECHTS EIN ITEM ANKLICKEN."; }).Image).color = new Color(1f, 1f, 1f, 0f); } private void AddItemButton(ModHelperWindow window, int index, float y) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) ModHelperText item = AddTextField(window, $"DeveloperItem{index}", 245f, y, 650f, 70f, string.Empty, 22f); itemTexts.Add(item); ((Graphic)GameObjectExt.AddButton(((Component)window.content).gameObject, new Info($"DeveloperItemSelect{index}", 245f, y, 674f, 76f), string.Empty, (Action)delegate { ApplyItem(index); }).Image).color = new Color(1f, 1f, 1f, 0f); } private static void AddPageButton(ModHelperWindow window, string name, float x, float y, string label, Action action) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) AddTextField(window, name + "Label", x, y, 200f, 46f, label, 17f); ((Graphic)GameObjectExt.AddButton(((Component)window.content).gameObject, new Info(name, x, y, 206f, 52f), string.Empty, action).Image).color = new Color(1f, 1f, 1f, 0f); } private void ApplyItem(int index) { IReadOnlyList developerItems = ChaosMonkeyMod.Session.GetDeveloperItems(selectedSlot); int num = itemPage * 10 + index; if (num >= developerItems.Count) { return; } try { ItemDefinition itemDefinition = developerItems[num]; ChaosMonkeyMod.EquipDeveloperItem(itemDefinition.Id); status = "TEST-ITEM GESETZT: " + itemDefinition.DisplayName.ToUpperInvariant() + " • KEINE ACHIEVEMENTS."; } catch (InvalidOperationException ex) { status = ex.Message.ToUpperInvariant(); } } private void ChangePage(int direction) { int pageCount = GetPageCount(); itemPage = Mathf.Clamp(itemPage + direction, 0, pageCount - 1); } private int GetPageCount() { int count = ChaosMonkeyMod.Session.GetDeveloperItems(selectedSlot).Count; return Math.Max(1, (count + 10 - 1) / 10); } private string BuildPageText() { return $"SEITE {itemPage + 1} / {GetPageCount()}"; } private string BuildSelectedSlotText() { EvolutionState evolutionState = ChaosMonkeyMod.Session.Match?.Evolution; string text = ((evolutionState != null && evolutionState.IsInProgress) ? "EVOLUTION LÄUFT • SLOTS GESPERRT" : ((evolutionState != null && evolutionState.IsComplete) ? "EVOLUTION ABGESCHLOSSEN • SLOTS GESPERRT" : "TEST-AUSRÜSTUNG")); return "AUSGEWÄHLT: " + GetSlotName(selectedSlot) + " • " + text; } private string BuildSlotText(EquipmentSlot slot) { ItemDefinition itemDefinition = ChaosMonkeyMod.Session.Match?.GetItem(slot); string text = ((slot == selectedSlot) ? " • AUSGEWÄHLT" : string.Empty); return GetSlotName(slot) + text + "\n" + (((object)itemDefinition == null) ? "LEER" : itemDefinition.DisplayName.ToUpperInvariant()); } private static string BuildItemText(ItemDefinition item) { return $"{item.Rarity.ToString().ToUpperInvariant()} • {item.DisplayName.ToUpperInvariant()}\n{item.Summary.ToUpperInvariant()}"; } private static ModHelperText AddTextField(ModHelperWindow window, string name, float x, float y, float width, float height, string text, float fontSize) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) ((ModHelperComponent)window.content).AddImage(new Info(name + "Panel", x, y, width, height), ModContent.GetSpriteReference("ChaosTextField").guidRef); ModHelperText obj = ((ModHelperComponent)window.content).AddText(new Info(name, x, y, width - 28f, height - 8f), text, fontSize, (TextAlignmentOptions)514); obj.EnableAutoSizing(fontSize, 16f); return obj; } private static string GetSlotName(EquipmentSlot slot) { return slot switch { EquipmentSlot.Weapon => "WAFFE", EquipmentSlot.Ammo => "MUNITION", EquipmentSlot.Body => "KÖRPER", EquipmentSlot.Head => "KOPF", EquipmentSlot.Trait => "TRAIT", EquipmentSlot.Ability => "FÄHIGKEIT", _ => slot.ToString().ToUpperInvariant(), }; } } public sealed class ChaosMonkeyGodlyEvolutionDisplay : ModTowerCustomDisplay { public override string AssetBundleName => "chaosmonkeyevolutions"; public override string PrefabName => "ChaosMonkeyGodlyEvolution"; public override bool LoadAsync => false; public override bool UseForTower(params int[] tiers) { return false; } public override void ModifyDisplayNode(UnityDisplayNode node) { ChaosEvolutionDisplayMaterials.Apply(node, secret: false); } } public sealed class ChaosMonkeySecretEvolutionDisplay : ModTowerCustomDisplay { public override string AssetBundleName => "chaosmonkeyevolutions"; public override string PrefabName => "ChaosMonkeySecretEvolution"; public override bool LoadAsync => false; public override bool UseForTower(params int[] tiers) { return false; } public override void ModifyDisplayNode(UnityDisplayNode node) { ChaosEvolutionDisplayMaterials.Apply(node, secret: true); } } internal static class ChaosEvolutionDisplayMaterials { private static Material? safeTowerMaterial; internal static void CaptureTowerMaterial(UnityDisplayNode? node) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown if ((Object)(object)safeTowerMaterial != (Object)null || (Object)(object)node == (Object)null) { return; } foreach (Renderer componentsInChild in ((Component)node).GetComponentsInChildren(true)) { if (!((Object)(object)componentsInChild.sharedMaterial == (Object)null)) { safeTowerMaterial = new Material(componentsInChild.sharedMaterial); break; } } } internal static void Apply(UnityDisplayNode node, bool secret) { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: 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_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) Sprite sprite = ModContent.GetSprite(secret ? "ChaosMonkeySecretEvolution" : "ChaosMonkeyGodlyEvolution", 100f); Texture2D val = ((sprite == null) ? null : sprite.texture); foreach (Renderer componentsInChild in ((Component)node).GetComponentsInChildren(true)) { bool flag = ((Object)((Component)componentsInChild).gameObject).name.StartsWith("SolidMonkey_", StringComparison.Ordinal); Material val2 = CreateSafeMaterial(flag ? null : val); if (!((Object)(object)val2 == (Object)null)) { if (val2.HasProperty("_Cull")) { val2.SetInt("_Cull", 0); } Color val3 = ((!flag && val != null) ? Color.white : GetPartColor(((Object)((Component)componentsInChild).gameObject).name, secret)); if (val2.HasProperty("_Color")) { val2.SetColor("_Color", val3); } if (val2.HasProperty("_BaseColor")) { val2.SetColor("_BaseColor", val3); } if (val2.HasProperty("_EmissionColor")) { val2.SetColor("_EmissionColor", val3 * 0.2f); } componentsInChild.material = val2; componentsInChild.enabled = true; } } } private static Material? CreateSafeMaterial(Texture2D? conceptTexture) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown Shader val = Shader.Find("Sprites/Default"); if ((Object)(object)val != (Object)null) { Material val2 = new Material(val); if (val2.HasProperty("_MainTex")) { val2.SetTexture("_MainTex", (Texture)(object)(conceptTexture ?? Texture2D.whiteTexture)); } return val2; } if ((Object)(object)safeTowerMaterial != (Object)null) { return new Material(safeTowerMaterial); } Shader val3 = Shader.Find("Unlit/Color"); if (!((Object)(object)val3 == (Object)null)) { return new Material(val3); } return null; } private static Color GetPartColor(string name, bool secret) { //IL_0072: 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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_013b: 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_0199: Unknown result type (might be due to invalid IL or missing references) //IL_017f: 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_01b6: Unknown result type (might be due to invalid IL or missing references) int num = name.LastIndexOf("__CM", StringComparison.Ordinal); if (num >= 0 && name.Length >= num + "__CM".Length + 8) { string text = name.Substring(num + "__CM".Length, 8); Color result = default(Color); if (ColorUtility.TryParseHtmlString("#" + text, ref result)) { return result; } } if (name.Contains("Eye")) { return new Color(0.1f, 0.94f, 1f, 1f); } if (name.Contains("Crystal") || name.Contains("Core") || name.Contains("Gem") || name.Contains("Planet")) { if (!secret) { return new Color(0.95f, 0.18f, 1f, 1f); } return new Color(0.86f, 0.07f, 1f, 1f); } if (name.Contains("Crown") || name.Contains("Halo") || name.Contains("Staff")) { if (!secret) { return new Color(1f, 0.72f, 0.1f, 1f); } return new Color(0.22f, 0.04f, 0.48f, 1f); } if (name.Contains("Robe") || name.Contains("Cape") || name.Contains("Hood")) { if (!secret) { return new Color(0.31f, 0.06f, 0.62f, 1f); } return new Color(0.035f, 0.008f, 0.1f, 1f); } if (!secret) { return new Color(0.47f, 0.2f, 0.09f, 1f); } return new Color(0.055f, 0.012f, 0.14f, 1f); } } internal static class ChaosItemArtwork { private static readonly Dictionary sprites = new Dictionary(StringComparer.Ordinal); internal static Sprite GetSprite(ItemDefinition item) { if (sprites.TryGetValue(item.Id, out Sprite value)) { return value; } Sprite sprite = ModContent.GetSprite($"ChaosItemIcon{item.Slot}{item.Rarity}", 100f); sprites[item.Id] = sprite; return sprite; } internal static Color GetTint(ItemDefinition item) { //IL_0026: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) if (item.Tags.Contains("Fire")) { return new Color(1f, 0.58f, 0.38f, 1f); } if (item.Tags.Contains("Frost")) { return new Color(0.48f, 0.88f, 1f, 1f); } if (item.Tags.Contains("Poison")) { return new Color(0.55f, 1f, 0.42f, 1f); } if (item.Tags.Contains("Lightning")) { return new Color(0.72f, 0.86f, 1f, 1f); } if (item.Tags.Contains("Gravity") || item.Tags.Contains("Void")) { return new Color(0.72f, 0.45f, 1f, 1f); } if (item.Tags.Contains("Time")) { return new Color(1f, 0.78f, 0.35f, 1f); } if (item.Tags.Contains("Reality")) { return new Color(1f, 0.42f, 0.78f, 1f); } if (item.Rarity == Rarity.Secret) { return new Color(0.72f, 0.42f, 1f, 1f); } return Color.white; } } internal sealed record ChaosItemDetails(string Stats, string Effect, string Synergy); internal static class ChaosItemDetailsCatalog { public static ChaosItemDetails Get(ItemDefinition item) { return item.Id switch { "rusty-dart" => Detail("1 DMG • 3 PIERCE • 0.90s", "Simple rapid dart attack. A dependable opening weapon.", "Pairs with basic or burning ammunition."), "chaos-slingshot" => Detail("2 DMG • 2 PIERCE • 1.00s", "Launches heavy chaotic pebbles for reliable early damage.", "Chaos Ammo effects can add splinters."), "twin-darts" => Detail("2 DARTS • 1 DMG • 0.95s", "Fires a matched pair of darts with each attack.", "Benefits especially from split and burning ammunition."), "scrap-blaster" => Detail("1 DMG • 6 PIERCE • 1.10s", "Sprays a broad piece of scrap through grouped Bloons.", "Pierce bonuses turn scrap into crowd control."), "chaos-needle" => Detail("1 DMG • 2 PIERCE • 0.35s", "Fires extremely quickly at a single target.", "Proc ammunition has many chances to trigger."), "pebble-launcher" => Detail("3 DMG • 2 PIERCE • 1.45s", "Throws slow, heavy pebbles with strong direct impact.", "Gravity effects keep targets in the impact line."), "broken-wand" => Detail("1 DMG • BONUS HIT 15%", "A cracked wand occasionally fires an additional magic bolt.", "Luck improves the bonus-hit chance."), "toy-cannon" => Detail("4 DMG • 3 PIERCE • 1.70s", "A deceptively strong toy shell fires very slowly.", "Explosion ammunition increases its impact area."), "double-chaos-blaster" => Detail("2 BOLTS • 2 DMG • 0.80s", "Releases two chaotic bolts at once.", "Chaos Affinity strengthens both bolts."), "spiked-launcher" => Detail("4 DMG • 8 PIERCE • 1.10s", "Fires a heavy spike that tears through dense groups.", "Piercing Plasma pushes the pierce even higher."), "mini-cannon" => Detail("3 DMG • SMALL BLAST • 1.25s", "Fires compact shells that damage nearby Bloons on impact.", "Gravity Ammo clusters targets for the blast."), "ricochet-gun" => Detail("2 DMG • 4 PIERCE • 1 BOUNCE", "Every shot rebounds once into a nearby Bloon.", "Extra bounces with Lightning Ammo."), "poison-dart-gun" => Detail("1 DMG • POISON 4s • 0.70s", "Poisons hit Bloons, dealing damage over time.", "Toxic effects combine with Poison Ammo."), "rapid-chaos-bow" => Detail("2 DMG • 3 PIERCE • 0.45s", "Rapidly fires chaotic arrows down the track.", "Chaos Split Ammo creates a fragment storm."), "plasma-rifle" => Detail("3 DMG • 10 PIERCE • 0.65s", "Fires hot plasma rounds that cut through crowds.", "Plasma shots benefit strongly from Body bonuses."), "gravity-cannon" => Detail("3 DMG • PULL • 1.15s", "Impacts create a small gravity pull around the target.", "Gravity Ammo extends the pull duration."), "chain-lightning-staff" => Detail("2 DMG • 4 TARGETS • 0.80s", "A lightning strike jumps between nearby targets.", "Storm equipment adds chain targets."), "frost-launcher" => Detail("2 DMG • CHILL 30% • 1.05s", "Chilling shells slow struck Bloons for a short time.", "Freezing effects strengthen the chill."), "meteor-cannon" => Detail("5 DMG • METEOR 12% • 1.30s", "Occasionally calls a meteor onto the current target area.", "Meteor Ammo raises the impact frequency."), "void-blaster" => Detail("4 DMG • 12 PIERCE • 0.75s", "Void bolts pierce dense groups and leave a brief tear.", "Void Mask and Void Ammo amplify rifts."), "soul-reaper" => Detail("3 DMG • EXECUTE BONUS • 0.85s", "Deals increasing bonus damage to already weakened Bloons.", "Soul effects mark targets for the Reaper."), "black-hole-launcher" => Detail("5 DMG • 6 PIERCE • 1.20s", "Impacts briefly pull Bloons toward a miniature singularity.", "Gravity equipment extends the pull."), "chaos-accelerator" => Detail("2–8 DMG • COMBO • 0.55s", "Repeated hits on the same target grow stronger until the combo breaks.", "Focused keeps the combo on tough targets."), "reality-rifle" => Detail("7 DMG • 18 PIERCE • 0.90s", "Some shots bypass ordinary Bloon physics and properties.", "Reality Ammo makes bypasses more reliable."), "dragon-cannon" => Detail("8 DMG/s • BEAM • 18 PIERCE", "Channels a continuous dragonfire beam through Bloons.", "Dragonfire Ammo adds a spreading flame wave."), "time-breaker" => Detail("6 DMG • TIME SLOW 20% • 1.00s", "Hits sometimes briefly slow the target; the effect is weaker against MOABs.", "Time Ammo and Time Crown extend the slow."), "void-destroyer" => Detail("14 DMG • RIFT • 1.40s", "Each impact opens a damaging void rift on the track.", "Rift Ammo makes each rift wider."), "judgement-cannon" => Detail("12 DMG • +MOAB DMG • 1.90s", "Fires an immense slow shell that deals more damage to powerful targets.", "Focused and World Eater raise its MOAB damage."), "eternal-chaos" => Detail("CHAOS PROC • 0.55s", "Each attack randomly triggers lightning, gravity, fire, time or void.", "Full Godly Harmony stabilizes every chaos proc."), "genesis-weapon" => Detail("ADAPTIVE ATTACK • 0.60s", "Changes its projectile form to match the equipped Ammo and build.", "Its strongest form is discovered through mixed-element loadouts."), "basic-ammo" => Detail("STANDARD ROUND", "Reliable ammunition with no additional effect.", "A clean base for any weapon."), "burning-ammo" => Detail("+1 BURN DMG • 3s", "Hits ignite Bloons and deal damage over time.", "Dragon Cannon turns burns into wider flames."), "lightning-ammo" => Detail("+2 CHAIN TARGETS", "A hit releases a short chain of lightning.", "Storm Helmet and Staff increase the chain."), "gravity-ammo" => Detail("PULL • 1.0s", "Hits drag nearby Bloons toward the impact point.", "Black Hole Launcher strengthens the pull."), "void-ammo" => Detail("VOID TEAR • 12%", "Some impacts leave a brief damaging void tear.", "Void Blaster improves tear duration."), "chaos-split-ammo" => Detail("3 SPLINTERS • 25%", "A quarter of hits split into three chaotic fragments.", "Chaos Affinity increases split reliability."), "dragonfire-ammo" => Detail("FIRE WAVE • 4s", "Direct hits emit a short dragonfire wave.", "Dragon Cannon doubles the visual fire trail."), "rift-ammo" => Detail("AREA RIFT • 2.5s", "Creates a larger area-damage rift after impact.", "Void and Reality loadouts expand the rift."), "law-of-chaos-ammo" => Detail("ADAPTIVE PROC • EVERY HIT", "Adapts a random elemental effect to the equipped weapon.", "Full Godly Harmony lets all elements coexist."), "basic-body" => Detail("+1 DMG • +1 PIERCE", "A small all-round improvement to the Monkey's attacks.", "Useful with every early loadout."), "storm-body" => Detail("STORM PULSE • 5s", "Periodically releases a lightning pulse around the Monkey.", "Storm Helmet gives the pulse more targets."), "gravity-body" => Detail("PULL AURA • 12 RANGE", "A small field slows and draws nearby Bloons together.", "Gravity Ammo makes the aura more forceful."), "chaos-core-body" => Detail("ROTATING BONUS • 4s", "Cycles through small damage, pierce, speed and range bonuses.", "Chaos weapons inherit the active bonus."), "time-lord-body" => Detail("TIME SLOW • 15%", "Nearby Bloons are periodically slowed by warped time.", "Time Crown extends the slow duration."), "world-eater-body" => Detail("+MOAB DMG • STACKING", "Gains additional power while fighting MOAB-class Bloons.", "Focused makes every MOAB stack stronger."), "celestial-core" => Detail("5-SLOT AMPLIFIER", "Empowers the other five equipped slots at once.", "A key component of Godly Harmony."), "singularity-body" => Detail("BLACK HOLE • 18s", "Occasionally forms a compact black hole that pulls and damages Bloons.", "Secret Harmony turns it into a galaxy rift."), "basic-cap" => Detail("FOCUS TARGETING", "Improves target focus for consistent first-target attacks.", "Works with every weapon."), "storm-helmet" => Detail("+2 STORM TARGETS", "Storm and lightning effects can hit more targets.", "Best with Lightning Ammo or the Staff."), "void-mask" => Detail("+20% VOID DURATION", "Void tears and rifts remain active longer.", "Pairs with Void Blaster and Rift Ammo."), "reality-mask" => Detail("PROPERTY BYPASS • 20%", "Some attacks partially ignore Bloon properties.", "Reality Collapse gains extra area damage."), "time-crown" => Detail("+30% TIME EFFECT", "Extends and strengthens all time manipulation.", "Time Stop becomes more reliable."), "crown-of-oblivion" => Detail("OBLIVION MARK • 10%", "Marked Bloons receive amplified void and reality damage.", "Void Destroyer consumes the mark."), "crown-of-infinity" => Detail("GODLY AMPLIFIER", "Raises the effect of every Godly item in the loadout.", "Required for a fully harmonized Godly build."), "quick-learner" => Detail("+12% ATTACK SPEED", "The Monkey attacks faster with every weapon.", "A flexible early-game trait."), "lucky" => Detail("+8% PROC CHANCE", "Slightly improves every chance-based effect.", "Helps chaos, void and critical effects."), "focused" => Detail("+25% MOAB DMG", "Deals more damage to MOAB-class Bloons.", "Excellent with World Eater Body."), "gambler" => Detail("CRIT • 8% ×5", "Rare hits deal massively increased damage.", "Absolute Luck increases crit consistency."), "chaos-affinity" => Detail("+25% CHAOS POWER", "Strengthens random chaos effects and their duration.", "Eternal Chaos becomes much more stable."), "reality-bender" => Detail("RULE SHIFT • 12s", "Periodically changes one active combat rule in your favor.", "Reality Mask reveals the next shift."), "absolute-luck" => Detail("+35% PROC POWER", "Strongly boosts all chance-based effects and random outcomes.", "Godly Harmony shares the luck bonus."), "chaos-blast" => Detail("ABILITY • 20s CD", "Detonates a small chaos blast at the selected location.", "Chaos Affinity adds a random secondary effect."), "lightning-strike" => Detail("ABILITY • 24s CD", "Calls a targeted lightning strike onto the track.", "Storm equipment causes additional jumps."), "gravity-pulse" => Detail("ABILITY • 28s CD", "Pulls nearby Bloons into a compact cluster.", "Gravity Body increases the pulse radius."), "void-rift" => Detail("ABILITY • 34s CD", "Creates a large damaging rift on the track.", "Void Mask extends the rift duration."), "time-stop" => Detail("ABILITY • 42s CD", "Temporarily slows the entire nearby track.", "Time Lord Body increases slow strength."), "reality-collapse" => Detail("ABILITY • 50s CD", "Collapses reality in an area and deals damage over time.", "Reality Mask allows partial property bypass."), "ascendant-chaos" => Detail("ABILITY • 60s CD", "Triggers a coordinated surge of all six Godly effects.", "Full Godly Harmony lowers its cooldown."), "the-unwritten-blade" => Detail("UNWRITTEN RULE • PROPERTY ERASE", "A black blade can remove Camo, Regrow or Fortified from the target.", "Pairs with Reality effects; all six Secrets begin Unknown Resonance."), "event-horizon" => Detail("COLLAPSE • SCALING SINGULARITY", "Creates a singularity at the target; stronger Bloons make stronger collapses.", "Combines with Singularity Core and The Black Halo."), "null-weapon" => Detail("[NULL] • NO VISIBLE SHOT", "It seems to fire nothing until Bloons vanish outside normal damage rules.", "Its hidden interaction is revealed only by other Secret items."), "forbidden-matter" => Detail("CORRUPTION • DETONATION", "Hits add corruption; a fully corrupted Bloon explodes.", "Works especially well with rapid or split weapons."), "yesterday" => Detail("TIME ECHO • REWIND HIT", "A struck Bloon can be returned to an earlier point on the track.", "Pairs with Rewind for the Paradox Secret synergy."), "outside" => Detail("OUTSIDE MAP • PHASE SHOT", "Shots pass obstacles, bypass protected targets and can reappear behind them.", "Reality and Null effects unlock its strangest behaviour."), "observer-body" => Detail("OBSERVATION • ESCALATING MARK", "Bloons remaining in view are marked and take increasingly heavy damage.", "Pairs with The Watching Eye to form The Observer."), "singularity-core" => Detail("GRAVITY • CROWD POWER", "Pulls nearby Bloons inward and becomes stronger as the crowd grows.", "Pairs with The Black Halo for Endless Gravity."), "forgotten-body" => Detail("FORGOTTEN • RECOGNITION LOSS", "Some Bloons lose their normal recognition of the Monkey.", "A Secret-only defensive rule break."), "watching-eye" => Detail("PREDICTION • PERFECT TRACKING", "Predicts movement for exceptionally precise target acquisition.", "Pairs with Observer Body for The Observer."), "crown-of-nothing" => Detail("NOTHING • RULE REMOVAL", "Every 20–30 seconds removes a negative effect and may erase enemy properties.", "Reality effects make property removal more reliable."), "the-black-halo" => Detail("GRAVITY RING • CHARGED WAVE", "Continuously slows and gathers Bloons before releasing a gravity wave.", "Pairs with Singularity Core for Endless Gravity."), "impossible-luck" => Detail("INVISIBLE LUCK CHECK", "Every roll secretly receives a second luck check.", "A Secret effect: it never appears in the public odds table."), "fate-secret" => Detail("FATE COUNTER • EVENT", "A hidden counter grows while the Monkey survives, then triggers a powerful random event.", "Works with Yesterday for the Paradox route."), "existence" => Detail("EXISTENCE • SIX-SLOT BONUS", "Some normal rules cannot affect the Monkey; all six categories receive a small bonus.", "Enhances every completed Secret loadout."), "erase" => Detail("ERASE • LONG COOLDOWN", "After a delay, destroys normal Bloons or deals huge BAD and boss damage.", "Secret Evolution turns it into an ascendant reality tear."), "rewind" => Detail("REWIND • TIME RESET", "Returns Bloons to earlier positions and repeats part of recent damage.", "Pairs with Yesterday for the Paradox Secret synergy."), "unknown-ability" => Detail("??? • UNPREDICTABLE", "After a silent delay, it chooses a massive random Secret effect.", "The full Secret set reveals the Unknown Resonance."), _ => CreateDefault(item), }; } public static ChaosItemDetails Empty(EquipmentSlot slot) { return new ChaosItemDetails($"{ChaosEconomy.SlotRollCosts[slot]} SHARDS • SELECTED ROLL", "Choose " + SlotName(slot) + " and use a Normal Roll to discover its first item.", "Items with matching tags unlock synergy bonuses. The final evolutions remain hidden."); } public static string SlotName(EquipmentSlot slot) { return slot switch { EquipmentSlot.Weapon => "WEAPON", EquipmentSlot.Ammo => "AMMO", EquipmentSlot.Body => "BODY", EquipmentSlot.Head => "HEAD", EquipmentSlot.Trait => "TRAIT", EquipmentSlot.Ability => "ABILITY", _ => slot.ToString().ToUpperInvariant(), }; } private static ChaosItemDetails Detail(string stats, string effect, string synergy) { return new ChaosItemDetails(stats, effect, synergy); } private static ChaosItemDetails CreateDefault(ItemDefinition item) { string[] array = item.Tags.Where((string tag) => !string.Equals(tag, "Secret", StringComparison.OrdinalIgnoreCase)).ToArray(); string text = ((array.Length == 0) ? "GENERAL" : string.Join(" • ", array).ToUpperInvariant()); return Detail($"{item.Rarity.ToString().ToUpperInvariant()} {SlotName(item.Slot)} • {text}", item.Summary, (array.Length == 0) ? "A flexible item with no required pairing." : ("SYNERGY: combines with matching " + text + " equipment.")); } } public sealed class ChaosLuckOddsWindow : ModWindow { private const float TableScale = 1.35f; private const string TextFieldTexture = "ChaosTextField"; private readonly Dictionary oddsLabels = new Dictionary(); private readonly GachaEngine gacha = new GachaEngine(); private ModHelperText? luckText; private ModHelperText? nextLuckText; private ModHelperText? resultText; private string result = "NORMAL ROLLS USE THE DISPLAYED ODDS."; public override int DefaultWidth => 920; public override int DefaultHeight => 480; public override bool AllowMultiple => false; public override bool AllowResizing => false; public override Info WindowInfo { get { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) Info val = default(Info); ((Info)(ref val))..ctor(((ModContent)this).Name); ((Info)(ref val)).set_Width((float)((ModWindow)this).DefaultWidth); ((Info)(ref val)).set_Height((float)((ModWindow)this).DefaultHeight); ((Info)(ref val)).set_Anchor(new Vector2(0.5f, 1f)); ((Info)(ref val)).set_Pivot(new Vector2(0.5f, 1f)); ((Info)(ref val)).set_Position(new Vector2(-270f, -8f)); return val; } } public override void ModifyWindow(ModHelperWindow window) { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) AddField(window, "LuckOddsTitle", 0f, 102f, 560f, 42f, "LUCK & DROP ODDS", 24f); luckText = AddField(window, "CurrentLuck", -174f, 56f, 210f, 40f, BuildLuckText(), 22f); nextLuckText = AddField(window, "NextLuck", 165f, 56f, 290f, 40f, BuildNextLuckText(), 18f); ((Graphic)GameObjectExt.AddButton(((Component)window.content).gameObject, TableInfo("BuyNextLuck", 165f, 56f, 292f, 42f), string.Empty, (Action)PurchaseNextLuck).Image).color = new Color(1f, 1f, 1f, 0f); AddOddsRow(window, Rarity.Common, -172f, 8f); AddOddsRow(window, Rarity.Uncommon, -172f, -36f); AddOddsRow(window, Rarity.Rare, -172f, -80f); AddOddsRow(window, Rarity.Epic, -172f, -124f); AddOddsRow(window, Rarity.Legendary, 172f, 8f); AddOddsRow(window, Rarity.Mythic, 172f, -36f); AddOddsRow(window, Rarity.Godly, 172f, -80f); resultText = AddField(window, "LuckOddsResult", 0f, -178f, 670f, 36f, result, 15f); } public override void OnUpdate(ModHelperWindow window) { ModHelperText? obj = luckText; if (obj != null) { obj.SetText(BuildLuckText()); } ModHelperText? obj2 = nextLuckText; if (obj2 != null) { obj2.SetText(BuildNextLuckText()); } ModHelperText? obj3 = resultText; if (obj3 != null) { obj3.SetText(result); } foreach (var (rarity2, val2) in oddsLabels) { val2.SetText(BuildOddsText(rarity2)); } } public override void OnClose(ModHelperWindow window) { luckText = null; nextLuckText = null; resultText = null; oddsLabels.Clear(); } private void AddOddsRow(ModHelperWindow window, Rarity rarity, float x, float y) { oddsLabels[rarity] = AddField(window, $"Odds{rarity}", x, y, 305f, 34f, BuildOddsText(rarity), 17f); } private void PurchaseNextLuck() { try { int? nextLuck = GetNextLuck(); if (!nextLuck.HasValue) { result = "LUCK IS ALREADY AT THE MAXIMUM ×2048."; return; } ChaosMonkeyMatchState? match = ChaosMonkeyMod.Session.Match; InGame instance = InGame.instance; if (match == null || !ChaosMonkeyMod.Session.IsChaosMonkeyPresent || instance == null) { throw new InvalidOperationException("SELECT AN ACTIVE CHAOS MONKEY FIRST."); } int num = ChaosEconomy.LuckCashCosts[nextLuck.Value]; if (InGameExt.GetCash(instance) < (double)num) { result = $"NOT ENOUGH CASH FOR LUCK ×{nextLuck.Value}."; } else { InGameExt.AddCash(instance, (double)(-num)); ChaosMonkeyMod.Session.PurchaseLuck(nextLuck.Value); result = $"LUCK UPGRADED TO ×{nextLuck.Value}. DROP ODDS UPDATED."; } } catch (InvalidOperationException ex) { result = ex.Message.ToUpperInvariant(); } } private static ModHelperText AddField(ModHelperWindow window, string name, float x, float y, float width, float height, string text, float fontSize) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) ((ModHelperComponent)window.content).AddImage(TableInfo(name + "Panel", x, y, width, height), ModContent.GetSpriteReference("ChaosTextField").guidRef); ModHelperText obj = ((ModHelperComponent)window.content).AddText(TableInfo(name, x, y, width - 18f, height - 5f), text, fontSize * 1.35f, (TextAlignmentOptions)514); obj.EnableAutoSizing(fontSize * 1.35f, 16.2f); return obj; } private static Info TableInfo(string name, float x, float y, float width, float height) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) return new Info(name, x * 1.35f, y * 1.35f, width * 1.35f, height * 1.35f); } private static string BuildLuckText() { ChaosMonkeyMatchState match = ChaosMonkeyMod.Session.Match; if (match != null) { return $"CURRENT LUCK ×{match.PurchasedLuck}"; } return "CURRENT LUCK ×—"; } private static string BuildNextLuckText() { int? nextLuck = GetNextLuck(); if (nextLuck.HasValue) { return $"BUY LUCK ×{nextLuck.Value} • ${ChaosEconomy.LuckCashCosts[nextLuck.Value]:N0}"; } return "LUCK MAXIMUM ×2048"; } private string BuildOddsText(Rarity rarity) { int luckMultiplier = ChaosMonkeyMod.Session.Match?.PurchasedLuck ?? 1; IReadOnlyDictionary displayedOdds = gacha.GetDisplayedOdds(luckMultiplier); return $"{rarity.ToString().ToUpperInvariant()} • {displayedOdds[rarity]:0.000}%"; } private static int? GetNextLuck() { int num = ChaosMonkeyMod.Session.Match?.PurchasedLuck ?? 1; for (int i = 0; i < ChaosEconomy.PurchasableLuck.Count - 1; i++) { if (ChaosEconomy.PurchasableLuck[i] == num) { return ChaosEconomy.PurchasableLuck[i + 1]; } } return null; } } internal static class ChaosMonkeyAppearance { private readonly record struct LayerLayout(string TextureName, Vector3 Position, Vector3 Scale, float Rotation, int SortingOrder); private readonly record struct AnimatedEvolutionPart(Transform Transform, Vector3 BaseScale, bool Pulses); private const string RootName = "ChaosMonkeyLoadoutVisual"; private const float PixelsPerUnit = 420f; private static readonly IReadOnlyDictionary Layouts = new Dictionary { [EquipmentSlot.Weapon] = new LayerLayout("SlotWeaponIcon", new Vector3(0.58f, 0.08f, -0.3f), new Vector3(0.54f, 0.54f, 1f), -12f, 30), [EquipmentSlot.Ammo] = new LayerLayout("SlotAmmoIcon", new Vector3(-0.44f, -0.2f, -0.25f), new Vector3(0.38f, 0.38f, 1f), 16f, 40), [EquipmentSlot.Body] = new LayerLayout("SlotBodyIcon", new Vector3(0f, -0.06f, -0.2f), new Vector3(0.48f, 0.48f, 1f), 0f, 50), [EquipmentSlot.Head] = new LayerLayout("SlotHeadIcon", new Vector3(0f, 0.55f, -0.2f), new Vector3(0.46f, 0.46f, 1f), 0f, 60), [EquipmentSlot.Trait] = new LayerLayout("SlotTraitIcon", new Vector3(-0.62f, 0.42f, -0.35f), new Vector3(0.34f, 0.34f, 1f), 12f, 70), [EquipmentSlot.Ability] = new LayerLayout("SlotAbilityIcon", new Vector3(0f, -0.08f, 0.4f), new Vector3(0.68f, 0.68f, 1f), 0f, 10) }; private static Tower? activeTower; private static UnityDisplayNode? activeDisplayNode; private static SpriteRenderer? pulseRenderer; private static float pulseEndsAt; private static Transform? evolutionRig; private static readonly List evolutionOrbitParts = new List(); private static readonly List evolutionMaterials = new List(); private static bool evolutionUsesMesh; private static bool evolutionUsesTowerDisplay; private static float evolutionOrbitTime; private static float nextEvolutionIntegrityCheckAt; private static EvolutionKind? appliedEvolutionDisplay; internal static void Attach(Tower tower) { activeTower = tower; ChaosMonkeyCombat.Apply(tower); Rebuild(celebrate: false, null); } internal static bool IsAttachedTo(Tower tower) { if (activeTower != null) { return activeTower == tower; } return false; } internal static void RegisterGraphics(IReadOnlyList nodes) { activeDisplayNode = ((IEnumerable)nodes).FirstOrDefault((Func)((UnityDisplayNode node) => (Object)(object)node != (Object)null)); ModHelper.Msg((object)$"Chaos graphics captured: {nodes.Count} node(s), live node: {(Object)(object)activeDisplayNode != (Object)null}."); if (activeTower != null) { Rebuild(celebrate: false, null); } } internal static void RefreshAfterRoll(RollResult result) { if (activeTower != null) { ChaosMonkeyCombat.Apply(activeTower); } Rebuild(celebrate: true, result); } internal static void RefreshAfterDeveloperLoadout() { if (activeTower != null) { ChaosMonkeyCombat.Apply(activeTower); } Rebuild(celebrate: false, null); } internal static void RefreshAfterEvolution() { if (activeTower != null) { ChaosMonkeyCombat.Apply(activeTower); } Rebuild(celebrate: false, null); } internal static void RefreshForSelection(Tower tower) { activeTower = tower; Rebuild(celebrate: false, null); } internal static void Reset() { activeTower = null; activeDisplayNode = null; pulseRenderer = null; pulseEndsAt = 0f; evolutionRig = null; evolutionOrbitParts.Clear(); DisposeEvolutionMaterials(); evolutionUsesMesh = false; evolutionUsesTowerDisplay = false; evolutionOrbitTime = 0f; nextEvolutionIntegrityCheckAt = 0f; appliedEvolutionDisplay = null; } internal static bool TrySellActiveTower() { if (activeTower == null) { return false; } TowerExt.SellTower(activeTower); return true; } internal static void Tick() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: 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_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) EnsureEvolutionVisualIsAttached(); TickSecretEvolutionRig(); if (pulseRenderer != null) { if (Time.time >= pulseEndsAt) { Object.Destroy((Object)(object)((Component)pulseRenderer).gameObject); pulseRenderer = null; return; } float num = 1f - (pulseEndsAt - Time.time) / 1.2f; float num2 = 0.75f + num * 1.15f; Color color = pulseRenderer.color; color.a = (1f - num) * 0.72f; pulseRenderer.color = color; ((Component)pulseRenderer).transform.localScale = new Vector3(num2, num2, 1f); ((Component)pulseRenderer).transform.localEulerAngles = new Vector3(0f, 0f, num * 220f); } } private static void Rebuild(bool celebrate, RollResult? result) { //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected O, but got Unknown //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) if (activeTower == null || !ChaosMonkeyMod.Session.IsChaosMonkeyPresent) { return; } try { ChaosMonkeyMatchState match = ChaosMonkeyMod.Session.Match; UnityDisplayNode liveDisplayNode = GetLiveDisplayNode(); if ((Object)(object)liveDisplayNode == (Object)null) { return; } Transform transform = ((Component)liveDisplayNode).transform; SetBaseRenderersVisible(transform, visible: true); Transform val = transform.Find("ChaosMonkeyLoadoutVisual"); if (val != null) { Object.Destroy((Object)(object)((Component)val).gameObject); } DisposeEvolutionMaterials(); evolutionRig = null; evolutionOrbitParts.Clear(); evolutionOrbitTime = 0f; nextEvolutionIntegrityCheckAt = Time.time + 0.45f; Renderer val2 = ((IEnumerable)((Component)transform).GetComponentsInChildren(true)).FirstOrDefault((Func)((Renderer renderer) => renderer != null && !((Object)((Component)renderer).gameObject).name.StartsWith("ChaosMonkeyLoadoutVisual", StringComparison.Ordinal))); ModHelper.Msg((object)$"Chaos display renderer scan: {val2 != null} visible renderer anchor."); int num = ((val2 == null) ? ((Component)transform).gameObject.layer : ((Component)val2).gameObject.layer); GameObject val3 = new GameObject("ChaosMonkeyLoadoutVisual"); val3.transform.SetParent(transform, false); val3.layer = num; val3.transform.localPosition = new Vector3(0f, 0f, -0.1f); if (match != null && match.Evolution.IsComplete) { ChaosEvolutionDisplayMaterials.CaptureTowerMaterial(GetLiveDisplayNode()); if (!TryApplyEvolutionTowerDisplay(match.Evolution.Kind)) { AddStableEvolutionVisual(val3.transform, match.Evolution.Kind, num); } return; } appliedEvolutionDisplay = null; evolutionUsesTowerDisplay = false; if (match != null) { foreach (KeyValuePair layout in Layouts) { layout.Deconstruct(out var key, out var value); EquipmentSlot equipmentSlot = key; LayerLayout layerLayout = value; ItemDefinition item = match.GetItem(equipmentSlot); if ((object)item != null) { AddLayer(val3.transform, $"ChaosMonkey{equipmentSlot}{item.Id}", item, layerLayout.Position, layerLayout.Scale, layerLayout.Rotation, layerLayout.SortingOrder); } } } if (celebrate && (object)result != null) { AddRollPulse(val3.transform, result.Item); } } catch (Exception ex) { ModHelper.Error((object)("Could not refresh Chaos Monkey appearance: " + ex.Message)); } } private static void AddStableEvolutionVisual(Transform parent, EvolutionKind kind, int visibleLayer) { //IL_0031: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_00aa: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject($"ChaosMonkey{kind}EvolutionVisual"); val.transform.SetParent(parent, false); val.layer = visibleLayer; val.transform.localPosition = new Vector3(0f, 0f, -0.22f); val.transform.localScale = Vector3.one * 0.82f; SpriteRenderer obj = val.AddComponent(); obj.sprite = ModContent.GetSprite((kind == EvolutionKind.SecretAscension) ? "ChaosMonkeySecretEvolution" : "ChaosMonkeyGodlyEvolution", 950f); obj.color = Color.white; ((Renderer)obj).sortingOrder = 250; evolutionRig = val.transform; evolutionOrbitParts.Clear(); evolutionOrbitTime = 0f; evolutionUsesMesh = false; evolutionUsesTowerDisplay = false; appliedEvolutionDisplay = kind; ModHelper.Msg((object)$"Attached stable {kind} evolution visual without loading a runtime AssetBundle."); } private static bool TryAddBundledEvolutionVisual(Transform parent, EvolutionKind kind, int visibleLayer, Renderer? materialAnchor) { //IL_00c8: 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_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Expected O, but got Unknown try { if (((materialAnchor != null) ? materialAnchor.sharedMaterial : null) == null) { ModHelper.Warning((object)"Evolution mesh is waiting for a live BTD6 material; using the safe fallback."); return false; } string text = ((kind == EvolutionKind.SecretAscension) ? "ChaosMonkeySecretEvolution" : "ChaosMonkeyGodlyEvolution"); GameObject val = AssetBundleExt.LoadAssetSync(ModContent.GetBundle("chaosmonkeyevolutions"), text); if ((Object)(object)val == (Object)null) { ModHelper.Warning((object)("Evolution mesh prefab " + text + " was not found; using the safe fallback.")); return false; } GameObject val2 = Object.Instantiate(val); ((Object)val2).name = $"ChaosMonkey{kind}EvolutionMesh"; val2.transform.SetParent(parent, false); val2.transform.localPosition = new Vector3(0f, -0.4f, -0.72f); val2.transform.localScale = Vector3.one * 0.46f; SetLayerRecursively(val2.transform, visibleLayer); Il2CppArrayBase componentsInChildren = val2.GetComponentsInChildren(true); if (componentsInChildren.Length == 0) { Object.Destroy((Object)(object)val2); ModHelper.Warning((object)("Evolution mesh prefab " + text + " has no meshes; using the safe fallback.")); return false; } foreach (MeshRenderer item in componentsInChildren) { Shader val3 = Shader.Find("Unlit/Color"); Material val4 = ((val3 == null) ? new Material(materialAnchor.sharedMaterial) : new Material(val3)); evolutionMaterials.Add(val4); ((Renderer)item).sharedMaterial = val4; ApplyEvolutionPartColor(val4, kind, ((Object)((Component)item).gameObject).name); val4.renderQueue = 4000; if (val4.HasProperty("_Cull")) { val4.SetInt("_Cull", 0); } ((Renderer)item).enabled = true; } evolutionRig = val2.transform; evolutionOrbitParts.Clear(); evolutionOrbitTime = 0f; evolutionUsesMesh = true; evolutionUsesTowerDisplay = false; appliedEvolutionDisplay = kind; ModHelper.Msg((object)$"Attached clean native 3D {kind} evolution mesh ({componentsInChildren.Length} parts)."); return true; } catch (Exception ex) { DisposeEvolutionMaterials(); ModHelper.Error((object)("Could not attach the clean 3D evolution mesh: " + ex.Message)); return false; } } private static void ApplyEvolutionPartColor(Material material, EvolutionKind kind, string partName) { //IL_000f: 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_0014: 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_0041: Unknown result type (might be due to invalid IL or missing references) Color val = ((kind == EvolutionKind.SecretAscension) ? GetSecretEvolutionColor(partName) : GetGodlyEvolutionColor(partName)); if (material.HasProperty("_Color")) { material.SetColor("_Color", val); } if (material.HasProperty("_BaseColor")) { material.SetColor("_BaseColor", val); } } private static bool TryApplyEvolutionTowerDisplay(EvolutionKind kind) { if (activeTower == null) { return false; } if (evolutionUsesTowerDisplay && appliedEvolutionDisplay == kind) { return true; } try { TowerModel val = TowerModelExt.MakeCopy(activeTower.towerModel, $"ChaosMonkey{kind}EvolutionRuntime", false, ((EntityModel)activeTower.towerModel).baseId); if (kind == EvolutionKind.SecretAscension) { TowerModelExt.SetDisplay(val); } else { TowerModelExt.SetDisplay(val); } activeDisplayNode = null; TowerExt.SetTowerModel(activeTower, val); evolutionRig = null; evolutionOrbitParts.Clear(); evolutionUsesMesh = false; evolutionUsesTowerDisplay = true; appliedEvolutionDisplay = kind; ModHelper.Msg((object)$"Applied {kind} through BTD6's native tower display pipeline."); return true; } catch (Exception ex) { evolutionUsesTowerDisplay = false; ModHelper.Error((object)("Could not apply the native evolution tower display: " + ex.Message)); return false; } } private static Color GetGodlyEvolutionColor(string partName) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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) //IL_0108: Unknown result type (might be due to invalid IL or missing references) if (partName.Contains("Eye", StringComparison.Ordinal)) { return new Color(0.08f, 0.92f, 1f, 1f); } if (partName.Contains("Crystal", StringComparison.Ordinal) || partName.Contains("Gem", StringComparison.Ordinal) || partName.Contains("Core", StringComparison.Ordinal)) { return new Color(0.95f, 0.18f, 1f, 1f); } if (partName.Contains("Crown", StringComparison.Ordinal) || partName.Contains("Halo", StringComparison.Ordinal) || partName.Contains("Staff", StringComparison.Ordinal)) { return new Color(1f, 0.72f, 0.1f, 1f); } if (partName.Contains("Robe", StringComparison.Ordinal) || partName.Contains("Cape", StringComparison.Ordinal) || partName.Contains("Hood", StringComparison.Ordinal)) { return new Color(0.31f, 0.06f, 0.62f, 1f); } return new Color(0.47f, 0.2f, 0.09f, 1f); } private static Color GetSecretEvolutionColor(string partName) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) if (partName.Contains("Eye", StringComparison.Ordinal)) { return new Color(0.12f, 0.94f, 1f, 1f); } if (partName.Contains("Crystal", StringComparison.Ordinal) || partName.Contains("Core", StringComparison.Ordinal) || partName.Contains("Planet", StringComparison.Ordinal)) { return new Color(0.86f, 0.07f, 1f, 1f); } if (partName.Contains("Halo", StringComparison.Ordinal) || partName.Contains("Staff", StringComparison.Ordinal)) { return new Color(0.2f, 0.04f, 0.48f, 1f); } if (partName.Contains("Robe", StringComparison.Ordinal) || partName.Contains("Cape", StringComparison.Ordinal) || partName.Contains("Crown", StringComparison.Ordinal)) { return new Color(0.035f, 0.008f, 0.1f, 1f); } return new Color(0.055f, 0.012f, 0.14f, 1f); } private static void SetBaseRenderersVisible(Transform displayTransform, bool visible) { Transform val = displayTransform.Find("ChaosMonkeyLoadoutVisual"); foreach (Renderer componentsInChild in ((Component)displayTransform).GetComponentsInChildren(true)) { if (val == null || !((Component)componentsInChild).transform.IsChildOf(val)) { componentsInChild.enabled = visible; } } } private static void SetLayerRecursively(Transform transform, int layer) { ((Component)transform).gameObject.layer = layer; for (int i = 0; i < transform.childCount; i++) { SetLayerRecursively(transform.GetChild(i), layer); } } private static void DisposeEvolutionMaterials() { foreach (Material evolutionMaterial in evolutionMaterials) { if ((Object)(object)evolutionMaterial != (Object)null) { Object.Destroy((Object)(object)evolutionMaterial); } } evolutionMaterials.Clear(); } private static void AddLayer(Transform parent, string name, ItemDefinition item, Vector3 position, Vector3 scale, float rotation, int sortingOrder, float pixelsPerUnit = 420f) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_0036: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(parent, false); val.layer = ((Component)parent).gameObject.layer; val.transform.localPosition = position; val.transform.localScale = scale; val.transform.localEulerAngles = new Vector3(0f, 0f, rotation); SpriteRenderer obj = val.AddComponent(); obj.sprite = ChaosItemArtwork.GetSprite(item); obj.color = ChaosItemArtwork.GetTint(item); ((Renderer)obj).sortingOrder = sortingOrder; } private static void AddRollPulse(Transform root, ItemDefinition item) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_003d: 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_005c: 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_00a1: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("ChaosMonkeyRollPulse"); val.transform.SetParent(root, false); val.layer = ((Component)root).gameObject.layer; val.transform.localPosition = new Vector3(0f, 0f, 0.6f); val.transform.localScale = new Vector3(0.75f, 0.75f, 1f); pulseRenderer = val.AddComponent(); pulseRenderer.sprite = ModContent.GetSprite("SlotAbilityIcon", 420f); Color itemColor = GetItemColor(item); itemColor.a = 0.72f; pulseRenderer.color = itemColor; ((Renderer)pulseRenderer).sortingOrder = 100; pulseEndsAt = Time.time + 1.2f; } private static void AddSecretEvolutionRig(Transform parent, UnityDisplayNode displayNode) { //IL_0015: 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) //IL_002a: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: 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_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) TintVanillaMonkey(displayNode, new Color(0.12f, 0.03f, 0.28f, 1f)); GameObject val = new GameObject("ChaosMonkeySecretEvolution3DRig"); val.transform.SetParent(parent, false); val.layer = ((Component)parent).gameObject.layer; val.transform.localPosition = new Vector3(0f, 0.03f, 0.25f); evolutionRig = val.transform; RegisterAnimatedPart(CreateEvolutionMesh("SecretVoidCore", (PrimitiveType)0, val.transform, new Vector3(0f, -0.02f, 0.35f), new Vector3(0.52f, 0.52f, 0.52f), new Color(0.035f, 0.008f, 0.1f, 1f)), pulse: false); CreateEvolutionMesh("SecretGalaxyHalo", (PrimitiveType)2, val.transform, new Vector3(0f, -0.04f, 0.2f), new Vector3(1.35f, 0.035f, 1.35f), new Color(0.18f, 0.02f, 0.42f, 0.85f)).transform.localEulerAngles = new Vector3(68f, 0f, 0f); Color[] array = (Color[])(object)new Color[6] { new Color(0.5f, 0.05f, 1f), new Color(0.05f, 0.82f, 1f), new Color(0.96f, 0.05f, 0.68f), new Color(0.16f, 0.03f, 0.35f), new Color(0.38f, 0.1f, 0.92f), new Color(0.05f, 0.46f, 0.92f) }; for (int i = 0; i < array.Length; i++) { float num = (float)i * MathF.PI * 2f / (float)array.Length; GameObject obj = CreateEvolutionMesh($"SecretOrbitCrystal{i}", (PrimitiveType)1, val.transform, new Vector3(Mathf.Cos(num) * 1.12f, Mathf.Sin(num) * 0.72f, -0.06f), new Vector3(0.18f, 0.3f, 0.18f), array[i]); obj.transform.localEulerAngles = new Vector3(35f, (float)i * 55f, (float)(-i) * 21f); RegisterAnimatedPart(obj, pulse: true); } } private static void AddGodlyEvolutionRig(Transform parent, UnityDisplayNode displayNode) { //IL_0015: 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) //IL_002a: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_00ba: 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_0136: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: 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_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_0377: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_0397: 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) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_0421: Unknown result type (might be due to invalid IL or missing references) //IL_0429: Unknown result type (might be due to invalid IL or missing references) //IL_0451: Unknown result type (might be due to invalid IL or missing references) TintVanillaMonkey(displayNode, new Color(0.66f, 0.25f, 0.98f, 1f)); GameObject val = new GameObject("ChaosMonkeyGodlyEvolution3DRig"); val.transform.SetParent(parent, false); val.layer = ((Component)parent).gameObject.layer; val.transform.localPosition = new Vector3(0f, 0.02f, 0.24f); evolutionRig = val.transform; CreateEvolutionMesh("GodlyCrownBand", (PrimitiveType)2, val.transform, new Vector3(0f, 0.7f, 0.05f), new Vector3(0.52f, 0.1f, 0.52f), new Color(1f, 0.7f, 0.08f, 1f)).transform.localEulerAngles = new Vector3(90f, 0f, 0f); for (int i = 0; i < 5; i++) { float num = (float)(i - 2) * 0.18f; RegisterAnimatedPart(CreateEvolutionMesh($"GodlyCrownCrystal{i}", (PrimitiveType)1, val.transform, new Vector3(num, 0.88f + (float)(i % 2) * 0.08f, 0.08f), new Vector3(0.11f, 0.28f, 0.11f), (i % 2 == 0) ? new Color(0.12f, 0.92f, 1f, 1f) : new Color(0.96f, 0.12f, 0.88f, 1f)), pulse: true); } RegisterAnimatedPart(CreateEvolutionMesh("GodlyChestCore", (PrimitiveType)0, val.transform, new Vector3(0f, 0.12f, 0.33f), new Vector3(0.34f, 0.34f, 0.2f), new Color(0.04f, 0.82f, 1f, 1f)), pulse: true); CreateEvolutionMesh("GodlyCrystalStaff", (PrimitiveType)2, val.transform, new Vector3(0.56f, 0.1f, 0.08f), new Vector3(0.08f, 0.72f, 0.08f), new Color(0.76f, 0.12f, 1f, 1f)).transform.localEulerAngles = new Vector3(0f, 0f, -28f); CreateEvolutionMesh("GodlyCrystalHalo", (PrimitiveType)2, val.transform, new Vector3(0f, 0.22f, 0.02f), new Vector3(1.22f, 0.025f, 1.22f), new Color(1f, 0.64f, 0.08f, 1f)).transform.localEulerAngles = new Vector3(68f, 0f, 0f); Color[] array = (Color[])(object)new Color[6] { new Color(0.08f, 0.92f, 1f, 1f), new Color(0.98f, 0.2f, 0.88f, 1f), new Color(0.4f, 1f, 0.22f, 1f), new Color(1f, 0.68f, 0.05f, 1f), new Color(0.48f, 0.18f, 1f, 1f), new Color(0.92f, 0.94f, 1f, 1f) }; for (int j = 0; j < array.Length; j++) { float num2 = (float)j * MathF.PI * 2f / (float)array.Length; GameObject obj = CreateEvolutionMesh($"GodlyOrbitCrystal{j}", (PrimitiveType)1, val.transform, new Vector3(Mathf.Cos(num2) * 0.98f, 0.2f + Mathf.Sin(num2) * 0.6f, -0.08f), new Vector3(0.15f, 0.29f, 0.15f), array[j]); obj.transform.localEulerAngles = new Vector3(42f, (float)j * 56f, (float)(-j) * 23f); RegisterAnimatedPart(obj, pulse: true); } } private static GameObject CreateEvolutionMesh(string name, PrimitiveType type, Transform parent, Vector3 position, Vector3 scale, Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GameObject.CreatePrimitive(type); ((Object)obj).name = name; obj.transform.SetParent(parent, false); obj.layer = ((Component)parent).gameObject.layer; obj.transform.localPosition = position + new Vector3(0f, 0f, -0.75f); obj.transform.localScale = scale; Collider component = obj.GetComponent(); if (component != null) { Object.Destroy((Object)(object)component); } Renderer component2 = obj.GetComponent(); if (component2 != null) { Shader val = Shader.Find("Unlit/Color"); if (val != null) { component2.material = new Material(val); } if (component2.material != null) { component2.material.renderQueue = 4000; if (component2.material.HasProperty("_Color")) { component2.material.color = color; } } component2.enabled = true; } return obj; } private static void TintVanillaMonkey(UnityDisplayNode displayNode, Color tint) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) foreach (Renderer componentsInChild in ((Component)displayNode).GetComponentsInChildren(true)) { if (((Object)((Component)componentsInChild).gameObject).name.StartsWith("ChaosMonkeyLoadoutVisual", StringComparison.Ordinal)) { continue; } SpriteRenderer val = (SpriteRenderer)(object)((componentsInChild is SpriteRenderer) ? componentsInChild : null); if (val != null) { val.color = tint; continue; } Material material = componentsInChild.material; if (material != null && material.HasProperty("_Color")) { material.color = tint; } } } private static void ApplyNativeEvolutionColor(EvolutionKind kind) { //IL_004a: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) if (activeTower != null) { DisplayNode displayNode = TowerExt.GetDisplayNode(activeTower); if (displayNode != null) { Color val = ((kind == EvolutionKind.SecretAscension) ? new Color(0.1f, 0.02f, 0.24f, 1f) : new Color(0.72f, 0.22f, 0.98f, 1f)); displayNode.modifyColor = true; displayNode.colorRed = val.r; displayNode.colorGreen = val.g; displayNode.colorBlue = val.b; } } } private static void ClearNativeEvolutionColor() { if (activeTower != null) { DisplayNode displayNode = TowerExt.GetDisplayNode(activeTower); if (displayNode != null) { displayNode.modifyColor = false; } } } private static void RegisterAnimatedPart(GameObject part, bool pulse) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) evolutionOrbitParts.Add(new AnimatedEvolutionPart(part.transform, part.transform.localScale, pulse)); } private static void TickSecretEvolutionRig() { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)evolutionRig == (Object)null) { evolutionRig = null; evolutionOrbitParts.Clear(); return; } evolutionOrbitTime += Time.deltaTime; if (evolutionUsesMesh) { evolutionRig.localEulerAngles = new Vector3(Mathf.Sin(evolutionOrbitTime * 0.75f) * 4f, Mathf.Sin(evolutionOrbitTime * 0.55f) * 7f, 0f); } else { evolutionRig.localEulerAngles = new Vector3(0f, 0f, Mathf.Sin(evolutionOrbitTime * 0.75f) * 3f); } for (int i = 0; i < evolutionOrbitParts.Count; i++) { AnimatedEvolutionPart animatedEvolutionPart = evolutionOrbitParts[i]; if (animatedEvolutionPart.Transform != null) { Transform transform = animatedEvolutionPart.Transform; transform.localEulerAngles += new Vector3(46f, 96f + (float)i * 13f, 72f) * Time.deltaTime; if (animatedEvolutionPart.Pulses) { float num = 1f + Mathf.Sin(evolutionOrbitTime * 3.2f + (float)i) * 0.1f; animatedEvolutionPart.Transform.localScale = animatedEvolutionPart.BaseScale * num; } } } } private static void EnsureEvolutionVisualIsAttached() { ChaosMonkeyMatchState match = ChaosMonkeyMod.Session.Match; if (activeTower == null || match == null || !match.Evolution.IsComplete || Time.time < nextEvolutionIntegrityCheckAt) { return; } nextEvolutionIntegrityCheckAt = Time.time + 0.45f; try { if (appliedEvolutionDisplay != match.Evolution.Kind || (!evolutionUsesTowerDisplay && (Object)(object)evolutionRig == (Object)null)) { Rebuild(celebrate: false, null); } } catch (Exception ex) { ModHelper.Error((object)("Could not restore Chaos Monkey evolution visual: " + ex.Message)); } } private static UnityDisplayNode? GetLiveDisplayNode() { if ((Object)(object)activeDisplayNode != (Object)null) { return activeDisplayNode; } if (activeTower == null) { return null; } DisplayNode displayNode = TowerExt.GetDisplayNode(activeTower); if ((Object)(object)((displayNode != null) ? displayNode.graphic : null) != (Object)null) { activeDisplayNode = displayNode.graphic; ModHelper.Msg((object)"Chaos Monkey live display acquired from its simulation node."); return activeDisplayNode; } UnityDisplayNode unityDisplayNode = TowerExt.GetUnityDisplayNode(activeTower); if ((Object)(object)unityDisplayNode != (Object)null) { activeDisplayNode = unityDisplayNode; ModHelper.Msg((object)"Chaos Monkey live display acquired through the tower bridge."); return activeDisplayNode; } return null; } internal static Color GetItemColor(ItemDefinition item) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: 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_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Unknown result type (might be due to invalid IL or missing references) Color result = (Color)(item.Rarity switch { Rarity.Common => new Color(0.82f, 0.84f, 0.88f), Rarity.Uncommon => new Color(0.4f, 1f, 0.52f), Rarity.Rare => new Color(0.22f, 0.72f, 1f), Rarity.Epic => new Color(0.82f, 0.27f, 1f), Rarity.Legendary => new Color(1f, 0.42f, 0.1f), Rarity.Mythic => new Color(1f, 0.12f, 0.5f), Rarity.Godly => new Color(1f, 0.84f, 0.22f), Rarity.Secret => new Color(1f, 0.04f, 0.25f), _ => Color.white, }); if (item.Tags.Contains("Fire")) { return new Color(1f, 0.28f, 0.06f); } if (item.Tags.Contains("Frost")) { return new Color(0.32f, 0.88f, 1f); } if (item.Tags.Contains("Lightning")) { return new Color(0.18f, 0.92f, 1f); } if (item.Tags.Contains("Gravity")) { return new Color(0.38f, 0.25f, 1f); } if (item.Tags.Contains("Void")) { return new Color(0.7f, 0.12f, 1f); } if (item.Tags.Contains("Poison")) { return new Color(0.34f, 0.94f, 0.2f); } if (item.Tags.Contains("Meteor")) { return new Color(1f, 0.48f, 0.08f); } if (item.Tags.Contains("Soul")) { return new Color(0.2f, 1f, 0.78f); } if (item.Tags.Contains("Time")) { return new Color(1f, 0.74f, 0.12f); } if (item.Tags.Contains("Reality")) { return new Color(1f, 0.18f, 0.64f); } if (item.Tags.Contains("Genesis")) { return new Color(1f, 0.95f, 0.42f); } if (item.Tags.Contains("Celestial")) { return new Color(0.72f, 0.92f, 1f); } if (item.Tags.Contains("Oblivion")) { return new Color(0.5f, 0.05f, 0.72f); } if (item.Tags.Contains("Luck")) { return new Color(0.36f, 1f, 0.58f); } if (item.Tags.Contains("Moab")) { return new Color(1f, 0.52f, 0.15f); } if (item.Tags.Contains("Galaxy")) { return new Color(0.2f, 0.82f, 1f); } if (item.Tags.Contains("Secret")) { return new Color(0.62f, 0.08f, 1f); } return result; } } internal static class ChaosMonkeyCombat { internal static void Apply(Tower tower) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown ChaosMonkeyMatchState match = ChaosMonkeyMod.Session.Match; if (match == null) { return; } try { ChaosCombatStats chaosCombatStats = ChaosCombatBalance.Calculate(match.Equipment, ChaosMonkeyMod.Session.ActiveSynergies, match.Evolution); TowerModel towerModel = tower.towerModel; OverrideCamoDetectionModel behavior = TowerModelBehaviorExt.GetBehavior(towerModel); if (behavior == null) { TowerModelBehaviorExt.AddBehavior(towerModel, new OverrideCamoDetectionModel("ChaosMonkeyAlwaysDetectsCamo", true)); } else { behavior.detectCamo = true; } AttackModel behavior2 = TowerModelBehaviorExt.GetBehavior(towerModel); if (behavior2 == null || ((Il2CppArrayBase)(object)behavior2.weapons).Length == 0) { return; } towerModel.range = chaosCombatStats.Range; behavior2.range = chaosCombatStats.Range; FilterInvisibleModel behavior3 = AttackModelBehaviorExt.GetBehavior(behavior2); if (behavior3 == null) { AttackModelBehaviorExt.AddBehavior(behavior2, new FilterInvisibleModel("ChaosMonkeyCamoTargeting", true, false)); } else { behavior3.isActive = true; } match.Equipment.TryGetValue(EquipmentSlot.Weapon, out ItemDefinition value); foreach (WeaponModel item in (Il2CppArrayBase)(object)behavior2.weapons) { item.Rate = chaosCombatStats.AttackCooldown; item.projectile.pierce = chaosCombatStats.Pierce; ProjectileModelExt.SetHitCamo(item.projectile, true); DamageModel behavior4 = ProjectileModelBehaviorExt.GetBehavior(item.projectile); if (behavior4 != null) { behavior4.damage = chaosCombatStats.Damage; behavior4.immuneBloonProperties = (BloonProperties)0; } if ((object)value != null) { ChaosWeaponProjectileDisplays.Apply(value.Id, item.projectile); } } } catch (Exception ex) { ModHelper.Error((object)("Could not apply Chaos Monkey combat gear: " + ex.Message)); } } } public sealed class ChaosMonkeyDashboardWindow : ModWindow { private const float BoardScale = 1.5f; private const string PanelTexture = "ChaosGachaPanel"; private const string TextFieldTexture = "ChaosTextField"; private const string ShardIconTexture = "ChaosShardIcon"; private readonly Dictionary slotLabels = new Dictionary(); private readonly Dictionary slotImages = new Dictionary(); private readonly Dictionary rollLabels = new Dictionary(); private EquipmentSlot selectedSlot; private ModHelperText? shardText; private ModHelperText? luckText; private ModHelperText? pityText; private ModHelperText? evolutionText; private ModHelperText? detailsTitle; private ModHelperText? detailsStats; private ModHelperText? detailsEffect; private ModHelperText? detailsSynergy; private ModHelperText? resultText; private ModHelperText? sellText; private ModHelperImage? loadoutPortrait; private string lastResult = "SELECT A SLOT, THEN ROLL FOR ITS FIRST PIECE OF GEAR."; public override int DefaultWidth => 2250; public override int DefaultHeight => 1530; public override bool AllowMultiple => false; public override bool AllowResizing => false; public override Info WindowInfo { get { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) Info result = default(Info); ((Info)(ref result))..ctor(((ModContent)this).Name); ((Info)(ref result)).set_Width((float)((ModWindow)this).DefaultWidth); ((Info)(ref result)).set_Height((float)((ModWindow)this).DefaultHeight); ((Info)(ref result)).set_Anchor(new Vector2(0.5f, 0.5f)); ((Info)(ref result)).set_Pivot(new Vector2(0.5f, 0.5f)); ((Info)(ref result)).set_Position(new Vector2(-235f, 0f)); return result; } } public override void ModifyWindow(ModHelperWindow window) { //IL_001f: 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_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) ((ModHelperComponent)window.content).AddImage(BoardInfo("ChaosGachaBoard", 0f, 0f, 1360f, 790f), ModContent.GetSpriteReference("ChaosGachaPanel").guidRef); AddField(window, "BoardTitle", 0f, 333f, 420f, 48f, "CHAOS MONKEY • GEAR BOARD", 27f); ((ModHelperComponent)window.content).AddImage(BoardInfo("BoardShardIcon", -225f, 279f, 46f, 46f), ModContent.GetSpriteReference("ChaosShardIcon").guidRef); shardText = AddField(window, "BoardShards", -75f, 279f, 235f, 50f, BuildShardText(), 28f); luckText = AddField(window, "BoardLuck", 220f, 279f, 190f, 50f, BuildLuckText(), 24f); pityText = ((ModHelperComponent)window.content).AddText(BoardInfo("BoardPities", 0f, 218f, 720f, 55f), BuildPityText(), BoardFont(20f), (TextAlignmentOptions)514); pityText.EnableAutoSizing(BoardFont(20f), BoardFont(14f)); evolutionText = AddField(window, "BoardEvolution", 0f, 154f, 690f, 52f, BuildEvolutionText(), 19f); AddSlotButton(window, EquipmentSlot.Weapon, -488f, 135f); AddSlotButton(window, EquipmentSlot.Body, -488f, -18f); AddSlotButton(window, EquipmentSlot.Trait, -488f, -171f); AddSlotButton(window, EquipmentSlot.Head, 488f, 135f); AddSlotButton(window, EquipmentSlot.Ammo, 488f, -18f); AddSlotButton(window, EquipmentSlot.Ability, 488f, -171f); loadoutPortrait = ((ModHelperComponent)window.content).AddImage(BoardInfo("ChaosMonkeyLoadoutPortrait", 0f, 5f, 215f, 265f), ModContent.GetSpriteReference("ChaosMonkeyBaseUnarmed").guidRef); loadoutPortrait.Image.preserveAspect = true; detailsTitle = AddField(window, "SelectedItemTitle", 0f, -175f, 360f, 48f, BuildDetailsTitle(), 24f); detailsStats = AddField(window, "SelectedItemStats", 0f, -227f, 520f, 42f, BuildDetails().Stats, 19f); detailsEffect = AddField(window, "SelectedItemEffect", 0f, -278f, 710f, 52f, "EFFEKT: " + BuildDetails().Effect, 18f); detailsSynergy = AddField(window, "SelectedItemSynergy", 0f, -335f, 710f, 46f, "SYNERGIE: " + BuildDetails().Synergy, 17f); AddRollButton(window, "NormalRoll", -420f, "NORMAL ROLL", RollMode.Normal); AddRollButton(window, "RandomRoll", -420f, "RANDOM ROLL", RollMode.Random, -310f); AddRollButton(window, "SpecialRoll", -420f, "SPECIAL ROLL", RollMode.Special, 310f); resultText = AddField(window, "RollResult", 0f, -480f, 860f, 46f, lastResult, 18f); AddSellButton(window, -535f); } public override void OnUpdate(ModHelperWindow window) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) ModHelperText? obj = shardText; if (obj != null) { obj.SetText(BuildShardText()); } ModHelperText? obj2 = luckText; if (obj2 != null) { obj2.SetText(BuildLuckText()); } ModHelperText? obj3 = pityText; if (obj3 != null) { obj3.SetText(BuildPityText()); } ModHelperText? obj4 = evolutionText; if (obj4 != null) { obj4.SetText(BuildEvolutionText()); } if (loadoutPortrait != null) { loadoutPortrait.Image.sprite = ModContent.GetSprite(BuildPortraitAssetName(), 100f); loadoutPortrait.Image.preserveAspect = true; ((Graphic)loadoutPortrait.Image).color = Color.white; } ModHelperText? obj5 = detailsTitle; if (obj5 != null) { obj5.SetText(BuildDetailsTitle()); } ModHelperText? obj6 = detailsStats; if (obj6 != null) { obj6.SetText(BuildDetails().Stats); } ModHelperText? obj7 = detailsEffect; if (obj7 != null) { obj7.SetText("EFFEKT: " + BuildDetails().Effect); } ModHelperText? obj8 = detailsSynergy; if (obj8 != null) { obj8.SetText("SYNERGIE: " + BuildDetails().Synergy); } ModHelperText? obj9 = resultText; if (obj9 != null) { obj9.SetText(lastResult); } ModHelperText? obj10 = sellText; if (obj10 != null) { obj10.SetText(BuildSellText()); } EquipmentSlot key; ModHelperText value; foreach (KeyValuePair slotLabel in slotLabels) { slotLabel.Deconstruct(out key, out value); EquipmentSlot slot = key; value.SetText(BuildSlotText(slot)); } foreach (KeyValuePair slotImage in slotImages) { slotImage.Deconstruct(out key, out var value2); EquipmentSlot slot2 = key; ModHelperImage val = value2; ItemDefinition itemDefinition = ChaosMonkeyMod.Session.Match?.GetItem(slot2); if ((object)itemDefinition != null) { val.Image.sprite = ChaosItemArtwork.GetSprite(itemDefinition); val.Image.preserveAspect = true; ((Graphic)val.Image).color = ChaosItemArtwork.GetTint(itemDefinition); } } foreach (KeyValuePair rollLabel in rollLabels) { rollLabel.Deconstruct(out var key2, out value); RollMode mode = key2; value.SetText(BuildRollText(mode)); } } public override void OnClose(ModHelperWindow window) { shardText = null; luckText = null; pityText = null; evolutionText = null; detailsTitle = null; detailsStats = null; detailsEffect = null; detailsSynergy = null; resultText = null; sellText = null; loadoutPortrait = null; slotLabels.Clear(); slotImages.Clear(); rollLabels.Clear(); } private void AddSlotButton(ModHelperWindow window, EquipmentSlot slot, float x, float y) { //IL_005d: 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_0182: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) ((ModHelperComponent)window.content).AddImage(BoardInfo($"Slot{slot}Frame", x, y, 365f, 132f), ModContent.GetSpriteReference("ChaosTextField").guidRef); ModHelperImage val = ((ModHelperComponent)window.content).AddImage(BoardInfo($"Slot{slot}Icon", x - 132f, y, 80f, 80f), ModContent.GetSpriteReference($"Slot{slot}Icon").guidRef); val.Image.preserveAspect = true; slotImages[slot] = val; ((ModHelperComponent)window.content).AddImage(BoardInfo($"Slot{slot}CostIcon", x + 81f, y - 39f, 28f, 28f), ModContent.GetSpriteReference("ChaosShardIcon").guidRef); ((ModHelperComponent)window.content).AddText(BoardInfo($"Slot{slot}Cost", x + 125f, y - 39f, 68f, 28f), ChaosEconomy.SlotRollCosts[slot].ToString(), BoardFont(18f), (TextAlignmentOptions)4097).EnableAutoSizing(BoardFont(18f), BoardFont(14f)); slotLabels[slot] = ((ModHelperComponent)window.content).AddText(BoardInfo($"Slot{slot}Label", x + 36f, y + 8f, 254f, 82f), BuildSlotText(slot), BoardFont(20f), (TextAlignmentOptions)4097); slotLabels[slot].EnableAutoSizing(BoardFont(20f), BoardFont(14f)); ((Graphic)GameObjectExt.AddButton(((Component)window.content).gameObject, BoardInfo($"Slot{slot}", x, y, 365f, 132f), string.Empty, (Action)delegate { selectedSlot = slot; lastResult = ChaosItemDetailsCatalog.SlotName(slot) + " SELECTED • INSPECT THE ITEM EFFECT BELOW."; }).Image).color = new Color(1f, 1f, 1f, 0f); } private void AddRollButton(ModHelperWindow window, string name, float y, string label, RollMode mode, float x = 0f) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) rollLabels[mode] = AddField(window, name + "Label", x, y, 250f, 72f, label, 21f); ((Graphic)GameObjectExt.AddButton(((Component)window.content).gameObject, BoardInfo(name, x, y, 252f, 74f), string.Empty, (Action)delegate { Roll(mode); }).Image).color = new Color(1f, 1f, 1f, 0f); } private void AddSellButton(ModHelperWindow window, float y) { //IL_004b: 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) sellText = AddField(window, "SellResetLabel", 0f, y, 670f, 44f, BuildSellText(), 17f); ((Graphic)GameObjectExt.AddButton(((Component)window.content).gameObject, BoardInfo("SellReset", 0f, y, 672f, 46f), string.Empty, (Action)delegate { if (ChaosMonkeyMod.TrySellActiveChaosMonkey()) { lastResult = "MONKEY SOLD • SHARDS RETAINED • NEXT PLACEMENT HAS EMPTY SLOTS."; } else { lastResult = "SELLING IS LOCKED WHILE OR AFTER A HIDDEN EVOLUTION."; } }).Image).color = new Color(1f, 1f, 1f, 0f); } private void Roll(RollMode mode) { try { RollResult rollResult = ChaosMonkeyMod.Session.Roll(selectedSlot, mode, new Random()); lastResult = $"NEW {rollResult.Item.Rarity.ToString().ToUpperInvariant()} • {rollResult.Item.DisplayName.ToUpperInvariant()} EQUIPPED"; ChaosMonkeyMod.RefreshAppearanceAfterRoll(rollResult); } catch (InvalidOperationException ex) { lastResult = ex.Message.ToUpperInvariant(); } } private static ModHelperText AddField(ModHelperWindow window, string name, float x, float y, float width, float height, string text, float fontSize) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) ((ModHelperComponent)window.content).AddImage(BoardInfo(name + "Panel", x, y, width, height), ModContent.GetSpriteReference("ChaosTextField").guidRef); ModHelperText obj = ((ModHelperComponent)window.content).AddText(BoardInfo(name, x, y, width - 24f, height - 6f), text, BoardFont(fontSize), (TextAlignmentOptions)514); obj.EnableAutoSizing(BoardFont(fontSize), BoardFont(13f)); return obj; } private static Info BoardInfo(string name, float x, float y, float width, float height) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) return new Info(name, x * 1.5f, y * 1.5f, width * 1.5f, height * 1.5f); } private static float BoardFont(float value) { return value * 1.5f; } private static string BuildShardText() { ChaosMonkeyMatchState match = ChaosMonkeyMod.Session.Match; if (match != null) { return $"SHARDS {match.Shards:N0}"; } return "SHARDS —"; } private static string BuildLuckText() { ChaosMonkeyMatchState match = ChaosMonkeyMod.Session.Match; if (match != null) { return $"LUCK ×{match.PurchasedLuck}"; } return "LUCK ×—"; } private static string BuildPityText() { ChaosMonkeyMatchState match = ChaosMonkeyMod.Session.Match; if (match == null) { return "LEGENDARY PITY — • MYTHIC PITY — • GODLY PITY —"; } return $"LEGENDARY PITY {match.Pity.RollsSinceLegendaryOrHigher}/{150} • MYTHIC PITY {match.Pity.RollsSinceMythicOrHigher}/{500} • GODLY PITY {match.Pity.RollsSinceGodly}/{1000}"; } private static string BuildEvolutionText() { EvolutionState evolutionState = ChaosMonkeyMod.Session.Match?.Evolution; string text = ((evolutionState == null || evolutionState.Kind == EvolutionKind.None) ? "EVOLUTION STATUS: HIDDEN" : (evolutionState.IsInProgress ? $"HIDDEN EVOLUTION: {evolutionState.RoundsCompleted}/{evolutionState.RoundsRequired} ROUNDS" : "HIDDEN EVOLUTION: COMPLETE")); SynergyDefinition synergyDefinition = ChaosMonkeyMod.Session.ActiveSynergies.FirstOrDefault((SynergyDefinition synergy) => synergy.IsFullSet); if ((object)synergyDefinition != null) { return text + " • " + synergyDefinition.DisplayName.ToUpperInvariant() + " ACTIVE"; } return text; } private static string BuildPortraitAssetName() { EvolutionState evolutionState = ChaosMonkeyMod.Session.Match?.Evolution; if (evolutionState == null || !evolutionState.IsComplete) { return "ChaosMonkeyBaseUnarmed"; } if (evolutionState.Kind != EvolutionKind.SecretAscension) { return "ChaosMonkeyGodlyEvolution"; } return "ChaosMonkeySecretEvolution"; } private static string BuildSellText() { ChaosMonkeyMatchState? match = ChaosMonkeyMod.Session.Match; if (match == null || !match.CanSell) { return "SELL LOCKED • HIDDEN EVOLUTION IN PROGRESS OR COMPLETE"; } return "SELL CHAOS MONKEY • RETAIN UNUSED SHARDS • RESET GEAR"; } private string BuildSlotText(EquipmentSlot slot) { ItemDefinition itemDefinition = ChaosMonkeyMod.Session.Match?.GetItem(slot); string text = ((slot == selectedSlot) ? "SELECTED" : "SELECT"); return ChaosItemDetailsCatalog.SlotName(slot) + " • " + text + "\n" + (((object)itemDefinition == null) ? "EMPTY • ROLL TO DISCOVER" : (itemDefinition.Rarity.ToString().ToUpperInvariant() + " • " + itemDefinition.DisplayName.ToUpperInvariant())); } private string BuildDetailsTitle() { ItemDefinition itemDefinition = ChaosMonkeyMod.Session.Match?.GetItem(selectedSlot); if ((object)itemDefinition != null) { return itemDefinition.Rarity.ToString().ToUpperInvariant() + " • " + itemDefinition.DisplayName.ToUpperInvariant(); } return ChaosItemDetailsCatalog.SlotName(selectedSlot) + " • EMPTY SLOT"; } private ChaosItemDetails BuildDetails() { ItemDefinition itemDefinition = ChaosMonkeyMod.Session.Match?.GetItem(selectedSlot); if ((object)itemDefinition != null) { return ChaosItemDetailsCatalog.Get(itemDefinition); } return ChaosItemDetailsCatalog.Empty(selectedSlot); } private string BuildRollText(RollMode mode) { ChaosMonkeyMatchState match = ChaosMonkeyMod.Session.Match; if (match == null) { return "PREPARING…"; } switch (mode) { case RollMode.Normal: return $"NORMAL ROLL\n{ChaosEconomy.GetRollCost(selectedSlot, RollMode.Normal)} SHARDS • {ChaosItemDetailsCatalog.SlotName(selectedSlot)}"; case RollMode.Random: if (match.RandomRollUnlocked) { return $"RANDOM ROLL\n{90} SHARDS • RANDOM SLOT"; } return $"RANDOM ROLL\nUNLOCK AT {match.RandomUnlockAtNormalRoll} NORMAL ROLLS"; case RollMode.Special: return $"SPECIAL ROLL\n{ChaosEconomy.GetRollCost(selectedSlot, RollMode.Special)} SHARDS • MINIMUM ×32 LUCK"; default: return string.Empty; } } } public sealed class ChaosMonkeyMod : BloonsTD6Mod { private static string? chaosMonkeyModelName; private static bool dashboardOpenRequested; private static bool luckOddsOpenRequested; internal static ChaosMonkeySession Session { get; } = new ChaosMonkeySession(ItemCatalog.CreateInitial(), new GachaEngine()); internal static bool IsDeveloperModeAvailable => string.Equals(Environment.UserName, "Lauri", StringComparison.OrdinalIgnoreCase); public override void OnApplicationStart() { ModHelper.Msg((object)"Chaos Monkey 1.0.0 loaded for BTD6 v56.3."); } public override void OnMatchStart() { ResetMapSession(); ModHelper.Msg((object)("Registered Chaos Monkey model: " + chaosMonkeyModelName + ".")); } public override void OnRestart() { ResetMapSession(); } private static void ResetMapSession() { Session.BeginMap(new Random()); ChaosShardHud.Reset(); ChaosMonkeyAppearance.Reset(); dashboardOpenRequested = false; luckOddsOpenRequested = false; ChaosShardUpgradePanel.Dispose(); chaosMonkeyModelName = ((Model)ModContent.GetTowerModel(0, 0, 0)).name; } public override void OnRoundEnd() { if (Session.AdvanceRound()) { ChaosMonkeyAppearance.RefreshAfterEvolution(); ModHelper.Msg((object)"A hidden Chaos Monkey evolution has completed."); } } public override void OnTowerGraphicsCreated(TowerModel towerModel, List nodes) { if (IsChaosMonkeyModel((Model)(object)towerModel)) { ChaosMonkeyAppearance.RegisterGraphics(nodes); } } public override void OnTowerCreated(Tower tower, Entity target, Model modelToUse) { if (IsChaosMonkeyModel(modelToUse)) { if (!Session.IsPlacementAvailable) { ModHelper.Msg((object)"Ignored an additional Chaos Monkey: one is allowed per map."); return; } Session.PlaceChaosMonkey(); ChaosMonkeyAppearance.Attach(tower); ModHelper.Msg((object)"Chaos Monkey placed."); } } public override void OnTowerSold(Tower tower, float amount) { if (IsActiveChaosMonkey(tower) && Session.TrySellChaosMonkey()) { ChaosMonkeyAppearance.Reset(); ModHelper.Msg((object)"Chaos Monkey sold. It may be placed again with its remaining Shards, but an empty loadout."); } } public override void OnTowerSelected(Tower tower) { if (!IsActiveChaosMonkey(tower)) { SetDefaultTowerPanelVisible(isVisible: true); return; } SetDefaultTowerPanelVisible(isVisible: true); dashboardOpenRequested = true; luckOddsOpenRequested = true; ChaosMonkeyAppearance.RefreshForSelection(tower); ChaosShardUpgradePanel.Show(); } public override void OnTowerDeselected(Tower tower) { if (IsActiveChaosMonkey(tower)) { ModHelperWindow[] array = ((ModWindow)ModContent.GetInstance()).OpenedWindows.ToArray(); for (int i = 0; i < array.Length; i++) { array[i].Close(); } array = ((ModWindow)ModContent.GetInstance()).OpenedWindows.ToArray(); for (int i = 0; i < array.Length; i++) { array[i].Close(); } ChaosShardUpgradePanel.Hide(); } } public override void OnUpdate() { ChaosShardHud.Refresh(Session); ChaosMonkeyAppearance.Tick(); if (IsDeveloperModeAvailable && Input.GetKeyDown((KeyCode)289) && Session.IsChaosMonkeyPresent) { ChaosDeveloperWindow instance = ModContent.GetInstance(); if (((ModWindow)instance).OpenedWindows.Count == 0) { ((ModWindow)instance).Open(); } else { ModHelperWindow[] array = ((ModWindow)instance).OpenedWindows.ToArray(); for (int i = 0; i < array.Length; i++) { array[i].Close(); } } } if (dashboardOpenRequested) { dashboardOpenRequested = false; ChaosMonkeyDashboardWindow instance2 = ModContent.GetInstance(); if (((ModWindow)instance2).OpenedWindows.Count == 0) { ((ModWindow)instance2).Open(); } } if (luckOddsOpenRequested) { luckOddsOpenRequested = false; ChaosLuckOddsWindow instance3 = ModContent.GetInstance(); if (((ModWindow)instance3).OpenedWindows.Count == 0) { ((ModWindow)instance3).Open(); } } ChaosShardUpgradePanel.Refresh(); } private static bool IsActiveChaosMonkey(Tower tower) { if (Session.IsChaosMonkeyPresent) { if (!IsChaosMonkeyModel((Model)(object)tower.towerModel)) { return ChaosMonkeyAppearance.IsAttachedTo(tower); } return true; } return false; } private static void SetDefaultTowerPanelVisible(bool isVisible) { TowerSelectionMenu towerSelectionMenu = Instances.TowerSelectionMenu; if (towerSelectionMenu != null) { ((Component)towerSelectionMenu).gameObject.SetActive(isVisible); } } private static bool IsChaosMonkeyModel(Model model) { string name = model.name; if (chaosMonkeyModelName == null || !name.StartsWith(chaosMonkeyModelName, StringComparison.Ordinal)) { return name.Contains("ChaosMonkey", StringComparison.OrdinalIgnoreCase); } return true; } internal static void RefreshAppearanceAfterRoll(RollResult result) { ChaosMonkeyAppearance.RefreshAfterRoll(result); } internal static void EquipDeveloperItem(string itemId) { if (IsDeveloperModeAvailable) { Session.EquipDeveloperItem(itemId, new Random()); ChaosMonkeyAppearance.RefreshAfterDeveloperLoadout(); } } internal static bool TrySellActiveChaosMonkey() { ChaosMonkeyMatchState? match = Session.Match; if (match == null || !match.CanSell) { return false; } return ChaosMonkeyAppearance.TrySellActiveTower(); } } public sealed class ChaosMonkeyTower : ModTower { public override TowerSet TowerSet => (TowerSet)4; public override string BaseTower => TowerType.DartMonkey; public override int Cost => 650; public override int TopPathUpgrades => 0; public override int MiddlePathUpgrades => 0; public override int BottomPathUpgrades => 0; public override int ShopTowerCount => 1; public override string Description => "A six-slot Chaos Gacha tower. Sell and re-place it before an unknown evolution begins; its remaining Shards stay, but its loadout resets."; public override void ModifyBaseTowerModel(TowerModel towerModel) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown towerModel.range = 45f; if (TowerModelBehaviorExt.GetBehavior(towerModel) == null) { TowerModelBehaviorExt.AddBehavior(towerModel, new OverrideCamoDetectionModel("ChaosMonkeyAlwaysDetectsCamo", true)); } AttackModel behavior = TowerModelBehaviorExt.GetBehavior(towerModel); behavior.range = 45f; ((Il2CppArrayBase)(object)behavior.weapons)[0].Rate = 0.4f; FilterInvisibleModel behavior2 = AttackModelBehaviorExt.GetBehavior(behavior); if (behavior2 == null) { AttackModelBehaviorExt.AddBehavior(behavior, new FilterInvisibleModel("ChaosMonkeyCamoTargeting", true, false)); } else { behavior2.isActive = true; } ProjectileModel projectile = ((Il2CppArrayBase)(object)behavior.weapons)[0].projectile; projectile.pierce = 5f; ProjectileModelExt.SetHitCamo(projectile, true); DamageModel behavior3 = ProjectileModelBehaviorExt.GetBehavior(projectile); behavior3.damage = 4f; behavior3.immuneBloonProperties = (BloonProperties)0; } } internal static class ChaosShardHud { private const string ShardIconTexture = "ChaosShardIcon"; private static ModHelperImage? shardIcon; private static ModHelperText? shardText; private static readonly MethodInfo? GetLeftHud = typeof(MainHudLeftAlignExt).GetMethod("get_instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); internal static void Reset() { object? obj = GetLeftHud?.Invoke(null, null); Component val = (Component)((obj is Component) ? obj : null); if (val != null) { RemoveExistingHud(val); } shardIcon = null; shardText = null; } internal static void Refresh(ChaosMonkeySession session) { //IL_0052: 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) if (session.Match == null) { return; } object? obj = GetLeftHud?.Invoke(null, null); Component val = (Component)((obj is Component) ? obj : null); if (val != null) { if (shardText == null) { RemoveExistingHud(val); shardIcon = GameObjectExt.AddImage(val.gameObject, new Info("ChaosShardHudIcon", 1100f, -65f, 185f, 185f), ModContent.GetSpriteReference("ChaosShardIcon").guidRef); shardText = GameObjectExt.AddText(val.gameObject, new Info("ChaosShardHud", 1285f, -65f, 220f, 120f), string.Empty, 64f); } shardText.SetText(session.Match.Shards.ToString("N0")); } } private static void RemoveExistingHud(Component leftHud) { Transform[] array = ((IEnumerable)leftHud.GetComponentsInChildren(true)).Where(delegate(Transform transform) { string name = ((Object)transform).name; return (name == "ChaosShardHud" || name == "ChaosShardHudIcon") ? true : false; }).ToArray(); for (int num = 0; num < array.Length; num++) { Object.Destroy((Object)(object)((Component)array[num]).gameObject); } } } internal static class ChaosShardUpgradePanel { private const string RootPrefix = "ChaosMonkeyNativeShard"; private static readonly List uiObjects = new List(); private static readonly List hiddenPathClosedLabels = new List(); private static readonly List packTexts = new List(); private static TextMeshProUGUI? shardsText; private static TextMeshProUGUI? statusText; private static string status = "REPEATABLE SHARD PURCHASES"; private static bool showRequested; internal static void Show() { showRequested = true; TowerSelectionMenu towerSelectionMenu = Instances.TowerSelectionMenu; if (towerSelectionMenu == null) { return; } if (uiObjects.Count > 0 && BelongsToCurrentMenu(((Component)towerSelectionMenu).transform)) { SetGeneratedObjectsActive(isActive: true); HidePathClosedLabels(((Component)towerSelectionMenu).transform); Refresh(); return; } DisposeGeneratedObjects(); Button componentInChildren = ((Component)towerSelectionMenu).GetComponentInChildren