Decompiled source of OG Bands v1.0.1

OGBands.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using RoR2;
using RoR2.Projectile;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace OGBands;

[BepInPlugin("local.ogbands", "OG Bands", "1.0.1")]
public sealed class Plugin : BaseUnityPlugin
{
	private void Awake()
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		if (Chainloader.PluginInfos.ContainsKey("local.classicroute"))
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"Classic Route already implements these bands; OG Bands stays inactive to avoid duplicate procs.");
			return;
		}
		ProcItems.Initialize(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
		new Harmony("local.ogbands").PatchAll(typeof(Plugin).Assembly);
		((BaseUnityPlugin)this).Logger.LogInfo((object)"OG Bands loaded: original shared 8% roll, no cooldown/threshold, original damage stacking and moving tornado.");
	}
}
internal static class BandDamage
{
	private sealed class Hit
	{
		public float damage;
	}

	[HarmonyPatch(typeof(GlobalEventManager), "ServerDamageDealt")]
	private static class Capture
	{
		private static void Prefix(DamageReport __0)
		{
			if (__0 != null && __0.damageInfo != null && !__0.damageInfo.rejected)
			{
				hits.GetOrCreateValue(__0.damageInfo).damage = __0.damageDealt;
			}
		}
	}

	private static readonly ConditionalWeakTable<DamageInfo, Hit> hits = new ConditionalWeakTable<DamageInfo, Hit>();

	internal static float Read(DamageInfo info)
	{
		Hit value;
		return hits.TryGetValue(info, out value) ? value.damage : info.damage;
	}

	internal static float Proc(float hit, float basic, float coefficient)
	{
		return Math.Max(1f, Math.Min(hit + (coefficient - 1f) * basic, hit * coefficient));
	}
}
internal static class ProcItems
{
	[HarmonyPatch(typeof(Language), "GetLocalizedStringByToken")]
	private static class Descriptions
	{
		private static bool Prefix(string __0, ref string __result)
		{
			if (!Enabled.Value)
			{
				return true;
			}
			switch (__0)
			{
			case "ITEM_ICERING_DESC":
				__result = "8% chance on hit to blast an enemy with ice for 250% (+125% per stack) damage and slow by 80% for 3 seconds. No cooldown or damage threshold. Shares its roll with Runald's and Kjaro's Bands.";
				return false;
			case "ITEM_FIRERING_DESC":
				__result = "8% chance on hit to create a moving flame tornado for 500% (+250% per stack) damage. No cooldown or damage threshold. Shares its roll with Runald's and Kjaro's Bands.";
				return false;
			case "ITEM_ICERING_PICKUP":
				__result = "Chance on hit to blast enemies with ice. No cooldown.";
				return false;
			case "ITEM_FIRERING_PICKUP":
				__result = "Chance on hit to create a moving flame tornado. No cooldown.";
				return false;
			default:
				return true;
			}
		}
	}

	[HarmonyPatch]
	private static class ReplaceVanilla
	{
		private static IEnumerable<MethodBase> TargetMethods()
		{
			yield return AccessTools.Method(typeof(GlobalEventManager), "ProcessHitEnemy", (Type[])null, (Type[])null);
		}

		private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod)
		{
			List<CodeInstruction> list = instructions.ToList();
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < list.Count - 1; i++)
			{
				if (!(list[i].opcode != OpCodes.Ldsfld))
				{
					FieldInfo fieldInfo = list[i].operand as FieldInfo;
					MethodInfo methodInfo = list[i + 1].operand as MethodInfo;
					if (Family(fieldInfo) && methodInfo != null && methodInfo.Name == "GetItemCountEffective" && methodInfo.GetParameters()[0].ParameterType == typeof(ItemDef))
					{
						list[i + 1].opcode = OpCodes.Call;
						list[i + 1].operand = AccessTools.Method(typeof(ProcItems), "VanillaCount", (Type[])null, (Type[])null);
						num++;
					}
					if (fieldInfo == AccessTools.Field(typeof(Buffs), "ElementalRingsReady") && methodInfo != null && methodInfo.Name == "HasBuff")
					{
						list[i + 1].opcode = OpCodes.Call;
						list[i + 1].operand = AccessTools.Method(typeof(ProcItems), "VanillaBandsReady", (Type[])null, (Type[])null);
						num2++;
					}
				}
			}
			int num3 = 2;
			if (num != num3 || (__originalMethod.Name == "ProcessHitEnemy" && num2 != 1))
			{
				throw new InvalidOperationException("Proc item targets changed in " + __originalMethod.Name + ": counts=" + num + " ready=" + num2);
			}
			log.LogInfo((object)("Classic item handlers replaced in " + __originalMethod.Name + ": " + num));
			return list;
		}
	}

	[HarmonyPatch(typeof(GlobalEventManager), "ProcessHitEnemy")]
	private static class HitItems
	{
		private static void Postfix(DamageInfo __0, GameObject __1)
		{
			//IL_00a8: 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)
			//IL_00c1: 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_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019c: Expected O, but got Unknown
			//IL_01c2: 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)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0202: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_025c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_0308: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_0317: Unknown result type (might be due to invalid IL or missing references)
			//IL_0319: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || !NetworkServer.active || __0.rejected || __0.procCoefficient <= 0f || !Object.op_Implicit((Object)(object)__0.attacker) || !Object.op_Implicit((Object)(object)__1))
			{
				return;
			}
			CharacterBody component = __0.attacker.GetComponent<CharacterBody>();
			CharacterBody component2 = __1.GetComponent<CharacterBody>();
			if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.inventory) || !Object.op_Implicit((Object)(object)component2) || !Object.op_Implicit((Object)(object)component2.healthComponent) || component2.HasBuff(Buffs.HiddenRejectAllDamage) || ((__0.damageType.damageTypeExtended & 0x400000) != 0 && !FriendlyFireManager.ShouldDirectHitProceed(component2.healthComponent, component.teamComponent.teamIndex)))
			{
				return;
			}
			Inventory inventory = component.inventory;
			TeamIndex teamIndex = component.teamComponent.teamIndex;
			float hit = BandDamage.Read(__0);
			int itemCountEffective = inventory.GetItemCountEffective(Items.IceRing);
			int itemCountEffective2 = inventory.GetItemCountEffective(Items.FireRing);
			if ((itemCountEffective | itemCountEffective2) > 0 && Util.CheckRoll(8f * __0.procCoefficient, component.master))
			{
				ProcChainMask procChainMask = __0.procChainMask;
				((ProcChainMask)(ref procChainMask)).AddProc((ProcType)12);
				if (itemCountEffective > 0)
				{
					EffectManager.SimpleImpactEffect(LegacyResourcesAPI.Load<GameObject>("Prefabs/Effects/ImpactEffects/IceRingExplosion"), __0.position, Vector3.up, true);
					component2.AddTimedBuff(Buffs.Slow80, 3f);
					HealthComponent healthComponent = component2.healthComponent;
					DamageInfo val = new DamageInfo();
					val.damage = BandDamage.Proc(hit, component.damage, 1.25f + 1.25f * (float)itemCountEffective);
					val.damageColorIndex = (DamageColorIndex)3;
					val.damageType = DamageTypeCombo.op_Implicit((DamageType)0);
					val.attacker = __0.attacker;
					val.crit = __0.crit;
					val.force = Vector3.zero;
					val.position = __0.position;
					val.procChainMask = procChainMask;
					val.procCoefficient = 1f;
					val.inflictedHurtbox = __0.inflictedHurtbox;
					healthComponent.TakeDamage(val);
				}
				if (itemCountEffective2 > 0)
				{
					GameObject projectilePrefab = LegacyResourcesAPI.Load<GameObject>("Prefabs/Projectiles/FireTornado");
					Vector3 val2 = __0.position - component.aimOrigin;
					val2.y = 0f;
					ProjectileManager instance = ProjectileManager.instance;
					FireProjectileInfo val3 = new FireProjectileInfo
					{
						projectilePrefab = projectilePrefab,
						position = __0.position,
						rotation = ((val2 != Vector3.zero) ? Util.QuaternionSafeLookRotation(val2, Vector3.up) : Quaternion.identity),
						owner = __0.attacker,
						damage = BandDamage.Proc(hit, component.damage, 2.5f + 2.5f * (float)itemCountEffective2) / 3.3f * 0.3f,
						crit = __0.crit,
						procChainMask = procChainMask,
						damageColorIndex = (DamageColorIndex)3
					};
					((FireProjectileInfo)(ref val3)).speedOverride = ((val2 != Vector3.zero) ? 5f : 0f);
					instance.FireProjectile(val3);
				}
			}
		}
	}

	[HarmonyPatch(typeof(ProjectileController), "Awake")]
	private static class TornadoMovement
	{
		private static void Postfix(ProjectileController __instance)
		{
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			if (Active && ((Object)((Component)__instance).gameObject).name.StartsWith("FireTornado", StringComparison.Ordinal))
			{
				ProjectileSimple component = ((Component)__instance).GetComponent<ProjectileSimple>();
				if (Object.op_Implicit((Object)(object)component))
				{
					component.desiredForwardSpeed = 5f;
					component.enableVelocityOverLifetime = true;
					component.lifetime = 3.3f;
				}
				ProjectileOverlapAttack component2 = ((Component)__instance).GetComponent<ProjectileOverlapAttack>();
				if (Object.op_Implicit((Object)(object)component2))
				{
					component2.resetInterval = 0.3f;
					component2.overlapProcCoefficient = 0f;
				}
				Transform val = ((Component)__instance).transform.Find("HitBox");
				if (Object.op_Implicit((Object)(object)val))
				{
					val.localScale = new Vector3(4.8f, 7.2f, 4.8f);
					val.localPosition = new Vector3(0f, 2.07f, 0f);
				}
			}
		}
	}

	internal static ConfigEntry<bool> Enabled;

	private static ManualLogSource log;

	internal static bool Active => Enabled.Value && Object.op_Implicit((Object)(object)Run.instance) && !(Run.instance is InfiniteTowerRun);

	internal static void Initialize(ConfigFile config, ManualLogSource logger)
	{
		log = logger;
		Enabled = config.Bind<bool>("Mechanics", "Enabled", true, "Restore original bands: shared chance, damage stacking, ice slow and moving fire tornado.");
	}

	internal static int VanillaCount(Inventory inventory, ItemDef item)
	{
		return (!Active) ? inventory.GetItemCountEffective(item) : 0;
	}

	internal static bool VanillaBandsReady(CharacterBody body, BuffDef buff)
	{
		return !Active && body.HasBuff(buff);
	}

	private static bool Family(FieldInfo field)
	{
		return field != null && field.DeclaringType == typeof(Items) && new string[2] { "IceRing", "FireRing" }.Contains(field.Name);
	}
}