using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP.Utils.Collections;
using Grimoire.Builds;
using Grimoire.Events;
using Grimoire.Generated;
using Grimoire.Reskins;
using Grimoire.Spells;
using Grimoire.Types;
using Grimoire.Ui;
using Il2CppInterop.Runtime;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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;
}
}
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte b)
{
NullableFlags = new byte[1] { b };
}
public NullableAttribute(byte[] b)
{
NullableFlags = b;
}
}
[AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte b)
{
Flag = b;
}
}
}
namespace Grimoire.LouderKnelly
{
internal static class BellExplodeOnExpirePatch
{
internal static void Subscribe()
{
TsbSpellSpawnRegistry.Subscribe((TsbSpellType)4, (Action<TsbSpellSpawn>)OnBellSpawned);
}
private static void OnBellSpawned(TsbSpellSpawn spawn)
{
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: 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_010b: Unknown result type (might be due to invalid IL or missing references)
if (!Plugin.IsEnabled)
{
return;
}
try
{
LogInfoHandler val;
bool flag = default(bool);
if (!KnellyBellSet.Contains(((TsbSpellSpawn)(ref spawn)).CasterClientId))
{
if (Plugin.VerboseLogging && Log.Source != null)
{
GrimoireLogSource source = Log.Source;
GrimoireLogSource obj = source;
val = new LogInfoHandler(80, 2, source, ref flag);
if (flag)
{
((LogInfoHandler)(ref val)).AppendLiteral("[LouderKnelly] Bell spawned: casterId=");
((LogInfoHandler)(ref val)).AppendFormatted<ulong>(((TsbSpellSpawn)(ref spawn)).CasterClientId);
((LogInfoHandler)(ref val)).AppendLiteral(" not in KnellyBellSet (count=");
((LogInfoHandler)(ref val)).AppendFormatted<int>(KnellyBellSet.Count);
((LogInfoHandler)(ref val)).AppendLiteral("), skipping");
}
obj.LogInfo(val);
}
return;
}
Component spawnedInstance = ((TsbSpellSpawn)(ref spawn)).SpawnedInstance;
Bell val2 = (Bell)(object)((spawnedInstance is Bell) ? spawnedInstance : null);
if ((Object)(object)val2 == (Object)null)
{
return;
}
float lifetime = Bell.op_Implicit(val2).lifetime;
if (Plugin.VerboseLogging && Log.Source != null)
{
GrimoireLogSource source = Log.Source;
GrimoireLogSource obj2 = source;
val = new LogInfoHandler(85, 2, source, ref flag);
if (flag)
{
((LogInfoHandler)(ref val)).AppendLiteral("[LouderKnelly] Bell spawned: scheduling explode-on-expire for casterId=");
((LogInfoHandler)(ref val)).AppendFormatted<ulong>(((TsbSpellSpawn)(ref spawn)).CasterClientId);
((LogInfoHandler)(ref val)).AppendLiteral(", lifetime=");
((LogInfoHandler)(ref val)).AppendFormatted<float>(lifetime);
((LogInfoHandler)(ref val)).AppendLiteral("s");
}
obj2.LogInfo(val);
}
((MonoBehaviour)val2).StartCoroutine(CollectionExtensions.WrapToIl2Cpp(WatchForExpiry(val2, lifetime, ((TsbSpellSpawn)(ref spawn)).CasterClientId)));
}
catch (Exception ex)
{
GrimoireLogSource source2 = Log.Source;
if (source2 != null)
{
source2.LogError((object)("[LouderKnelly] BellExplodeOnExpirePatch handler threw: " + ex.Message));
}
}
}
private static IEnumerator WatchForExpiry(Bell bell, float lifetime, ulong casterId)
{
float num = Mathf.Max(0f, lifetime - 0.1f);
yield return (object)new WaitForSeconds(num);
if ((Object)(object)bell == (Object)null)
{
if (Plugin.VerboseLogging)
{
GrimoireLogSource source = Log.Source;
if (source != null)
{
source.LogInfo((object)"[LouderKnelly] WatchForExpiry: bell destroyed before watcher woke, no-op");
}
}
yield break;
}
Bell val = Bell.op_Implicit(bell);
if (val.isTriggered)
{
if (Plugin.VerboseLogging)
{
GrimoireLogSource source2 = Log.Source;
if (source2 != null)
{
source2.LogInfo((object)"[LouderKnelly] WatchForExpiry: bell was triggered by player, no-op");
}
}
yield break;
}
if (Plugin.VerboseLogging && Log.Source != null)
{
GrimoireLogSource source3 = Log.Source;
bool flag = default(bool);
LogInfoHandler val2 = new LogInfoHandler(106, 3, source3, ref flag);
if (flag)
{
((LogInfoHandler)(ref val2)).AppendLiteral("[LouderKnelly] WatchForExpiry: firing ExplosionCoroutine for casterId=");
((LogInfoHandler)(ref val2)).AppendFormatted<ulong>(casterId);
((LogInfoHandler)(ref val2)).AppendLiteral(" ");
((LogInfoHandler)(ref val2)).AppendLiteral("(isEndingLifetime=");
((LogInfoHandler)(ref val2)).AppendFormatted<bool>(val.isEndingLifetime);
((LogInfoHandler)(ref val2)).AppendLiteral(", isTriggered=");
((LogInfoHandler)(ref val2)).AppendFormatted<bool>(val.isTriggered);
((LogInfoHandler)(ref val2)).AppendLiteral(")");
}
source3.LogInfo(val2);
}
((MonoBehaviour)bell).StartCoroutine(val.ExplosionCoroutine(casterId));
}
}
internal static class BringUpProbe
{
private static bool _explodeAtEndProbeRan;
private static UnityAction<Scene, Scene>? _sceneChangedRaw;
private static ManualLogSource? _capturedLog;
public static void Run(ManualLogSource log)
{
log.LogInfo((object)"[BringUpProbe] -- start --");
ProbeBellSurface(log);
DeferExplodeAtEndProbe(log);
log.LogInfo((object)"[BringUpProbe] -- end (B deferred to first scene) --");
}
private static void ProbeBellSurface(ManualLogSource log)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Expected O, but got Unknown
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(97, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[BringUpProbe] A: Grimoire.Generated.Bell wrapper compiled OK. ");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("InteropAssembly=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("Runtime");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", ");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("PinnedGameBuild=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("1.0.2.16727");
}
log.LogInfo(val);
log.LogInfo((object)"[BringUpProbe] A: typed surface available -> casterId, ExplosionCoroutine(ulong), EndLifetimeCoroutine()");
}
private static void DeferExplodeAtEndProbe(ManualLogSource log)
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
_capturedLog = log;
_sceneChangedRaw = DelegateSupport.ConvertDelegate<UnityAction<Scene, Scene>>((Delegate)new Action<Scene, Scene>(OnSceneChanged));
SceneManager.activeSceneChanged += _sceneChangedRaw;
Scene activeScene = SceneManager.GetActiveScene();
TryProbeOnce(log, ((Scene)(ref activeScene)).name);
}
private static void OnSceneChanged(Scene previous, Scene next)
{
if (_capturedLog != null && ((Scene)(ref next)).IsValid())
{
TryProbeOnce(_capturedLog, ((Scene)(ref next)).name);
}
}
private static void TryProbeOnce(ManualLogSource log, string sceneName)
{
//IL_016d: Unknown result type (might be due to invalid IL or missing references)
//IL_0174: Expected O, but got Unknown
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Expected O, but got Unknown
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Expected O, but got Unknown
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Expected O, but got Unknown
if (_explodeAtEndProbeRan)
{
return;
}
bool flag = default(bool);
try
{
IReadOnlyList<SpellVariantData> all = SpellVariantDataRepository.GetAll((SpellVariant)13);
BepInExInfoLogInterpolatedStringHandler val;
if (all.Count == 0)
{
val = new BepInExInfoLogInterpolatedStringHandler(87, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[BringUpProbe] B: scene='");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(sceneName);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' — GetAll(ExplodeAtEnd) still empty, will retry on next scene");
}
log.LogInfo(val);
return;
}
_explodeAtEndProbeRan = true;
val = new BepInExInfoLogInterpolatedStringHandler(63, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[BringUpProbe] B: scene='");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(sceneName);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' — GetAll(ExplodeAtEnd) -> ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(all.Count);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" match(es)");
}
log.LogInfo(val);
for (int i = 0; i < all.Count; i++)
{
SpellVariantData val2 = all[i].Unwrap();
val = new BepInExInfoLogInterpolatedStringHandler(53, 4, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[BringUpProbe] B: [");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(i);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("] Title='");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((StoreItemData)val2).TitleEntry ?? "<null>");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' ");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Desc='");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((StoreItemData)val2).DescriptionEntry ?? "<null>");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' ");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("RepeatAmount=");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(all[i].RepeatAmount);
}
log.LogInfo(val);
}
}
catch (Exception ex)
{
BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(55, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[BringUpProbe] B: deferred lookup threw on scene='");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(sceneName);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("' -> ");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<Exception>(ex);
}
log.LogError(val3);
}
}
}
internal static class KnellyBellSet
{
private static readonly HashSet<ulong> _casterIds = new HashSet<ulong>();
public static int Count => _casterIds.Count;
public static void Add(ulong casterId)
{
_casterIds.Add(casterId);
}
public static bool Contains(ulong casterId)
{
return _casterIds.Contains(casterId);
}
public static void Clear()
{
_casterIds.Clear();
}
}
[BepInPlugin("com.commkicks.grimoire.louderknelly", "Louder Knelly", "1.0.2")]
public sealed class Plugin : BasePlugin
{
public const string PluginId = "com.commkicks.grimoire.louderknelly";
private const TsbCharacterClass MOD_CLASS = 4;
private const TsbSkinId MOD_SKIN = 1;
private const int defaultValue = 3;
private static ConfigEntry<int>? _movementSpeedPercent;
private static ConfigEntry<bool>? _enabled;
private static ConfigEntry<bool>? _verboseLogging;
internal static ConfigEntry<bool>? EnabledEntry => _enabled;
internal static bool IsEnabled => _enabled?.Value ?? false;
internal static bool VerboseLogging
{
get
{
ConfigEntry<bool>? verboseLogging = _verboseLogging;
if (verboseLogging == null)
{
return false;
}
return !verboseLogging.Value;
}
}
internal static int MovementSpeedPercent => _movementSpeedPercent?.Value ?? 3;
public override void Load()
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Expected O, but got Unknown
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Expected O, but got Unknown
//IL_0167: 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_0183: Expected O, but got Unknown
ManualLogSource log = ((BasePlugin)this).Log;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(48, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[LouderKnelly] Load — registering build for (");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<TsbCharacterClass>((TsbCharacterClass)4);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(", ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<TsbSkinId>((TsbSkinId)1);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")");
}
log.LogInfo(val);
Bootstrap.Run((BasePlugin)(object)this);
_enabled = ((BasePlugin)this).Config.Bind<bool>("LouderKnelly", "Enabled", true, "Master toggle for the Louder Knelly mod. When OFF, Knelly plays vanilla.");
_verboseLogging = ((BasePlugin)this).Config.Bind<bool>("LouderKnelly", "VerboseLogging", false, "Per-spawn diagnostic logging. Off for player installs. Turn on when debugging why a bell didn't explode or why the build callback didn't fire.");
_movementSpeedPercent = ((BasePlugin)this).Config.Bind<int>("LouderKnelly", "MovementSpeedPercent", 3, new ConfigDescription("Bonus movement speed granted to BellMage (Knelly) on spawn. Reads as percent-points on the in-run movement-speed tracker. 0 = vanilla, 3 = +3% (default), 100 = +100% (effectively 2x), 300 = +300% (4x). Changes take effect on the next spawn — die or start a new run to feel a new value.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 300), Array.Empty<object>()));
TsbSettingsMenu.RegisterSection("Louder Knelly", (Action<SettingsSection>)delegate(SettingsSection section)
{
section.AddToggle(_enabled, "Louder Knelly").AddSlider(_movementSpeedPercent, "Bonus Move Speed (%)").DependsOn(_enabled);
});
_enabled.SettingChanged += delegate
{
SpellCardDescriptionPatch.RefreshLiveVisualizers();
};
_movementSpeedPercent.SettingChanged += delegate
{
SpellCardDescriptionPatch.RefreshLiveVisualizers();
};
BellExplodeOnExpirePatch.Subscribe();
SpellCardDescriptionPatch.Subscribe();
BringUpProbe.Run(((BasePlugin)this).Log);
Players.Spawned += delegate(PlayerReskinContext ctx)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Expected O, but got Unknown
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
if (VerboseLogging)
{
ManualLogSource log5 = ((BasePlugin)this).Log;
bool flag4 = default(bool);
BepInExInfoLogInterpolatedStringHandler val5 = new BepInExInfoLogInterpolatedStringHandler(74, 4, ref flag4);
if (flag4)
{
((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("[LouderKnelly] Players.Spawned fired: ");
((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("class=");
((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<TsbCharacterClass>(ctx.CharacterClass);
((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(", skin=");
((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<TsbSkinId>(ctx.SkinId);
((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(", ");
((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("identity=");
((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<string>((ctx.Identity == null) ? "null" : "present");
((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(", ");
((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("renderers=");
((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<int>(ctx.Renderers.Length);
}
log5.LogInfo(val5);
}
};
CharacterBuild val2 = new CharacterBuild();
val2.set_Custom((Action<BuildApplyContext>)delegate(BuildApplyContext ctx)
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Expected O, but got Unknown
//IL_0049: 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_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Expected O, but got Unknown
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_0103: Unknown result type (might be due to invalid IL or missing references)
ConfigEntry<bool>? enabled = _enabled;
bool flag3 = default(bool);
if (enabled == null || !enabled.Value)
{
if (VerboseLogging)
{
ManualLogSource log3 = ((BasePlugin)this).Log;
BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(77, 2, ref flag3);
if (flag3)
{
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[LouderKnelly] Custom callback fired for ");
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("(");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<TsbCharacterClass>(ctx.CharacterClass);
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", ");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<TsbSkinId>(ctx.SkinId);
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("): disabled, skipping all effects");
}
log3.LogInfo(val4);
}
}
else
{
ulong num = ctx.Identity.IGameplayPlayerIdentity_get_OwnerClientId();
KnellyBellSet.Add(num);
int num2 = _movementSpeedPercent?.Value ?? 4;
if (num2 > 0)
{
ctx.Stats.AddCharacterImprovement((StatType)7, (float)num2, (StatModifiersType)0);
}
if (VerboseLogging)
{
ManualLogSource log4 = ((BasePlugin)this).Log;
BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(112, 6, ref flag3);
if (flag3)
{
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[LouderKnelly] Custom callback fired for ");
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("(");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<TsbCharacterClass>(ctx.CharacterClass);
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", ");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<TsbSkinId>(ctx.SkinId);
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("): ");
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("ownerClientId=");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<ulong>(num);
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", ");
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("MovementSpeed +");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(num2);
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("% (passed ");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(num2);
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("f), ");
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("KnellyBellSet.Count=");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(KnellyBellSet.Count);
}
log4.LogInfo(val4);
}
}
});
BuildRegistry.Register((TsbCharacterClass)4, (TsbSkinId)1, val2);
TsbEvents.SceneChanged += delegate(TsbScene scene)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
if (KnellyBellSet.Count > 0)
{
if (VerboseLogging)
{
ManualLogSource log2 = ((BasePlugin)this).Log;
bool flag2 = default(bool);
BepInExInfoLogInterpolatedStringHandler val3 = new BepInExInfoLogInterpolatedStringHandler(58, 2, ref flag2);
if (flag2)
{
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[LouderKnelly] scene='");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(((TsbScene)(ref scene)).RawName);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("': clearing KnellyBellSet (");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(KnellyBellSet.Count);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" entries)");
}
log2.LogInfo(val3);
}
KnellyBellSet.Clear();
}
};
((BasePlugin)this).Log.LogInfo((object)"[LouderKnelly] Build registered. Pick Knelly to verify.");
}
}
internal static class SpellCardDescriptionPatch
{
private const string ExpireBulletText = "Spell explodes when its lifetime expires.";
private const string LocTable = "Localization_Strings";
private const string ExpireMarker = "LouderKnellyExplodeOnExpireBullet";
private const string MoveSpeedMarker = "LouderKnellyMoveSpeedBullet";
private static CharacterUIVisualizer? _liveCharacterVisualizer;
private static SpellUIVisualizer? _liveSpellVisualizer;
internal static void Subscribe()
{
TsbInfoPanels.SpellInfoSkipVote += OnSpellInfoSkipVote;
TsbInfoPanels.Subscribe((TsbSpellType)4, (Action<SpellInfoVisualizedArgs>)OnBellSpellInfoVisualized);
TsbInfoPanels.Subscribe((TsbCharacterClass)4, (Action<CharacterInfoVisualizedArgs>)OnBellMageCharacterInfoVisualized);
}
private static void OnSpellInfoSkipVote(SpellInfoSkipVoteArgs args)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Invalid comparison between Unknown and I4
if (args.IsCharacterInfoPanelSurface && (int)args.SpellType == 4 && (Object)(object)args.Visualizer.CurrentSpellData == (Object)(object)SpellData.op_Implicit(args.SpellData))
{
args.SkipVanillaRebuild = true;
}
}
private static void OnBellSpellInfoVisualized(SpellInfoVisualizedArgs args)
{
if (args.IsCharacterInfoPanelSurface)
{
_liveSpellVisualizer = args.Visualizer.Unwrap();
if (Plugin.IsEnabled)
{
ApplySpellBullets(args.Visualizer);
}
}
}
private static void OnBellMageCharacterInfoVisualized(CharacterInfoVisualizedArgs args)
{
_liveCharacterVisualizer = args.Visualizer.Unwrap();
if (Plugin.IsEnabled)
{
ApplyTraitBullets(args.Visualizer);
}
}
public static void RefreshLiveVisualizers()
{
try
{
if ((Object)(object)_liveCharacterVisualizer == (Object)null)
{
_liveCharacterVisualizer = null;
}
else if (Plugin.IsEnabled)
{
ApplyTraitBullets(CharacterUIVisualizer.op_Implicit(_liveCharacterVisualizer));
}
else
{
DestroyMarkers(CharacterUIVisualizer.op_Implicit(_liveCharacterVisualizer).statEntryParent);
}
if ((Object)(object)_liveSpellVisualizer == (Object)null)
{
_liveSpellVisualizer = null;
}
else if (Plugin.IsEnabled)
{
ApplySpellBullets(SpellUIVisualizer.op_Implicit(_liveSpellVisualizer));
}
else
{
DestroyMarkers(SpellUIVisualizer.op_Implicit(_liveSpellVisualizer).statEntryParent);
}
}
catch (Exception ex)
{
GrimoireLogSource source = Log.Source;
if (source != null)
{
source.LogError((object)("[LouderKnelly] RefreshLiveVisualizers threw: " + ex.Message));
}
}
}
private static void ApplyTraitBullets(CharacterUIVisualizer wrapped)
{
Transform statEntryParent = wrapped.statEntryParent;
if ((Object)(object)statEntryParent == (Object)null)
{
return;
}
DestroyMarkersByName(statEntryParent, "LouderKnellyMoveSpeedBullet");
int movementSpeedPercent = Plugin.MovementSpeedPercent;
if (movementSpeedPercent <= 0)
{
return;
}
GameObject statEntryPrefab = wrapped.statEntryPrefab;
if (!((Object)(object)statEntryPrefab == (Object)null))
{
GameObject obj = Object.Instantiate<GameObject>(statEntryPrefab, statEntryParent);
((Object)obj).name = "LouderKnellyMoveSpeedBullet";
obj.SetActive(true);
TextMeshProUGUI componentInChildren = obj.GetComponentInChildren<TextMeshProUGUI>(true);
if ((Object)(object)componentInChildren != (Object)null)
{
string value = TsbLoc.Resolve("Localization_Strings", "CharacterProperty_Increased_MovementSpeed", "Movement speed");
((TMP_Text)componentInChildren).text = $"+{movementSpeedPercent}% {value}";
}
}
}
private static void ApplySpellBullets(SpellUIVisualizer wrapped)
{
Transform statEntryParent = wrapped.statEntryParent;
if ((Object)(object)statEntryParent == (Object)null)
{
return;
}
DestroyMarkersByName(statEntryParent, "LouderKnellyExplodeOnExpireBullet");
wrapped.CreateStatEntry("Spell explodes when its lifetime expires.");
if (statEntryParent.childCount > 0)
{
Transform child = statEntryParent.GetChild(statEntryParent.childCount - 1);
if ((Object)(object)child != (Object)null)
{
((Object)((Component)child).gameObject).name = "LouderKnellyExplodeOnExpireBullet";
}
}
}
private static void DestroyMarkers(Transform statParent)
{
if (!((Object)(object)statParent == (Object)null))
{
DestroyMarkersByName(statParent, "LouderKnellyMoveSpeedBullet");
DestroyMarkersByName(statParent, "LouderKnellyExplodeOnExpireBullet");
}
}
private static void DestroyMarkersByName(Transform statParent, string markerName)
{
for (int num = statParent.childCount - 1; num >= 0; num--)
{
Transform child = statParent.GetChild(num);
if ((Object)(object)child != (Object)null && ((Object)child).name == markerName)
{
Object.Destroy((Object)(object)((Component)child).gameObject);
}
}
}
}
}