Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of HaldorExpansion v1.0.0
BepInEx/plugins/aveasura-HaldorExpansion/HaldorExpansion.dll
Decompiled 2 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("HaldorExpansion")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("aveasura")] [assembly: AssemblyProduct("HaldorExpansion")] [assembly: AssemblyCopyright("Copyright © aveasura 2026")] [assembly: AssemblyTrademark("aveasura")] [assembly: ComVisible(false)] [assembly: Guid("8A5C36D6-1908-4277-91DF-24E5D1B9B7BA")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace HaldorExpansion { [BepInPlugin("aveasura.haldor.expansion", "Haldor Expansion", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class HaldorExpansionPlugin : BaseUnityPlugin { private sealed class CestusState { public Player Player; public float Charge; public float ShieldRemaining; public float ShieldMax; public float ShieldDecayPerTick; public int ShieldTicksLeft; public float CooldownUntil; public bool IsCasting; public float InputLockedUntil; public Coroutine ShieldRoutine; public Coroutine CastRoutine; public readonly List<AudioSource> PreparedExplosionAudios = new List<AudioSource>(); public float LastChargeGainTime; public Coroutine ChargeDecayRoutine; public float LastObservedHealth; public float LastObservedMaxHealth; public bool HasObservedHealth; public bool WasEquippedLastFrame; public bool ForceHideHudBar; public float LastSyncedShieldRemaining = -1f; public float LastSyncedShieldMax = -1f; public bool LastSyncedShieldActive; } private sealed class CestusAnimatorSpeedState { public bool Applied; public float LastBaseSpeed = 1f; public float LastAppliedSpeed = 1f; } [HarmonyPatch(typeof(CharacterAnimEvent), "CustomFixedUpdate")] private static class CestusAnimatorSpeedPatch { private static readonly FieldInfo CurrentAttackField = AccessTools.Field(typeof(Humanoid), "m_currentAttack"); private static void Postfix(Character ___m_character, Animator ___m_animator) { if ((Object)(object)___m_character == (Object)null || (Object)(object)___m_animator == (Object)null) { return; } Player val = (Player)(object)((___m_character is Player) ? ___m_character : null); if ((Object)(object)val == (Object)null) { return; } int instanceID = ((Object)___m_animator).GetInstanceID(); if (!CestusAnimatorStates.TryGetValue(instanceID, out var value)) { value = new CestusAnimatorSpeedState(); CestusAnimatorStates[instanceID] = value; } float speed = ___m_animator.speed; float num = speed; if (value.Applied && Mathf.Abs(speed - value.LastAppliedSpeed) < 0.0001f) { num = value.LastBaseSpeed; } ItemData currentWeapon = ((Humanoid)val).GetCurrentWeapon(); Attack val2 = null; if (CurrentAttackField != null) { object? value2 = CurrentAttackField.GetValue(val); val2 = (Attack)((value2 is Attack) ? value2 : null); } if (!((Character)val).InAttack() || !IsCestusWeapon(currentWeapon) || val2 == null || string.IsNullOrEmpty(val2.m_attackAnimation) || val2.m_attackAnimation.IndexOf("unarmed", StringComparison.OrdinalIgnoreCase) < 0) { value.Applied = false; value.LastBaseSpeed = speed; value.LastAppliedSpeed = speed; return; } float num2 = Mathf.Clamp(1.9f, 0.01f, 10f); float num3 = num * num2; if (Mathf.Abs(___m_animator.speed - num3) > 0.0001f) { ___m_animator.speed = num3; DebugLog("Cestus animator speed applied: " + num.ToString("0.###") + " -> " + num3.ToString("0.###")); } value.Applied = true; value.LastBaseSpeed = num; value.LastAppliedSpeed = num3; } } [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] private static class CestusMaxHealthPatch { private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr) { if (!((Object)(object)__instance == (Object)null)) { if (HasEquippedCestus(__instance)) { hp += 30f; } DebugLog($"[HaldorExpansion] Cestus HP bonus: equipped={HasEquippedCestus(__instance)}, hpBeforeBonus={hp}"); } } } [HarmonyPatch(typeof(Player), "GetBodyArmor")] private static class CestusArmorPenaltyPatch { private static void Postfix(Player __instance, ref float __result) { if (!((Object)(object)__instance == (Object)null)) { bool flag = HasEquippedCestus(__instance); if (flag) { __result = Mathf.Max(0f, __result - 15f); } DebugLog($"[HaldorExpansion] Cestus armor penalty: equipped={flag}, armorAfterPenalty={__result}"); } } } private sealed class DelayedDoomDotState { public Player Player; public float RemainingDamage; public int TicksLeft; public Coroutine Routine; } [HarmonyPatch(typeof(Player), "GetTotalFoodValue")] private static class PitKingChestMaxHealthPatch { private static void Postfix(Player __instance, ref float hp, ref float stamina, ref float eitr) { if (!((Object)(object)__instance == (Object)null)) { bool flag = HasPitKingChestEquipped(__instance); if (flag) { hp += 70f; } DebugLog($"[HaldorExpansion] Pit King chest HP bonus: equipped={flag}, hpAfterBonus={hp:0.##}"); } } } [CompilerGenerated] private sealed class <CestusCastRoutine>d__67 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public CestusState state; public float shieldAmount; private Player <player>5__2; private long <playerId>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CestusCastRoutine>d__67(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <player>5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Expected O, but got Unknown bool result; try { switch (<>1__state) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; if (state == null) { result = false; } else { <player>5__2 = state.Player; <playerId>5__3 = (((Object)(object)<player>5__2 != (Object)null) ? GetCestusStateKey(<player>5__2) : 0); state.IsCasting = true; state.InputLockedUntil = Time.time + 1.05f; state.PreparedExplosionAudios.Clear(); <>1__state = -3; if ((Object)(object)<player>5__2 == (Object)null || ((Character)<player>5__2).IsDead()) { result = false; break; } <player>5__2.StartEmote("point", true); ClearHumanoidBlockState((Humanoid)(object)<player>5__2); state.ShieldRemaining = shieldAmount; state.ShieldMax = shieldAmount; state.ShieldTicksLeft = 40; state.ShieldDecayPerTick = shieldAmount / 40f; SyncCestusShieldState(<player>5__2, state, force: true); if (state.ShieldRoutine != null) { ((MonoBehaviour)Instance).StopCoroutine(state.ShieldRoutine); state.ShieldRoutine = null; } PlayCestusCastFx(<player>5__2, state, shieldAmount); PlayCestusCastSfx(<player>5__2); <>2__current = (object)new WaitForSeconds(1.05f); <>1__state = 1; result = true; } goto end_IL_0000; case 1: <>1__state = -3; if ((Object)(object)<player>5__2 == (Object)null || ((Character)<player>5__2).IsDead()) { result = false; break; } state.ShieldRoutine = ((MonoBehaviour)Instance).StartCoroutine(CestusShieldRoutine(state)); TriggerCestusNova(<player>5__2, shieldAmount); PlayPreparedCestusExplosionAudio(state); DebugLog("[HaldorExpansion] Cestus cast resolved: " + $"shield={shieldAmount:0.##}, " + $"duration={1.05f:0.##}"); <>m__Finally1(); result = false; goto end_IL_0000; } <>m__Finally1(); end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; state.IsCasting = false; state.InputLockedUntil = 0f; state.CastRoutine = null; if (<playerId>5__3 != 0L && ActiveCestusStates.TryGetValue(<playerId>5__3, out var value) && value == state) { value.IsCasting = false; value.InputLockedUntil = 0f; value.CastRoutine = null; } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <CestusChargeDecayRoutine>d__63 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public CestusState state; private long <playerId>5__2; private float <wait>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CestusChargeDecayRoutine>d__63(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>1__state = -2; } private bool MoveNext() { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown bool result; try { int num = <>1__state; if (num != 0) { if (num == 1) { <>1__state = -3; Player player = state.Player; if ((Object)(object)player == (Object)null || ((Character)player).IsDead()) { result = false; } else { if (!(state.Charge <= 0.001f)) { if (!state.IsCasting && !(state.ShieldRemaining > 0.001f) && !(Time.time < state.CooldownUntil) && !(Time.time < state.LastChargeGainTime + 7f)) { float charge = state.Charge; float num2 = 6f * <wait>5__3; state.Charge = Mathf.Max(0f, state.Charge - num2); DebugLog("[HaldorExpansion] Cestus charge decay: " + $"before={charge:0.##}, " + $"decay={num2:0.##}, " + $"after={state.Charge:0.##}"); if (state.Charge <= 0.001f) { state.Charge = 0f; result = false; goto IL_01dc; } } goto IL_0078; } result = false; } goto IL_01dc; } result = false; } else { <>1__state = -1; if (state != null) { <playerId>5__2 = (((Object)(object)state.Player != (Object)null) ? GetCestusStateKey(state.Player) : 0); <wait>5__3 = Mathf.Max(0.02f, 0.2f); <>1__state = -3; goto IL_0078; } result = false; } goto end_IL_0000; IL_01dc: <>m__Finally1(); goto end_IL_0000; IL_0078: <>2__current = (object)new WaitForSeconds(<wait>5__3); <>1__state = 1; result = true; end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; state.ChargeDecayRoutine = null; if (<playerId>5__2 != 0L && ActiveCestusStates.TryGetValue(<playerId>5__2, out var value) && value == state) { value.ChargeDecayRoutine = null; } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <CestusShieldRoutine>d__82 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public CestusState state; private float <waitPerTick>5__2; private long <playerId>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CestusShieldRoutine>d__82(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>1__state = -2; } private bool MoveNext() { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown bool result; try { int num = <>1__state; if (num != 0) { if (num != 1) { result = false; } else { <>1__state = -3; Player player = state.Player; if ((Object)(object)player == (Object)null || ((Character)player).IsDead()) { result = false; } else if (state.ShieldRemaining <= 0.001f || state.ShieldTicksLeft <= 0) { result = false; } else { float num2 = Mathf.Min(state.ShieldRemaining, state.ShieldDecayPerTick); state.ShieldRemaining = Mathf.Max(0f, state.ShieldRemaining - num2); state.ShieldTicksLeft--; if (state.ShieldRemaining <= 0.001f) { ClearCestusShieldState(player, state, stopRoutine: false, syncNow: true); } else { SyncCestusShieldState(player, state); } DebugLog("[HaldorExpansion] Cestus shield decay: " + $"decay={num2:0.##}, " + $"remaining={state.ShieldRemaining:0.##}, " + $"ticksLeft={state.ShieldTicksLeft}"); if (!(state.ShieldRemaining <= 0.001f)) { goto IL_006b; } result = false; } <>m__Finally1(); } } else { <>1__state = -1; if (state != null) { <waitPerTick>5__2 = 0.15f; <playerId>5__3 = (((Object)(object)state.Player != (Object)null) ? GetCestusStateKey(state.Player) : 0); <>1__state = -3; goto IL_006b; } result = false; } goto end_IL_0000; IL_006b: <>2__current = (object)new WaitForSeconds(<waitPerTick>5__2); <>1__state = 1; result = true; end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; state.ShieldRoutine = null; ClearCestusShieldState(state.Player, state, stopRoutine: false, syncNow: true); if (<playerId>5__3 != 0L && ActiveCestusStates.TryGetValue(<playerId>5__3, out var value) && value == state) { value.ShieldRoutine = null; ClearCestusShieldState(value.Player, value, stopRoutine: false, syncNow: true); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <DelayedDoomRoutine>d__173 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public DelayedDoomDotState state; private float <waitPerTick>5__2; private int <playerId>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedDoomRoutine>d__173(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>1__state = -2; } private bool MoveNext() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown bool result; try { int num = <>1__state; if (num != 0) { if (num != 1) { result = false; } else { <>1__state = -3; Player player = state.Player; if ((Object)(object)player == (Object)null) { DebugLog("[HaldorExpansion] Delayed Doom routine stop: player null"); result = false; } else if (((Character)player).IsDead()) { DebugLog("[HaldorExpansion] Delayed Doom routine stop: player dead, " + GetCestusDebugPlayerTag(player)); result = false; } else if (state.RemainingDamage <= 0f || state.TicksLeft <= 0) { DebugLog("[HaldorExpansion] Delayed Doom routine stop: exhausted, " + $"remaining={state.RemainingDamage:0.##}, " + $"ticksLeft={state.TicksLeft}, " + GetCestusDebugPlayerTag(player)); result = false; } else { float num2 = state.RemainingDamage / (float)state.TicksLeft; num2 = Mathf.Max(0f, num2); state.RemainingDamage = Mathf.Max(0f, state.RemainingDamage - num2); state.TicksLeft--; DebugLog("[HaldorExpansion] Delayed Doom pooled tick: " + $"tick={num2:0.##}, " + $"remaining={state.RemainingDamage:0.##}, " + $"ticksLeft={state.TicksLeft}, " + GetCestusDebugPlayerTag(player)); if (!ApplyDelayedDoomHealthTick(player, num2)) { result = false; } else { if (!(state.RemainingDamage <= 0.001f)) { goto IL_006a; } result = false; } } <>m__Finally1(); } } else { <>1__state = -1; if (state != null) { <waitPerTick>5__2 = 0.5f; <playerId>5__3 = (((Object)(object)state.Player != (Object)null) ? ((Object)state.Player).GetInstanceID() : 0); <>1__state = -3; goto IL_006a; } result = false; } goto end_IL_0000; IL_006a: <>2__current = (object)new WaitForSeconds(<waitPerTick>5__2); <>1__state = 1; result = true; end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if ((Object)(object)state.Player != (Object)null) { DebugLog("[HaldorExpansion] Delayed Doom routine finally: " + $"remainingBeforeClear={state.RemainingDamage:0.##}, " + $"ticksLeftBeforeClear={state.TicksLeft}, " + GetCestusDebugPlayerTag(state.Player)); } state.Routine = null; state.RemainingDamage = 0f; state.TicksLeft = 0; if (<playerId>5__3 != 0 && ActiveDelayedDoomDots.TryGetValue(<playerId>5__3, out var value) && value == state) { ActiveDelayedDoomDots.Remove(<playerId>5__3); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static readonly HashSet<string> CestusItemKeys = new HashSet<string> { "$item_weapon_gritcestus" }; internal const float CestusSetBonusMultiplier = 1.5f; internal static ConfigEntry<KeyCode> CestusAbilityKeyConfig; internal static ButtonConfig CestusAbilityButton; internal const float CestusChargeMax = 100f; internal const float CestusShieldMaxHpRatio = 0.4f; internal const float CestusShieldMinFlat = 20f; internal const float CestusShieldDuration = 6f; internal const int CestusShieldTicks = 40; internal const float CestusCooldown = 15f; private const string CestusShieldZdoRemainingKey = "he_cestus_shield_remaining"; private const string CestusShieldZdoMaxKey = "he_cestus_shield_max"; private const string CestusShieldZdoActiveKey = "he_cestus_shield_active"; internal const string CestusActivationEmote = "point"; internal const float CestusCastDuration = 1.05f; internal const float CestusNovaDamageMultiplier = 2.7f; internal const float CestusNovaRadius = 4f; internal const float CestusNovaPushForce = 20f; internal const string CestusCastFxPrefabName = "vfx_StaminaUpgrade"; internal const string CestusCastSfxPrefabName = ""; internal const float CestusCastFxAudioPitch = 1.25f; internal const float CestusCastFxAudioStartOffset = 0.08f; internal const int CestusCastFxAmount = 2; internal const float CestusCastFxForwardOffset = 1f; internal const float CestusCastFxUpOffset = 0.8f; internal const float CestusCastFxBaseScale = 1f; internal const float CestusCastFxMaxScale = 1.6f; internal const float CestusCastFxReferenceShield = 100f; internal const float CestusCastFxPlaybackSpeed = 2f; internal const float CestusChargePerPostArmorDamage = 0.8f; internal const float CestusChargeDecayDelay = 7f; internal const float CestusChargeDecayPerSecond = 6f; internal const float CestusChargeDecayTickInterval = 0.2f; private static readonly Dictionary<long, CestusState> ActiveCestusStates = new Dictionary<long, CestusState>(); private static Image CestusShieldOverlayImage; private static RectTransform CestusShieldOverlayRect; private static RectTransform CestusShieldReferenceRect; private static Text CestusShieldText; private static RectTransform CestusShieldTextRect; private static bool CestusShieldOverlayLoggedMissing; private static bool _adrenalineReflectionDumped; private static readonly Dictionary<int, CestusAnimatorSpeedState> CestusAnimatorStates = new Dictionary<int, CestusAnimatorSpeedState>(); internal const string GritCestusPrefabName = "Bone_crushers"; private const string CestusEffectNameKey = "$se_weapon_gritcestus"; private const string CestusEffectDescKey = "$se_weapon_gritcestus_desc"; internal const string GritCestusSourcePrefab = "FistFenrirClaw"; internal const int GritCestusPrice = 2500; private const string CestusItemKey = "$item_weapon_gritcestus"; private const string CestusItemDescKey = "$item_weapon_gritcestus_desc"; private const float GritCestusWeight = 5f; private const int GritCestusMaxQuality = 1; private const float GritCestusMaxDurability = 1800f; private const float GritCestusDurabilityPerLevel = 0f; private const float GritCestusBluntDamage = 24f; private const float GritCestusLightningDamage = 4f; internal const float GritCestusBonusMaxHealth = 30f; private const float GritCestusPrimaryStaggerMultiplier = 1.35f; private const float GritCestusSecondaryStaggerMultiplier = 2.2f; private const float GritCestusAttackSpeedMultiplier = 1.9f; private const float GritCestusArmorPenalty = 15f; private const float GritCestusBlockPower = 2f; private const float GritCestusBlockPowerPerLevel = 0f; private const float GritCestusDeflectionForce = 15f; private const float GritCestusDeflectionForcePerLevel = 0f; private const float GritCestusTimedBlockBonus = 2f; internal static GameObject GritCestusPrefab; internal static ItemDrop GritCestusItemDrop; private const string ModGuid = "aveasura.haldor.expansion"; private const string ModName = "Haldor Expansion"; private const string ModVersion = "1.0.0"; internal static ManualLogSource Log; internal static HaldorExpansionPlugin Instance; private static readonly bool DebugLogging = false; internal const string DelayedDoomChestPrefabName = "ArmorDelayedDoomChest"; internal const string DelayedDoomChestSourcePrefab = "ArmorPaddedCuirass"; internal const int DelayedDoomChestPrice = 4000; internal const float DelayedDoomChestFoodRegenBonus = 5f; internal static GameObject DelayedDoomChestPrefab; internal static ItemDrop DelayedDoomChestItemDrop; private static readonly HashSet<string> DelayedDoomItemKeys = new HashSet<string> { "$item_chest_delayeddoom" }; internal const float DelayedDoomTriggerRatio = 0.5f; internal const float DelayedDoomImmediateRatio = 0.5f; internal const float DelayedDoomDebtRatio = 0.7f; internal const float DelayedDoomDuration = 6f; internal const int DelayedDoomTicks = 12; private static readonly HashSet<int> DelayedDoomInternalDamageVictims = new HashSet<int>(); private static readonly Dictionary<int, DelayedDoomDotState> ActiveDelayedDoomDots = new Dictionary<int, DelayedDoomDotState>(); private const string EmbeddedIconPrefix = "HaldorExpansion.Assets.Icons."; internal const string PitKingChestPrefabName = "ArmorPitKingChest"; internal const string PitKingChestSourcePrefab = "ArmorMageChest"; internal const int PitKingChestPrice = 4000; internal const float PitKingChestBonusMaxHealth = 70f; private const string PitKingChestItemKey = "$item_chest_pitking"; private const string PitKingChestItemDescKey = "$item_chest_pitking_desc"; private const string PitKingChestEffectNameKey = "$se_pitking_vigor"; private const string PitKingChestEffectDescKey = "$se_pitking_vigor_desc"; private const string SteelHeartSetNameKey = "$itemset_steelheart"; private const string SteelHeartSetDescKey = "$itemset_steelheart_desc"; private static readonly HashSet<string> PitKingChestItemKeys = new HashSet<string> { "$item_chest_pitking" }; internal static GameObject PitKingChestPrefab; internal static ItemDrop PitKingChestItemDrop; internal const string RingPrefabName = "BrisingamenRing"; internal const int RingPrice = 1600; internal static GameObject RingPrefab; internal static ItemDrop RingItemDrop; private static bool _ringReadyLogged; internal const string ShadowCrossbowPrefabName = "CrossbowSilentHunt"; internal const string ShadowCrossbowSourcePrefab = "CrossbowArbalest"; internal const int ShadowCrossbowPrice = 2500; internal const string ShadowCrossbowItemKey = "$item_crossbow_silenthunt"; internal const string ShadowCrossbowItemDescKey = "$item_crossbow_silenthunt_desc"; internal const float ShadowCrossbowBasePierceDamage = 210f; internal const float ShadowCrossbowMovementModifier = -0.35f; internal const float ShadowCrossbowBackstabBonus = 6f; internal static GameObject ShadowCrossbowPrefab; internal static ItemDrop ShadowCrossbowItemDrop; private const int DefaultTrophyValue = 10; private static readonly Dictionary<string, int> ExtraSellableItems = new Dictionary<string, int> { { "SurtlingCore", 30 }, { "BlackCore", 80 }, { "MoltenCore", 130 } }; private static readonly Dictionary<string, int> TrophyValueOverrides = new Dictionary<string, int> { { "TrophyDeer", 15 }, { "TrophyBoar", 15 }, { "TrophyNeck", 25 }, { "TrophyEikthyr", 70 }, { "TrophyGreydwarf", 15 }, { "TrophySkeleton", 15 }, { "TrophyGreydwarfShaman", 20 }, { "TrophyGhost", 25 }, { "TrophyGreydwarfBrute", 20 }, { "TrophyBjorn", 50 }, { "TrophyFrostTroll", 50 }, { "TrophySkeletonPoison", 50 }, { "TrophySkeletonHildir", 80 }, { "TrophyTheElder", 100 }, { "TrophySerpent", 500 }, { "TrophyBonemawSerpent", 500 }, { "TrophyBlob", 15 }, { "TrophyDraugr", 15 }, { "TrophyLeech", 15 }, { "TrophySurtling", 15 }, { "TrophyDraugrElite", 30 }, { "TrophyWraith", 35 }, { "TrophyAbomination", 75 }, { "TrophyKvastur", 80 }, { "TrophyBonemass", 150 }, { "TrophyWolf", 15 }, { "TrophyHatchling", 15 }, { "TrophyUlv", 20 }, { "TrophyFenring", 25 }, { "TrophyCultist", 40 }, { "TrophySGolem", 70 }, { "TrophyCultist_Hildir", 80 }, { "TrophyDragonQueen", 200 }, { "TrophyDeathsquito", 15 }, { "TrophyGoblin", 15 }, { "TrophyGrowth", 15 }, { "TrophyBjornUndead", 50 }, { "TrophyLox", 35 }, { "TrophyGoblinShaman", 30 }, { "TrophyGoblinBrute", 70 }, { "TrophyGoblinBruteBrosShaman", 80 }, { "TrophyGoblinBruteBrosBrute", 80 }, { "TrophyGoblinKing", 350 }, { "TrophySeeker", 20 }, { "TrophyTick", 20 }, { "TrophyDvergr", 20 }, { "TrophyHare", 20 }, { "TrophyGjall", 70 }, { "TrophySeekerBrute", 80 }, { "TrophySeekerQueen", 500 }, { "TrophyCharredArcher", 20 }, { "TrophyVolture", 20 }, { "TrophyAsksvin", 20 }, { "TrophyCharredMage", 25 }, { "TrophyCharredMelee", 25 }, { "TrophyMorgen", 100 }, { "TrophyFallenValkyrie", 120 }, { "TrophyFader", 1000 } }; private const float WoundedBeastCapeRegenWithDelayedDoomMultiplier = 0.5f; internal const string WoundedBeastCapePrefabName = "CapeWoundedBeast"; internal const string WoundedBeastCapeSourcePrefab = "CapeWolf"; internal const int WoundedBeastCapePrice = 2500; internal const string WoundedBeastCapeItemKey = "$item_cape_woundedbeast"; private const string WoundedBeastCapeItemDescKey = "$item_cape_woundedbeast_desc"; private const string WoundedBeastCapeEffectNameKey = "$se_cape_woundedbeast"; private const string WoundedBeastCapeEffectDescKey = "$se_cape_woundedbeast_desc"; internal const float WoundedBeastCapeIncomingDamageMultiplier = 1.15f; internal const float WoundedBeastCapeDotRegenSuppressDuration = 2f; private const float WoundedBeastCapeRegenTickInterval = 1f; internal static GameObject WoundedBeastCapePrefab; internal static ItemDrop WoundedBeastCapeItemDrop; private static readonly Dictionary<long, float> WoundedBeastCapeNextRegenTickTimes = new Dictionary<long, float>(); private static readonly Dictionary<long, float> WoundedBeastCapeRegenSuppressedUntil = new Dictionary<long, float>(); private static long GetCestusStateKey(Player player) { if ((Object)(object)player == (Object)null) { return 0L; } long playerID = player.GetPlayerID(); if (playerID != 0L) { return playerID; } return ((Object)player).GetInstanceID(); } private static CestusState GetOrCreateCestusState(Player player) { long cestusStateKey = GetCestusStateKey(player); if (!ActiveCestusStates.TryGetValue(cestusStateKey, out var value)) { value = new CestusState { Player = player, LastChargeGainTime = 0f, ChargeDecayRoutine = null, LastObservedHealth = ((Character)player).GetHealth(), LastObservedMaxHealth = ((Character)player).GetMaxHealth(), HasObservedHealth = true, WasEquippedLastFrame = false, ForceHideHudBar = false, Charge = 0f, ShieldRemaining = 0f, ShieldMax = 0f, ShieldDecayPerTick = 0f, ShieldTicksLeft = 0, CooldownUntil = 0f, IsCasting = false, InputLockedUntil = 0f, ShieldRoutine = null, CastRoutine = null }; ActiveCestusStates[cestusStateKey] = value; } value.Player = player; return value; } internal static bool HasCestusEquipped(Player player) { if ((Object)(object)player == (Object)null) { return false; } if (IsCestusWeapon(((Humanoid)player).GetCurrentWeapon())) { return true; } if (IsCestusWeapon(GetPlayerHandItem(player, "m_rightItem"))) { return true; } if (IsCestusWeapon(GetPlayerHandItem(player, "m_leftItem"))) { return true; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return false; } List<ItemData> allItems = inventory.GetAllItems(); if (allItems == null) { return false; } foreach (ItemData item in allItems) { if (item == null || !item.m_equipped) { continue; } if (IsCestusWeapon(item)) { return true; } if (item.m_shared != null) { string name = item.m_shared.m_name; if (!string.IsNullOrEmpty(name) && CestusItemKeys.Contains(name)) { return true; } } } return false; } internal static bool ShouldProcessCestusLocally(Player player) { if ((Object)(object)player != (Object)null && (Object)(object)Player.m_localPlayer != (Object)null) { return (Object)(object)player == (Object)(object)Player.m_localPlayer; } return false; } internal static string GetCestusDebugPlayerTag(Player player) { if ((Object)(object)player == (Object)null) { return "player=null"; } ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon(); ItemData playerHandItem = GetPlayerHandItem(player, "m_rightItem"); ItemData playerHandItem2 = GetPlayerHandItem(player, "m_leftItem"); bool flag = (Object)(object)player == (Object)(object)Player.m_localPlayer; ZNetView playerNView = GetPlayerNView(player); bool flag2 = (Object)(object)playerNView != (Object)null && playerNView.IsValid() && playerNView.IsOwner(); return "name=" + ((Object)player).name + ", " + $"local={flag}, " + $"owner={flag2}, " + $"pid={player.GetPlayerID()}, " + $"iid={((Object)player).GetInstanceID()}, " + "current=" + GetCestusItemDebugName(currentWeapon) + ", right=" + GetCestusItemDebugName(playerHandItem) + ", left=" + GetCestusItemDebugName(playerHandItem2); } private static ZNetView GetPlayerNView(Player player) { if ((Object)(object)player == (Object)null) { return null; } object? obj = typeof(Character).GetField("m_nview", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(player); return (ZNetView)((obj is ZNetView) ? obj : null); } private static bool IsPlayerNViewOwner(Player player) { ZNetView playerNView = GetPlayerNView(player); if ((Object)(object)playerNView != (Object)null && playerNView.IsValid()) { return playerNView.IsOwner(); } return false; } private static ZDO GetPlayerZdo(Player player) { ZNetView playerNView = GetPlayerNView(player); if (!((Object)(object)playerNView != (Object)null) || !playerNView.IsValid()) { return null; } return playerNView.GetZDO(); } internal static bool IsCestusShieldAuthorityRuntime(Player player) { if (!ShouldProcessCestusLocally(player)) { return false; } ZNetView playerNView = GetPlayerNView(player); if (!((Object)(object)playerNView == (Object)null) && playerNView.IsValid()) { return playerNView.IsOwner(); } return true; } internal static float GetSyncedCestusShieldRemaining(Player player) { ZDO playerZdo = GetPlayerZdo(player); if (playerZdo == null) { return 0f; } return Mathf.Max(0f, playerZdo.GetFloat("he_cestus_shield_remaining", 0f)); } internal static float GetSyncedCestusShieldMax(Player player) { ZDO playerZdo = GetPlayerZdo(player); if (playerZdo == null) { return 0f; } return Mathf.Max(0f, playerZdo.GetFloat("he_cestus_shield_max", 0f)); } internal static float GetCestusEffectiveShieldRemaining(Player player) { if ((Object)(object)player == (Object)null) { return 0f; } CestusState orCreateCestusState = GetOrCreateCestusState(player); return Mathf.Max(Mathf.Max(0f, orCreateCestusState.ShieldRemaining), GetSyncedCestusShieldRemaining(player)); } private static void SyncCestusShieldState(Player player, CestusState state, bool force = false) { if ((Object)(object)player == (Object)null || state == null || !IsPlayerNViewOwner(player)) { return; } float num = Mathf.Max(0f, state.ShieldRemaining); float num2 = Mathf.Max(0f, state.ShieldMax); bool flag = num > 0.001f; if (force || !(Mathf.Abs(state.LastSyncedShieldRemaining - num) <= 0.01f) || !(Mathf.Abs(state.LastSyncedShieldMax - num2) <= 0.01f) || state.LastSyncedShieldActive != flag) { ZDO playerZdo = GetPlayerZdo(player); if (playerZdo != null) { playerZdo.Set("he_cestus_shield_remaining", num); playerZdo.Set("he_cestus_shield_max", num2); playerZdo.Set("he_cestus_shield_active", flag); state.LastSyncedShieldRemaining = num; state.LastSyncedShieldMax = num2; state.LastSyncedShieldActive = flag; } } } private static void ClearCestusShieldState(Player player, CestusState state, bool stopRoutine, bool syncNow) { if (state != null) { if (stopRoutine && state.ShieldRoutine != null && (Object)(object)Instance != (Object)null) { ((MonoBehaviour)Instance).StopCoroutine(state.ShieldRoutine); state.ShieldRoutine = null; } state.ShieldRemaining = 0f; state.ShieldMax = 0f; state.ShieldDecayPerTick = 0f; state.ShieldTicksLeft = 0; if (syncNow) { SyncCestusShieldState(player, state, force: true); return; } state.LastSyncedShieldRemaining = -1f; state.LastSyncedShieldMax = -1f; state.LastSyncedShieldActive = false; } } private static ItemData GetPlayerHandItem(Player player, string fieldName) { if ((Object)(object)player == (Object)null || string.IsNullOrWhiteSpace(fieldName)) { return null; } object? obj = typeof(Humanoid).GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(player); return (ItemData)((obj is ItemData) ? obj : null); } private static string GetCestusItemDebugName(ItemData item) { if (item == null) { return "null"; } if ((Object)(object)item.m_dropPrefab != (Object)null && !string.IsNullOrWhiteSpace(((Object)item.m_dropPrefab).name)) { return ((Object)item.m_dropPrefab).name; } if (item.m_shared != null && !string.IsNullOrWhiteSpace(item.m_shared.m_name)) { return item.m_shared.m_name; } return "unknown"; } internal static bool HasFullCestusCharge(Player player) { if ((Object)(object)player == (Object)null) { return false; } return GetOrCreateCestusState(player).Charge >= 99.999f; } internal static float GetCestusCharge(Player player) { if ((Object)(object)player == (Object)null) { return 0f; } return Mathf.Clamp(GetOrCreateCestusState(player).Charge, 0f, 100f); } internal static bool ShouldMirrorCestusToAdrenaline(Player player) { if ((Object)(object)player == (Object)null) { return false; } CestusState orCreateCestusState = GetOrCreateCestusState(player); if (!HasCestusEquipped(player) && !(orCreateCestusState.Charge > 0.001f) && !(orCreateCestusState.ShieldRemaining > 0.001f)) { return orCreateCestusState.IsCasting; } return true; } internal static bool ShouldForceHideCestusHudBar(Player player) { if ((Object)(object)player == (Object)null) { return false; } CestusState orCreateCestusState = GetOrCreateCestusState(player); if (!HasCestusEquipped(player) && orCreateCestusState.ForceHideHudBar && orCreateCestusState.Charge <= 0.001f && orCreateCestusState.ShieldRemaining <= 0.001f) { return !orCreateCestusState.IsCasting; } return false; } internal static bool IsCestusShieldActive(Player player) { return GetCestusEffectiveShieldRemaining(player) > 0.001f; } internal static bool IsCestusCasting(Player player) { if ((Object)(object)player == (Object)null) { return false; } return GetOrCreateCestusState(player).IsCasting; } internal static bool IsCestusInputLocked(Player player) { if ((Object)(object)player == (Object)null) { return false; } CestusState orCreateCestusState = GetOrCreateCestusState(player); if (orCreateCestusState.IsCasting) { return Time.time < orCreateCestusState.InputLockedUntil; } return false; } internal static void UpdateCestusLocalEquipState(Player player) { if (ShouldProcessCestusLocally(player)) { CestusState orCreateCestusState = GetOrCreateCestusState(player); bool flag = HasCestusEquipped(player); if (flag) { orCreateCestusState.ForceHideHudBar = false; } else if (orCreateCestusState.WasEquippedLastFrame) { ResetCestusState(player, orCreateCestusState, "unequipped"); orCreateCestusState.ForceHideHudBar = true; } orCreateCestusState.WasEquippedLastFrame = flag; } } private static void ResetCestusState(Player player, CestusState state, string reason) { if (state != null) { if (state.ChargeDecayRoutine != null && (Object)(object)Instance != (Object)null) { ((MonoBehaviour)Instance).StopCoroutine(state.ChargeDecayRoutine); } if (state.ShieldRoutine != null && (Object)(object)Instance != (Object)null) { ((MonoBehaviour)Instance).StopCoroutine(state.ShieldRoutine); } if (state.CastRoutine != null && (Object)(object)Instance != (Object)null) { ((MonoBehaviour)Instance).StopCoroutine(state.CastRoutine); } state.ChargeDecayRoutine = null; state.ShieldRoutine = null; state.CastRoutine = null; state.Charge = 0f; state.LastChargeGainTime = 0f; ClearCestusShieldState(player, state, stopRoutine: false, syncNow: true); state.IsCasting = false; state.InputLockedUntil = 0f; if ((Object)(object)player != (Object)null) { state.LastObservedHealth = Mathf.Max(0f, ((Character)player).GetHealth()); state.HasObservedHealth = true; } DebugLog("[HaldorExpansion] Cestus state reset: reason=" + reason + ", " + GetCestusDebugPlayerTag(player)); } } internal static void UpdateCestusLocalDamageCharge(Player player) { if (!ShouldProcessCestusLocally(player)) { return; } CestusState orCreateCestusState = GetOrCreateCestusState(player); float num = Mathf.Max(0f, ((Character)player).GetHealth()); float num2 = Mathf.Max(0f, ((Character)player).GetMaxHealth()); if (!orCreateCestusState.HasObservedHealth) { orCreateCestusState.LastObservedHealth = num; orCreateCestusState.LastObservedMaxHealth = num2; orCreateCestusState.HasObservedHealth = true; return; } float lastObservedHealth = orCreateCestusState.LastObservedHealth; float lastObservedMaxHealth = orCreateCestusState.LastObservedMaxHealth; orCreateCestusState.LastObservedHealth = num; orCreateCestusState.LastObservedMaxHealth = num2; if (!HasCestusEquipped(player)) { return; } float num3 = lastObservedHealth - num; float num4 = Mathf.Max(0f, lastObservedMaxHealth - num2); float num5 = num3 - num4; if (num5 <= 0.05f) { return; } DebugLog("[HaldorExpansion] Observed local Cestus damage: " + GetCestusDebugPlayerTag(player) + ", " + $"prevHp={lastObservedHealth:0.##}, " + $"currentHp={num:0.##}, " + $"prevMaxHp={lastObservedMaxHealth:0.##}, " + $"currentMaxHp={num2:0.##}, " + $"effectiveDelta={num5:0.##}"); if (orCreateCestusState.ShieldRemaining > 0.001f && !((Character)player).IsDead()) { float num6 = Mathf.Min(orCreateCestusState.ShieldRemaining, num5); if (num6 > 0.001f) { orCreateCestusState.ShieldRemaining = Mathf.Max(0f, orCreateCestusState.ShieldRemaining - num6); float num7 = Mathf.Min(num2, Mathf.Max(0f, num + num6)); SetCharacterHealth((Character)(object)player, num7); orCreateCestusState.LastObservedHealth = num7; if (orCreateCestusState.ShieldRemaining <= 0.001f) { ClearCestusShieldState(player, orCreateCestusState, stopRoutine: false, syncNow: true); } else { SyncCestusShieldState(player, orCreateCestusState); } DebugLog("[HaldorExpansion] Cestus shield corrected via local observer: " + $"observedDamage={num5:0.##}, " + $"absorbed={num6:0.##}, " + $"correctedHealth={num7:0.##}, " + $"remaining={orCreateCestusState.ShieldRemaining:0.##}, " + GetCestusDebugPlayerTag(player)); num5 = Mathf.Max(0f, num5 - num6); } } AddCestusCharge(player, num5); } internal static void AddCestusCharge(Player player, float postArmorDamage) { if ((Object)(object)player == (Object)null || postArmorDamage <= 0f) { return; } if (!ShouldProcessCestusLocally(player)) { DebugLog("[HaldorExpansion] Skip Cestus charge on non-local player: " + GetCestusDebugPlayerTag(player)); return; } if (!HasCestusEquipped(player)) { DebugLog("[HaldorExpansion] Skip Cestus charge because weapon not detected: " + GetCestusDebugPlayerTag(player)); return; } CestusState orCreateCestusState = GetOrCreateCestusState(player); if (!(Time.time < orCreateCestusState.CooldownUntil) && !(orCreateCestusState.ShieldRemaining > 0.001f) && !orCreateCestusState.IsCasting) { float charge = orCreateCestusState.Charge; float num = postArmorDamage * 0.8f; orCreateCestusState.Charge = Mathf.Clamp(orCreateCestusState.Charge + num, 0f, 100f); orCreateCestusState.LastChargeGainTime = Time.time; EnsureCestusChargeDecayRoutine(orCreateCestusState); DebugLog("[HaldorExpansion] Cestus charge added: " + $"damage={postArmorDamage:0.##}, " + $"added={num:0.##}, " + $"before={charge:0.##}, " + $"after={orCreateCestusState.Charge:0.##}"); } } private static void EnsureCestusChargeDecayRoutine(CestusState state) { if (state != null && !((Object)(object)Instance == (Object)null) && state.ChargeDecayRoutine == null) { state.ChargeDecayRoutine = ((MonoBehaviour)Instance).StartCoroutine(CestusChargeDecayRoutine(state)); } } [IteratorStateMachine(typeof(<CestusChargeDecayRoutine>d__63))] private static IEnumerator CestusChargeDecayRoutine(CestusState state) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CestusChargeDecayRoutine>d__63(0) { state = state }; } internal static float AbsorbCestusShield(Player player, float incomingDamage) { if ((Object)(object)player == (Object)null || incomingDamage <= 0f) { return 0f; } if (!IsCestusShieldAuthorityRuntime(player)) { return 0f; } CestusState orCreateCestusState = GetOrCreateCestusState(player); if (orCreateCestusState.ShieldRemaining <= 0.001f) { return 0f; } float num = Mathf.Min(orCreateCestusState.ShieldRemaining, incomingDamage); orCreateCestusState.ShieldRemaining = Mathf.Max(0f, orCreateCestusState.ShieldRemaining - num); if (orCreateCestusState.ShieldRemaining <= 0.001f) { ClearCestusShieldState(player, orCreateCestusState, stopRoutine: false, syncNow: true); } else { SyncCestusShieldState(player, orCreateCestusState); } DebugLog("[HaldorExpansion] Cestus shield absorbed: " + $"incoming={incomingDamage:0.##}, " + $"absorbed={num:0.##}, " + $"remaining={orCreateCestusState.ShieldRemaining:0.##}, " + $"syncedRemaining={GetSyncedCestusShieldRemaining(player):0.##}, " + GetCestusDebugPlayerTag(player)); return num; } internal static float CorrectCestusShieldAfterDamage(Player player, float beforeHealth, float afterHealth) { if ((Object)(object)player == (Object)null) { return 0f; } if (!IsCestusShieldAuthorityRuntime(player)) { return 0f; } if (((Character)player).IsDead()) { return 0f; } float num = beforeHealth - afterHealth; if (num <= 0.001f) { return 0f; } CestusState orCreateCestusState = GetOrCreateCestusState(player); if (orCreateCestusState.ShieldRemaining <= 0.001f) { return 0f; } float num2 = Mathf.Min(orCreateCestusState.ShieldRemaining, num); if (num2 <= 0.001f) { return 0f; } orCreateCestusState.ShieldRemaining = Mathf.Max(0f, orCreateCestusState.ShieldRemaining - num2); float num3 = Mathf.Min(GetCharacterMaxHealth((Character)(object)player), Mathf.Max(0f, afterHealth + num2)); SetCharacterHealth((Character)(object)player, num3); if (orCreateCestusState.ShieldRemaining <= 0.001f) { ClearCestusShieldState(player, orCreateCestusState, stopRoutine: false, syncNow: true); } else { SyncCestusShieldState(player, orCreateCestusState); } DebugLog("[HaldorExpansion] Cestus shield corrected post-damage: " + $"before={beforeHealth:0.##}, " + $"after={afterHealth:0.##}, " + $"absorbed={num2:0.##}, " + $"newHealth={num3:0.##}, " + $"remaining={orCreateCestusState.ShieldRemaining:0.##}, " + GetCestusDebugPlayerTag(player)); return num2; } internal static bool TryActivateCestusShield(Player player) { if ((Object)(object)Instance == (Object)null || (Object)(object)player == (Object)null) { return false; } if (!ShouldProcessCestusLocally(player)) { return false; } if (!HasCestusEquipped(player)) { return false; } CestusState orCreateCestusState = GetOrCreateCestusState(player); if (orCreateCestusState.IsCasting) { return false; } if (orCreateCestusState.ShieldRemaining > 0.001f) { return false; } if (orCreateCestusState.Charge < 99.999f) { return false; } if (Time.time < orCreateCestusState.CooldownUntil) { return false; } float characterMaxHealth = GetCharacterMaxHealth((Character)(object)player); if (characterMaxHealth <= 0f) { return false; } float num = Mathf.Max(20f, characterMaxHealth * 0.4f); bool flag = HasCestusSetBonus(player); float num2 = (flag ? 1.5f : 1f); float num3 = num * num2; orCreateCestusState.Charge = 0f; orCreateCestusState.CooldownUntil = Time.time + 15f; if (orCreateCestusState.CastRoutine != null) { ((MonoBehaviour)Instance).StopCoroutine(orCreateCestusState.CastRoutine); orCreateCestusState.CastRoutine = null; } orCreateCestusState.CastRoutine = ((MonoBehaviour)Instance).StartCoroutine(CestusCastRoutine(orCreateCestusState, num3)); DebugLog("[HaldorExpansion] Cestus cast started: " + $"baseShield={num:0.##}, " + $"shieldMultiplier={num2:0.##}, " + $"shield={num3:0.##}, " + $"setBonus={flag}, " + $"maxHealth={characterMaxHealth:0.##}, " + $"cooldownUntil={orCreateCestusState.CooldownUntil:0.##}"); return true; } [IteratorStateMachine(typeof(<CestusCastRoutine>d__67))] private static IEnumerator CestusCastRoutine(CestusState state, float shieldAmount) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CestusCastRoutine>d__67(0) { state = state, shieldAmount = shieldAmount }; } private static void TriggerCestusNova(Player player, float shieldAmount) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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) if ((Object)(object)player == (Object)null || shieldAmount <= 0f) { return; } float num = shieldAmount * 2.7f; if (num <= 0f) { return; } Vector3 cestusNovaOrigin = GetCestusNovaOrigin(player); int num2 = 0; List<Character> allCharacters = Character.GetAllCharacters(); if (allCharacters == null) { return; } foreach (Character item in allCharacters) { if (ShouldHitCestusNovaTarget(player, item, cestusNovaOrigin)) { ApplyCestusNovaDamage(player, item, cestusNovaOrigin, num); num2++; } } DebugLog("[HaldorExpansion] Cestus nova triggered: " + $"shield={shieldAmount:0.##}, " + $"damage={num:0.##}, " + $"radius={4f:0.##}, " + $"hits={num2}"); } private static bool ShouldHitCestusNovaTarget(Player player, Character target, Vector3 origin) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)target == (Object)null) { return false; } if (player == target) { return false; } if (target.IsDead() || target.IsPlayer()) { return false; } if (!BaseAI.IsEnemy((Character)(object)player, target)) { return false; } float num = 4f + Mathf.Max(0f, target.GetRadius()); return Vector3.Distance(origin, GetCestusNovaTargetPoint(target)) <= num; } private static void ApplyCestusNovaDamage(Player player, Character target, Vector3 origin, float damage) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0057: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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) if (!((Object)(object)player == (Object)null) && !((Object)(object)target == (Object)null) && !(damage <= 0f)) { Vector3 cestusNovaTargetPoint = GetCestusNovaTargetPoint(target); Vector3 val = cestusNovaTargetPoint - origin; if (((Vector3)(ref val)).sqrMagnitude <= 0.0001f) { val = ((Component)player).transform.forward; } HitData val2 = new HitData(); val2.m_damage.m_blunt = damage; val2.m_point = cestusNovaTargetPoint; val2.m_dir = ((Vector3)(ref val)).normalized; val2.m_pushForce = 20f; val2.m_skill = (SkillType)11; TryAssignHitAttacker(val2, (Character)(object)player); target.Damage(val2); } } private static Vector3 GetCestusNovaOrigin(Player player) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return Vector3.zero; } return ((Character)player).GetCenterPoint(); } private static Vector3 GetCestusNovaTargetPoint(Character target) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)target == (Object)null) { return Vector3.zero; } return target.GetCenterPoint(); } private static void TryAssignHitAttacker(HitData hit, Character attacker) { if (hit == null || (Object)(object)attacker == (Object)null) { return; } MethodInfo method = typeof(HitData).GetMethod("SetAttacker", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(Character) }, null); if (method != null) { method.Invoke(hit, new object[1] { attacker }); return; } FieldInfo field = typeof(HitData).GetField("m_attacker", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null && field.FieldType.IsAssignableFrom(((object)attacker).GetType())) { field.SetValue(hit, attacker); } } private static void PlayCestusCastFx(Player player, CestusState state, float shieldAmount) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null || (Object)(object)ZNetScene.instance == (Object)null || string.IsNullOrWhiteSpace("vfx_StaminaUpgrade")) { return; } GameObject prefab = ZNetScene.instance.GetPrefab("vfx_StaminaUpgrade"); if ((Object)(object)prefab == (Object)null) { DebugLog("[HaldorExpansion] Missing Cestus FX prefab: vfx_StaminaUpgrade"); return; } Vector3 cestusCastFxOrigin = GetCestusCastFxOrigin(player); Quaternion val = Quaternion.LookRotation(((Component)player).transform.forward, Vector3.up); float num = Mathf.Clamp01(shieldAmount / Mathf.Max(1f, 100f)); float num2 = Mathf.Lerp(1f, 1.6f, num); int num3 = Mathf.Max(1, 2); for (int i = 0; i < num3; i++) { GameObject obj = Object.Instantiate<GameObject>(prefab, cestusCastFxOrigin, val); Transform transform = obj.transform; transform.localScale *= num2; TrySpeedUpCestusFx(obj, state); } } private static void TrySpeedUpCestusFx(GameObject fxInstance, CestusState state) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)fxInstance == (Object)null) { return; } Animator[] componentsInChildren = fxInstance.GetComponentsInChildren<Animator>(true); foreach (Animator val in componentsInChildren) { if ((Object)(object)val != (Object)null) { val.speed *= 2f; } } ParticleSystem[] componentsInChildren2 = fxInstance.GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem val2 in componentsInChildren2) { if (!((Object)(object)val2 == (Object)null)) { MainModule main = val2.main; ((MainModule)(ref main)).simulationSpeed = ((MainModule)(ref main)).simulationSpeed * 2f; } } ZSFX[] componentsInChildren3 = fxInstance.GetComponentsInChildren<ZSFX>(true); DebugLog($"[HaldorExpansion] ZSFX found: {componentsInChildren3.Length}"); ZSFX[] array = componentsInChildren3; foreach (ZSFX val3 in array) { if ((Object)(object)val3 == (Object)null) { continue; } AudioSource cestusFxAudioSource = GetCestusFxAudioSource(val3); AudioClip[] cestusFxAudioClips = GetCestusFxAudioClips(val3); if ((Object)(object)cestusFxAudioSource == (Object)null) { continue; } string text = ((Object)((Component)val3).gameObject).name.ToLowerInvariant(); DebugLog("[HaldorExpansion] ZSFX name=" + ((Object)((Component)val3).gameObject).name + ", " + $"clips={((cestusFxAudioClips != null) ? cestusFxAudioClips.Length : 0)}, " + "clip=" + (((Object)(object)cestusFxAudioSource.clip != (Object)null) ? ((Object)cestusFxAudioSource.clip).name : "null") + ", " + $"isPlaying={cestusFxAudioSource.isPlaying}, playOnAwake={cestusFxAudioSource.playOnAwake}, " + $"pitch={cestusFxAudioSource.pitch:0.##}"); ((Behaviour)val3).enabled = false; cestusFxAudioSource.playOnAwake = false; cestusFxAudioSource.Stop(); if (cestusFxAudioClips != null && cestusFxAudioClips.Length != 0 && !((Object)(object)cestusFxAudioClips[0] == (Object)null)) { cestusFxAudioSource.clip = cestusFxAudioClips[0]; if (text.Contains("expl")) { state?.PreparedExplosionAudios.Add(cestusFxAudioSource); DebugLog("[HaldorExpansion] Prepared explosion audio: " + ((Object)((Component)val3).gameObject).name + ", clip=" + ((Object)cestusFxAudioSource.clip).name); continue; } cestusFxAudioSource.pitch *= 1.25f; float num = 0f; num = (cestusFxAudioSource.time = Mathf.Clamp(0.08f, 0f, Mathf.Max(0f, cestusFxAudioSource.clip.length - 0.01f))); cestusFxAudioSource.Play(); DebugLog("[HaldorExpansion] Manual FX sound play: name=" + ((Object)((Component)val3).gameObject).name + ", clip=" + ((Object)cestusFxAudioSource.clip).name + ", " + $"pitch={cestusFxAudioSource.pitch:0.##}, startOffset={num:0.##}"); } } } internal static bool HasCestusSetBonus(Player player) { if ((Object)(object)player != (Object)null && HasCestusEquipped(player)) { return HasPitKingChestEquipped(player); } return false; } private static void PlayPreparedCestusExplosionAudio(CestusState state) { if (state == null || state.PreparedExplosionAudios == null || state.PreparedExplosionAudios.Count == 0) { return; } foreach (AudioSource preparedExplosionAudio in state.PreparedExplosionAudios) { if (!((Object)(object)preparedExplosionAudio == (Object)null) && !((Object)(object)preparedExplosionAudio.clip == (Object)null)) { preparedExplosionAudio.Stop(); preparedExplosionAudio.time = 0f; preparedExplosionAudio.Play(); DebugLog("[HaldorExpansion] Explosion audio played: " + $"clip={((Object)preparedExplosionAudio.clip).name}, pitch={preparedExplosionAudio.pitch:0.##}"); } } state.PreparedExplosionAudios.Clear(); } private static AudioSource GetCestusFxAudioSource(ZSFX sfx) { if ((Object)(object)sfx == (Object)null) { return null; } object? obj = typeof(ZSFX).GetField("m_audioSource", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(sfx); return (AudioSource)((obj is AudioSource) ? obj : null); } private static AudioClip[] GetCestusFxAudioClips(ZSFX sfx) { if ((Object)(object)sfx == (Object)null) { return null; } return typeof(ZSFX).GetField("m_audioClips", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(sfx) as AudioClip[]; } private static void PlayCestusCastSfx(Player player) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_0064: 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_0067: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player == (Object)null) && !((Object)(object)ZNetScene.instance == (Object)null) && !string.IsNullOrWhiteSpace("")) { GameObject prefab = ZNetScene.instance.GetPrefab(""); if ((Object)(object)prefab == (Object)null) { DebugLog("[HaldorExpansion] Missing Cestus SFX prefab: "); return; } Vector3 cestusCastFxOrigin = GetCestusCastFxOrigin(player); Quaternion val = Quaternion.LookRotation(((Component)player).transform.forward, Vector3.up); Object.Instantiate<GameObject>(prefab, cestusCastFxOrigin, val); } } private static Vector3 GetCestusCastFxOrigin(Player player) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return Vector3.zero; } return ((Character)player).GetCenterPoint() + ((Component)player).transform.forward * 1f + Vector3.up * 0.8f; } [IteratorStateMachine(typeof(<CestusShieldRoutine>d__82))] private static IEnumerator CestusShieldRoutine(CestusState state) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CestusShieldRoutine>d__82(0) { state = state }; } internal static void ClearHumanoidAttackState(Humanoid humanoid) { if (!((Object)(object)humanoid == (Object)null)) { SetFieldIfExists(humanoid, "m_attack", false); SetFieldIfExists(humanoid, "m_secondaryAttack", false); SetFieldIfExists(humanoid, "m_attackHold", false); } } internal static void ClearHumanoidBlockState(Humanoid humanoid) { if (!((Object)(object)humanoid == (Object)null)) { SetFieldIfExists(humanoid, "m_blocking", false); SetFieldIfExists(humanoid, "m_blockTimer", 0f); } } internal static float GetCestusShieldNormalized(Player player) { if ((Object)(object)player == (Object)null) { return 0f; } CestusState orCreateCestusState = GetOrCreateCestusState(player); if (orCreateCestusState.ShieldRemaining <= 0.001f || orCreateCestusState.ShieldMax <= 0.001f) { return 0f; } return Mathf.Clamp01(orCreateCestusState.ShieldRemaining / orCreateCestusState.ShieldMax); } internal static float GetCestusShieldBarNormalized(Player player) { if ((Object)(object)player == (Object)null) { return 0f; } CestusState orCreateCestusState = GetOrCreateCestusState(player); if (orCreateCestusState.ShieldRemaining <= 0.001f) { return 0f; } float characterMaxHealth = GetCharacterMaxHealth((Character)(object)player); if (characterMaxHealth <= 0f) { return 0f; } return Mathf.Clamp01(orCreateCestusState.ShieldRemaining / characterMaxHealth); } internal static float GetCestusHealthNormalized(Player player) { if ((Object)(object)player == (Object)null) { return 0f; } float characterMaxHealth = GetCharacterMaxHealth((Character)(object)player); if (characterMaxHealth <= 0f) { return 0f; } return Mathf.Clamp01(((Character)player).GetHealth() / characterMaxHealth); } private void RegisterCestusInput() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_0056: Expected O, but got Unknown CestusAbilityKeyConfig = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Cestus", "Ability Key", (KeyCode)325, "Key for activating the Cestus ability"); CestusAbilityButton = new ButtonConfig { Name = "CestusAbility", Config = CestusAbilityKeyConfig, HintToken = "$cestus_ability", BlockOtherInputs = true }; InputManager.Instance.AddButton("aveasura.haldor.expansion", CestusAbilityButton); } internal static void UpdateCestusShieldOverlay(Hud hud, Player player) { //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0148: 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_0170: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)hud == (Object)null) { return; } EnsureCestusShieldOverlay(hud); if ((Object)(object)CestusShieldOverlayImage == (Object)null || (Object)(object)CestusShieldOverlayRect == (Object)null || (Object)(object)CestusShieldReferenceRect == (Object)null || (Object)(object)CestusShieldText == (Object)null || (Object)(object)CestusShieldTextRect == (Object)null) { return; } if ((Object)(object)player == (Object)null || ((Character)player).IsDead()) { if (((Component)CestusShieldOverlayImage).gameObject.activeSelf) { ((Component)CestusShieldOverlayImage).gameObject.SetActive(false); } if (((Component)CestusShieldText).gameObject.activeSelf) { ((Component)CestusShieldText).gameObject.SetActive(false); } return; } CestusState orCreateCestusState = GetOrCreateCestusState(player); float cestusShieldBarNormalized = GetCestusShieldBarNormalized(player); bool flag = cestusShieldBarNormalized > 0.001f; if (((Component)CestusShieldOverlayImage).gameObject.activeSelf != flag) { ((Component)CestusShieldOverlayImage).gameObject.SetActive(flag); } if (((Component)CestusShieldText).gameObject.activeSelf != flag) { ((Component)CestusShieldText).gameObject.SetActive(flag); } if (flag) { float cestusHealthNormalized = GetCestusHealthNormalized(player); CopyRectTransform(CestusShieldReferenceRect, CestusShieldOverlayRect); Rect rect = CestusShieldReferenceRect.rect; float width = ((Rect)(ref rect)).width; Vector2 anchoredPosition = CestusShieldReferenceRect.anchoredPosition; float num = width * cestusShieldBarNormalized; float num2 = width * cestusHealthNormalized; CestusShieldOverlayRect.anchoredPosition = anchoredPosition + new Vector2(num2, 0f); CestusShieldOverlayImage.fillAmount = cestusShieldBarNormalized; ((Transform)CestusShieldTextRect).rotation = Quaternion.identity; CestusShieldText.text = Mathf.CeilToInt(orCreateCestusState.ShieldRemaining).ToString(); CestusShieldTextRect.sizeDelta = new Vector2(Mathf.Max(36f, num), 18f); CestusShieldTextRect.anchoredPosition = new Vector2(num * 0.5f, 0f); } } private static void EnsureCestusShieldOverlay(Hud hud) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: 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_011b: Unknown result type (might be due to invalid IL or missing references) //IL_019d: 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_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0219: 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_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0320: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)CestusShieldOverlayImage != (Object)null && (Object)(object)CestusShieldOverlayRect != (Object)null && (Object)(object)CestusShieldReferenceRect != (Object)null && (Object)(object)CestusShieldText != (Object)null && (Object)(object)CestusShieldTextRect != (Object)null) { return; } Component val = FindReferenceHealthBarComponent(hud); if ((Object)(object)val == (Object)null) { if (!CestusShieldOverlayLoggedMissing) { CestusShieldOverlayLoggedMissing = true; DebugLog("[HaldorExpansion] Cestus segmented HUD: health bar component not found"); } return; } RectTransform component = val.GetComponent<RectTransform>(); if ((Object)(object)component == (Object)null || (Object)(object)((Transform)component).parent == (Object)null) { if (!CestusShieldOverlayLoggedMissing) { CestusShieldOverlayLoggedMissing = true; DebugLog("[HaldorExpansion] Cestus segmented HUD: reference RectTransform not found"); } return; } GameObject val2 = new GameObject("HaldorExpansion_CestusShieldSegment", new Type[1] { typeof(RectTransform) }); RectTransform component2 = val2.GetComponent<RectTransform>(); ((Transform)component2).SetParent(((Transform)component).parent, false); CopyRectTransform(component, component2); Image val3 = val2.AddComponent<Image>(); ((Graphic)val3).raycastTarget = false; val3.type = (Type)3; val3.fillMethod = (FillMethod)0; val3.fillOrigin = 0; val3.fillAmount = 0f; ((Graphic)val3).color = new Color(0.62f, 0.62f, 0.62f, 0.78f); Image val4 = val.GetComponent<Image>(); if ((Object)(object)val4 == (Object)null) { val4 = val.GetComponentInChildren<Image>(true); } if ((Object)(object)val4 != (Object)null) { val3.sprite = val4.sprite; ((Graphic)val3).material = ((Graphic)val4).material; val3.preserveAspect = val4.preserveAspect; } ((Transform)component2).SetSiblingIndex(((Transform)component).GetSiblingIndex() + 1); val2.SetActive(false); GameObject val5 = new GameObject("HaldorExpansion_CestusShieldText", new Type[1] { typeof(RectTransform) }); RectTransform component3 = val5.GetComponent<RectTransform>(); ((Transform)component3).SetParent((Transform)(object)component2, false); component3.anchorMin = new Vector2(0f, 0.5f); component3.anchorMax = new Vector2(0f, 0.5f); component3.pivot = new Vector2(0.5f, 0.5f); component3.sizeDelta = new Vector2(64f, 18f); ((Transform)component3).localScale = Vector3.one; ((Transform)component3).rotation = Quaternion.identity; component3.anchoredPosition = Vector2.zero; Text val6 = val5.AddComponent<Text>(); ((Graphic)val6).raycastTarget = false; val6.alignment = (TextAnchor)4; val6.horizontalOverflow = (HorizontalWrapMode)1; val6.verticalOverflow = (VerticalWrapMode)1; val6.resizeTextForBestFit = false; val6.fontSize = 14; val6.fontStyle = (FontStyle)1; ((Graphic)val6).color = new Color(1f, 1f, 1f, 0.95f); val6.text = string.Empty; Text val7 = val.GetComponent<Text>(); if ((Object)(object)val7 == (Object)null) { val7 = val.GetComponentInChildren<Text>(true); } if ((Object)(object)val7 != (Object)null && (Object)(object)val7.font != (Object)null) { val6.font = val7.font; } else { val6.font = Resources.GetBuiltinResource<Font>("Arial.ttf"); } Outline obj = val5.AddComponent<Outline>(); ((Shadow)obj).effectColor = new Color(0f, 0f, 0f, 0.9f); ((Shadow)obj).effectDistance = new Vector2(1f, -1f); val5.SetActive(false); CestusShieldOverlayImage = val3; CestusShieldOverlayRect = component2; CestusShieldReferenceRect = component; CestusShieldText = val6; CestusShieldTextRect = component3; CestusShieldOverlayLoggedMissing = false; DebugLog("[HaldorExpansion] Cestus segmented HUD with text created"); } private static Component FindReferenceHealthBarComponent(Hud hud) { FieldInfo[] fields = typeof(Hud).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); Component val = null; FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { if (fieldInfo.FieldType == null || fieldInfo.FieldType.Name != "GuiBar") { continue; } object? value = fieldInfo.GetValue(hud); Component val2 = (Component)((value is Component) ? value : null); if ((Object)(object)val2 == (Object)null) { continue; } string text = fieldInfo.Name.ToLowerInvariant(); if (text.Contains("health") || text.Contains("hp")) { if (text.Contains("fast")) { return val2; } if ((Object)(object)val == (Object)null) { val = val2; } } } return val; } private static void CopyRectTransform(RectTransform source, RectTransform target) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) target.anchorMin = source.anchorMin; target.anchorMax = source.anchorMax; target.pivot = source.pivot; target.anchoredPosition = source.anchoredPosition; target.sizeDelta = source.sizeDelta; ((Transform)target).localScale = ((Transform)source).localScale; ((Transform)target).localRotation = ((Transform)source).localRotation; target.offsetMin = source.offsetMin; target.offsetMax = source.offsetMax; } internal static void DumpAdrenalineReflection() { if (_adrenalineReflectionDumped) { return; } _adrenalineReflectionDumped = true; try { Assembly assembly = typeof(Player).Assembly; DebugLog("[HaldorExpansion] ===== ADRENALINE / TRINKET REFLECTION DUMP START ====="); string[] needles = new string[2] { "adren", "trinket" }; Type[] array = (from t in assembly.GetTypes() where needles.Any((string n) => (t.FullName ?? string.Empty).IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0 || t.Name.IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0) orderby t.FullName select t).ToArray(); foreach (Type type in array) { DebugLog("[HaldorExpansion] [Reflect] TYPE: " + type.FullName); FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { DebugLog("[HaldorExpansion] [Reflect] FIELD: " + fieldInfo.FieldType.Name + " " + fieldInfo.Name); } PropertyInfo[] properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (PropertyInfo propertyInfo in properties) { DebugLog("[HaldorExpansion] [Reflect] PROP: " + propertyInfo.PropertyType.Name + " " + propertyInfo.Name); } MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo i in methods) { if (needles.Any((string n) => i.Name.IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0)) { string text = string.Join(", ", from p in i.GetParameters() select p.ParameterType.Name + " " + p.Name); DebugLog("[HaldorExpansion] [Reflect] METHOD: " + i.ReturnType.Name + " " + i.Name + "(" + text + ")"); } } } DumpRelevantMembers(typeof(Player), "Player"); DumpRelevantMembers(typeof(Hud), "Hud"); DumpRelevantMembers(typeof(Humanoid), "Humanoid"); DumpRelevantMembers(typeof(InventoryGui), "InventoryGui"); DebugLog("[HaldorExpansion] ===== ADRENALINE / TRINKET REFLECTION DUMP END ====="); } catch (Exception arg) { ManualLogSource log = Log; if (log != null) { log.LogError((object)$"[HaldorExpansion] Adrenaline reflection dump failed: {arg}"); } } } private static void DumpRelevantMembers(Type t, string label) { try { string[] source = new string[2] { "adren", "trinket" }; DebugLog("[HaldorExpansion] [Reflect] ===== " + label + " relevant members ====="); FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo f in fields) { if (source.Any((string n) => f.Name.IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0)) { DebugLog("[HaldorExpansion] [Reflect] FIELD: " + f.FieldType.Name + " " + f.Name); } } PropertyInfo[] properties = t.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (PropertyInfo p2 in properties) { if (source.Any((string n) => p2.Name.IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0)) { DebugLog("[HaldorExpansion] [Reflect] PROP: " + p2.PropertyType.Name + " " + p2.Name); } } MethodInfo[] methods = t.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo i in methods) { if (source.Any((string n) => i.Name.IndexOf(n, StringComparison.OrdinalIgnoreCase) >= 0)) { string text = string.Join(", ", from p in i.GetParameters() select p.ParameterType.Name + " " + p.Name); DebugLog("[HaldorExpansion] [Reflect] METHOD: " + i.ReturnType.Name + " " + i.Name + "(" + text + ")"); } } } catch (Exception arg) { ManualLogSource log = Log; if (log != null) { log.LogError((object)$"[HaldorExpansion] DumpRelevantMembers failed for {label}: {arg}"); } } } internal static bool EnsureCestusReady() { //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Expected O, but got Unknown try { if ((Object)(object)ObjectDB.instance == (Object)null) { return false; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Bone_crushers"); if ((Object)(object)itemPrefab != (Object)null) { GritCestusPrefab = itemPrefab; GritCestusItemDrop = itemPrefab.GetComponent<ItemDrop>(); if ((Object)(object)GritCestusItemDrop != (Object)null) { ConfigureCestusShared(GritCestusItemDrop.m_itemData.m_shared); ApplyBoneCrushersIcon(GritCestusItemDrop.m_itemData.m_shared); GritCestusItemDrop.m_itemData.m_dropPrefab = itemPrefab; } DebugLog("[HaldorExpansion] Cestus already in ObjectDB: Bone_crushers"); return (Object)(object)GritCestusItemDrop != (Object)null; } GameObject itemPrefab2 = ObjectDB.instance.GetItemPrefab("FistFenrirClaw"); if ((Object)(object)itemPrefab2 == (Object)null) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)"[HaldorExpansion] Source cestus prefab not found: FistFenrirClaw"); } return false; } GameObject val = PrefabManager.Instance.CreateClonedPrefab("Bone_crushers", ((Object)itemPrefab2).name); if ((Object)(object)val == (Object)null) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogWarning((object)"[HaldorExpansion] Failed to clone cestus prefab"); } return false; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { ManualLogSource log3 = Log; if (log3 != null) { log3.LogWarning((object)"[HaldorExpansion] ItemDrop missing on cloned cestus prefab"); } return false; } ConfigureCestusShared(component.m_itemData.m_shared); ApplyBoneCrushersIcon(component.m_itemData.m_shared); component.m_itemData.m_dropPrefab = val; ItemManager.Instance.AddItem(new CustomItem(val, true)); GritCestusPrefab = val; GritCestusItemDrop = component; DebugLog("[HaldorExpansion] Cestus registered: Bone_crushers (source=" + ((Object)itemPrefab2).name + ")"); return true; } catch (Exception arg) { ManualLogSource log4 = Log; if (log4 != null) { log4.LogError((object)$"[HaldorExpansion] EnsureCestusReady error: {arg}"); } return false; } } private static void ConfigureCestusShared(SharedData shared) { if (shared != null) { shared.m_name = "$item_weapon_gritcestus"; shared.m_description = "$item_weapon_gritcestus_desc"; shared.m_maxStackSize = 1; shared.m_weight = 5f; shared.m_value = 0; shared.m_maxQuality = 1; shared.m_canBeReparied = true; shared.m_useDurability = true; shared.m_maxDurability = 1800f; shared.m_durabilityPerLevel = 0f; shared.m_damages.m_slash = 0f; shared.m_damages.m_blunt = 24f; shared.m_damages.m_pierce = 0f; shared.m_damages.m_fire = 0f; shared.m_damages.m_frost = 0f; shared.m_damages.m_lightning = 4f; shared.m_damages.m_poison = 0f; shared.m_damages.m_spirit = 0f; shared.m_damagesPerLevel.m_slash = 0f; shared.m_damagesPerLevel.m_blunt = 0f; shared.m_damagesPerLevel.m_pierce = 0f; shared.m_damagesPerLevel.m_fire = 0f; shared.m_damagesPerLevel.m_frost = 0f; shared.m_damagesPerLevel.m_lightning = 0f; shared.m_damagesPerLevel.m_poison = 0f; shared.m_damagesPerLevel.m_spirit = 0f; shared.m_blockPower = 2f; shared.m_blockPowerPerLevel = 0f; shared.m_deflectionForce = 15f; shared.m_deflectionForcePerLevel = 0f; shared.m_timedBlockBonus = 2f; if (shared.m_attack != null) { shared.m_attack.m_attackStamina = 12f; shared.m_attack.m_staggerMultiplier = 1.35f; } if (shared.m_secondaryAttack != null) { shared.m_secondaryAttack.m_attackStamina = 20f; shared.m_secondaryAttack.m_staggerMultiplier = 2.2f; } shared.m_backstabBonus = 3f; ApplyCestusEquipBonuses(shared); shared.m_canBeReparied = true; shared.m_useDurability = true; ApplySteelHeartSet(shared); } } private static void ApplyCestusEquipBonuses(SharedData shared) { if (shared != null) { ApplyCestusVisualEffect(shared); } } private static bool IsCestusWeapon(ItemData item) { if (item == null) { return false; } if ((Object)(object)item.m_dropPrefab != (Object)null && ((Object)item.m_dropPrefab).name == "Bone_crushers") { return true; } if (item.m_shared != null && item.m_shared.m_name == "$item_weapon_gritcestus") { return true; } return false; } internal static void RegisterCestusRecipe() { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: 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_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0100: 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) //IL_0113: 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_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Expected O, but got Unknown //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Expected O, but got Unknown try { string text = "Recipe_Bone_crushers"; if (ItemManager.Instance.GetRecipe(text) != null) { DebugLog("[HaldorExpansion] Recipe already registered: " + text); return; } ObjectDB instance = ObjectDB.instance; GameObject val = ((instance != null) ? instance.GetItemPrefab("FistFenrirClaw") : null); if ((Object)(object)val == (Object)null) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)"[HaldorExpansion] Source prefab not found for cestus recipe"); } return; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogWarning((object)"[HaldorExpansion] Source ItemDrop not found for cestus recipe"); } return; } Recipe recipe = ObjectDB.instance.GetRecipe(component.m_itemData); if ((Object)(object)recipe == (Object)null) { ManualLogSource log3 = Log; if (log3 != null) { log3.LogWarning((object)"[HaldorExpansion] Source recipe not found for cestus"); } return; } string craftingStation = (((Object)(object)recipe.m_craftingStation != (Object)null) ? ((Object)recipe.m_craftingStation).name : "forge"); RecipeConfig val2 = new RecipeConfig { Name = text, Item = "Bone_crushers", Amount = 1, CraftingStation = craftingStation, RepairStation = "forge", MinStationLevel = 1, Enabled = false, Requirements = Array.Empty<RequirementConfig>() }; ItemManager.Instance.AddRecipe(new CustomRecipe(val2)); DebugLog("[HaldorExpansion] Registered recipe via Jotunn for Bone_crushers"); } catch (Exception arg) { ManualLogSource log4 = Log; if (log4 != null) { log4.LogError((object)$"[HaldorExpansion] RegisterCestusRecipe error: {arg}"); } } } internal static bool FixCestusItemsInInventory(Player player) { try { if ((Object)(object)player == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return false; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Bone_crushers"); if ((Object)(object)itemPrefab == (Object)null) { return false; } ItemDrop component = itemPrefab.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { return false; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return false; } bool result = false; List<ItemData> allItems = inventory.GetAllItems(); if (allItems == null) { return false; } foreach (ItemData item in allItems) { if (item != null && item.m_shared != null && !(item.m_shared.m_name != "$item_weapon_gritcestus")) { result = true; int num = Mathf.Max(1, item.m_quality); float durability = item.m_durability; bool equipped = item.m_equipped; int variant = item.m_variant; long crafterID = item.m_crafterID; string crafterName = item.m_crafterName; item.m_dropPrefab = itemPrefab; item.m_shared = component.m_itemData.m_shared; item.m_quality = Mathf.Clamp(num, 1, Mathf.Max(1, item.m_shared.m_maxQuality)); item.m_variant = variant; item.m_crafterID = crafterID; item.m_crafterName = crafterName; item.m_equipped = equipped; float num2 = item.m_shared.m_maxDurability + item.m_shared.m_durabilityPerLevel * (float)(item.m_quality - 1); item.m_durability = Mathf.Clamp(durability, 0f, Mathf.Max(1f, num2)); item.m_shared.m_canBeReparied = true; item.m_shared.m_useDurability = true; } } return result; } catch (Exception arg) { ManualLogSource log = Log; if (log != null) { log.LogError((object)$"[HaldorExpansion] FixCestusItemsInInventory error: {arg}"); } return false; } } private static bool HasEquippedCestus(Player player) { if ((Object)(object)player == (Object)null) { return false; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return false; } List<ItemData> allItems = inventory.GetAllItems(); if (allItems == null) { return false; } foreach (ItemData item in allItems) { if (item != null && item.m_equipped && IsCestusWeapon(item)) { return true; } } return false; } private static void ApplyCestusVisualEffect(SharedData shared) { if (shared != null) { SE_Stats val = ScriptableObject.CreateInstance<SE_Stats>(); ((Object)val).name = "SE_GritCestusVisual"; SetFieldIfExists(val, "m_name", "$se_weapon_gritcestus"); SetFieldIfExists(val, "m_tooltip", "$se_weapon_gritcestus_desc"); shared.m_equipStatusEffect = (StatusEffect)(object)val; } } private static void ApplyBoneCrushersIcon(SharedData shared) { if (shared != null && !TrySetEmbeddedIcon(shared, "Bone_crushers.png")) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)"[HaldorExpansion] Embedded icon missing for Bone crushers: Bone_crushers.png"); } } } internal static void DebugLog(string message) { if (DebugLogging) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)message); } } } private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; AddLocalizations(); Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "aveasura.haldor.expansion"); if (DebugLogging) { DumpAdrenalineReflection(); } RegisterCestusInput(); } private static void ApplyDelayedDoomChestVisualEffect(SharedData shared) { if (shared != null) { SE_Stats val = ScriptableObject.CreateInstance<SE_Stats>(); ((Object)val).name = "SE_DelayedDoomChestVisual"; SetFieldIfExists(val, "m_name", "$se_delayeddoom_regen"); SetFieldIfExists(val, "m_tooltip", "$se_delayeddoom_regen_desc"); shared.m_equipStatusEffect = (StatusEffect)(object)val; } } internal static bool EnsureDelayedDoomChestReady() { //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Expected O, but got Unknown try { if ((Object)(object)ObjectDB.instance == (Object)null) { return false; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("ArmorDelayedDoomChest"); if ((Object)(object)itemPrefab != (Object)null) { DelayedDoomChestPrefab = itemPrefab; DelayedDoomChestItemDrop = itemPrefab.GetComponent<ItemDrop>(); if ((Object)(object)DelayedDoomChestItemDrop != (Object)null) { SharedData shared = DelayedDoomChestItemDrop.m_itemData.m_shared; ConfigureDelayedDoomChestShared(shared); ApplyDelayedDoomChestIcon(shared); DelayedDoomChestItemDrop.m_itemData.m_dropPrefab = itemPrefab; shared.m_canBeReparied = true; shared.m_useDurability = true; } DebugLog("[HaldorExpansion] Delayed Doom chest already in ObjectDB: ArmorDelayedDoomChest"); return (Object)(object)DelayedDoomChestItemDrop != (Object)null; } GameObject itemPrefab2 = ObjectDB.instance.GetItemPrefab("ArmorPaddedCuirass"); if ((Object)(object)itemPrefab2 == (Object)null) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)"[HaldorExpansion] Source chest prefab not found: ArmorPaddedCuirass"); } return false; } GameObject val = PrefabManager.Instance.CreateClonedPrefab("ArmorDelayedDoomChest", ((Object)itemPrefab2).name); if ((Object)(object)val == (Object)null) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogWarning((object)"[HaldorExpansion] Failed to clone delayed doom chest prefab"); } return false; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { ManualLogSource log3 = Log; if (log3 != null) { log3.LogWarning((object)"[HaldorExpansion] ItemDrop missing on delayed doom chest"); } return false; } SharedData shared2 = component.m_itemData.m_shared; ConfigureDelayedDoomChestShared(shared2); ApplyDelayedDoomChestIcon(shared2); component.m_itemData.m_dropPrefab = val; ItemManager.Instance.AddItem(new CustomItem(val, true)); DelayedDoomChestPrefab = val; DelayedDoomChestItemDrop = component; DebugLog("[HaldorExpansion] Delayed Doom chest registered: ArmorDelayedDoomChest (source=" + ((Object)itemPrefab2).name + ")"); return true; } catch (Exception arg) { ManualLogSource log4 = Log; if (log4 != null) { log4.LogError((object)$"[HaldorExpansion] EnsureDelayedDoomChestReady error: {arg}"); } return false; } } private static void ConfigureDelayedDoomChestShared(SharedData shared) { if (shared != null) { shared.m_name = "$item_chest_delayeddoom"; shared.m_description = "$item_chest_delayeddoom_desc"; shared.m_armor = 32f; shared.m_maxQuality = 1; shared.m_weight = 5f; shared.m_value = 0; shared.m_maxDurability = 2100f; shared.m_durabilityPerLevel = 0f; shared.m_useDurability = true; shared.m_canBeReparied = true; shared.m_setName = ""; shared.m_setSize = 0; shared.m_setStatusEffect = null; ApplyDelayedDoomChestVisualEffect(shared); } } internal static bool FixDelayedDoomItemsInInventory(Player player) { try { if ((Object)(object)player == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return false; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("ArmorDelayedDoomChest"); if ((Object)(object)itemPrefab == (Object)null) { return false; } ItemDrop component = itemPrefab.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { return false; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return false; } bool flag = false; bool flag2 = false; List<ItemData> allItems = inventory.GetAllItems(); if (allItems == null) { return false; } foreach (ItemData item in allItems) { if (item != null && item.m_shared != null && !(item.m_shared.m_name != "$item_chest_delayeddoom")) { flag = true; int num = Mathf.Max(1, item.m_quality); float durability = item.m_durability; bool equipped = item.m_equipped; int variant = item.m_variant; long crafterID = item.m_crafterID; string crafterName = item.m_crafterName; item.m_dropPrefab = itemPrefab; item.m_shared = component.m_itemData.m_shared; item.m_quality = Mathf.Clamp(num, 1, Mathf.Max(1, item.m_shared.m_maxQuality)); item.m_variant = variant; item.m_crafterID = crafterID; item.m_crafterName = crafterName; item.m_equipped = equipped; float num2 = item.m_shared.m_maxDurability + item.m_shared.m_durabilityPerLevel * (float)(item.m_quality - 1); item.m_durability = Mathf.Clamp(durability, 0f, Mathf.Max(1f, num2)); item.m_shared.m_canBeReparied = true; item.m_shared.m_useDurability = true; flag2 = true; } } if (flag) { Recipe recipe = ObjectDB.instance.GetRecipe(component.m_itemData); string[] obj = new string[10] { "[HaldorExpansion] Inventory rebind checked: ", $"changed={flag2}, ", "recipe=", ((Object)(object)recipe != (Object)null) ? ((Object)recipe).name : "null", ", craft=", null, null, null, null, null }; object obj2; if (!((Object)(object)recipe != (Object)null)) { obj2 = "null"; } else { CraftingStation craftingStation = recipe.m_craftingStation; obj2 = ((craftingStation != null) ? ((Object)craftingStation).name : null); } obj[5] = (string)obj2; obj[6] = ", repair="; object obj3; if (!((Object)(object)recipe != (Object)null)) { obj3 = "null"; } else { CraftingStation repairStation = recipe.m_repairStation; obj3 = ((repairStation != null) ? ((Object)repairStation).name : null); } obj[7] = (string)obj3; obj[8] = ", dropPrefab=";