Decompiled source of AuricAegis v1.1.2

AuricAegis.dll

Decompiled 6 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using HutongGames.PlayMaker;
using HutongGames.PlayMaker.Actions;
using Microsoft.CodeAnalysis;
using Silksong.FsmUtil;
using TeamCherry.Localization;
using UnityEngine;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("AuricAegis")]
[assembly: AssemblyDescription("Auric Aegis")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Astrum Nova")]
[assembly: AssemblyProduct("Auric Aegis")]
[assembly: AssemblyCopyright("Copyright \ufffd 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("d13a3b2c-1a23-4c45-9123-7f5a7b8e9abc")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Silksong.Mods.PrimedSentinel
{
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("com.astrumnova.auricaegis", "Auric Aegis", "0.0.1")]
	[BepInProcess("Hollow Knight Silksong.exe")]
	public class PrimedSentinel : BaseUnityPlugin
	{
		private static int INITIAL_HP = 1800;

		private static int PHASE_2_THRESHOLD = 1500;

		private static int PARRY_DAMAGE = 2;

		private static int STUN_QUOTA = 100;

		private static int PARRY_SILK_GAIN_MULTIPLIER = 1;

		private static int stunCounter;

		private static GameObject gameObj;

		public static PlayMakerFSM control;

		private static HealthManager healthManager;

		private static bool enable;

		private static bool phase2;

		private static bool risingSlashedOnce;

		private static bool diveFollowUpSelected;

		private static bool risingSlashing;

		private static bool windSlashedOnce;

		private static bool dashStabbedOnce = true;

		private static bool isCrossStitching;

		private static readonly string[] stunStates = new string[5] { "Stun Start", "Stun Air", "Stun Land", "Stunned", "Stun Damage" };

		private static readonly ManualLogSource logger = Logger.CreateLogSource("Auric Aegis");

		public static void log(string msg)
		{
			logger.LogInfo((object)msg);
		}

		private void Awake()
		{
			INITIAL_HP = ((BaseUnityPlugin)this).Config.Bind<int>("Boss Settings", "Initial HP", 1800, "The total HP the boss starts with at the beginning of the fight.").Value;
			PHASE_2_THRESHOLD = ((BaseUnityPlugin)this).Config.Bind<int>("Boss Settings", "Phase 2 Threshold", 1500, "When HP drops to this value, the next stun will trigger Phase 2.").Value;
			PARRY_DAMAGE = ((BaseUnityPlugin)this).Config.Bind<int>("Boss Settings", "Parry Damage", 2, "Amount of damage dealt to the boss each frame the player parries.").Value;
			STUN_QUOTA = ((BaseUnityPlugin)this).Config.Bind<int>("Boss Settings", "Stun Quota", 100, "How many parried frames are required to stun the boss.").Value;
			PARRY_SILK_GAIN_MULTIPLIER = ((BaseUnityPlugin)this).Config.Bind<int>("Boss Settings", "Parry Silk Gain Multiplier", 1, "Multiplier for parry silk gain, by default it does nothing since its set to 1.").Value;
			Harmony.CreateAndPatchAll(typeof(PrimedSentinel), (string)null);
			Harmony.CreateAndPatchAll(typeof(Patch_SpawnObjectFromGlobalPool_OnEnter), (string)null);
			((MonoBehaviour)this).StartCoroutine(WaitAndPatch());
			((BaseUnityPlugin)this).Logger.LogInfo((object)"com.astrumnova.auricaegis loaded and initialized!");
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(PlayMakerFSM), "OnEnable")]
		private static void OnFsmEnabled(PlayMakerFSM __instance)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)control == (Object)null && __instance.FsmName == "Control")
			{
				Scene scene = ((Component)__instance).gameObject.scene;
				if (((Scene)(ref scene)).name == "Hang_17b" && ((IEnumerable<FsmState>)__instance.FsmStates).FirstOrDefault((Func<FsmState, bool>)((FsmState state) => state.Name == "First Idle")) != null)
				{
					PlayerData.instance.encounteredSongChevalierBoss = true;
					enable = true;
					control = __instance;
					gameObj = ((Component)__instance).gameObject;
					healthManager = gameObj.GetComponent<HealthManager>();
					healthManager.hp = INITIAL_HP;
					removeEventFromState("Target Check", "NEEDOLIN");
					removeEventFromState("Rising Slash Followup", "FALL");
					removeEventFromState("Rising Slash Followup", "STEP");
					removeEventFromState("WJ Cross Slash", "CANCEL");
					removeEventFromState("Jump Rise", "LAND");
					FsmUtil.GetFirstActionOfType<SetVelocityByScale>(control, "Rising Slash").speed = FsmFloat.op_Implicit(-60f);
					FsmUtil.GetFirstActionOfType<SetVelocityAsAngle>(control, "Dive").speed = FsmFloat.op_Implicit(120f);
					FsmUtil.GetFirstActionOfType<SetVelocityByScale>(control, "DashStab Dash").speed = FsmFloat.op_Implicit(-100f);
					FsmUtil.GetFirstActionOfType<SetFloatValue>(control, "Windslash G").floatValue = FsmFloat.op_Implicit(-70f);
					FsmUtil.GetFirstActionOfType<SetVelocity2d>(control, "Windslash G").y = FsmFloat.op_Implicit(40f);
					FsmUtil.GetFirstActionOfType<SetFloatValue>(control, "Windslash A").floatValue = FsmFloat.op_Implicit(-70f);
					FsmUtil.GetLastActionOfType<SetFloatValue>(control, "Windslash A").floatValue = FsmFloat.op_Implicit(-40f);
					FsmUtil.GetLastActionOfType<SetVelocityByScale>(control, "CrossSlash Recoil").speed = FsmFloat.op_Implicit(15f);
					FsmUtil.GetFirstActionOfType<Wait>(control, "Idle").time = FsmFloat.op_Implicit(-1f);
					FsmUtil.GetFirstActionOfType<ConvertBoolToFloat>(control, "Idle").floatVariable = FsmFloat.op_Implicit(0f);
					FsmUtil.GetFirstActionOfType<ConvertBoolToFloat>(control, "Idle").falseValue = FsmFloat.op_Implicit(0f);
					FsmUtil.GetLastActionOfType<FaceObjectV2>(control, "Dive Dir").pauseBetweenTurns = 0f;
					FsmUtil.GetLastActionOfType<Wait>(control, "CS Antic").time = FsmFloat.op_Implicit(0.25f);
				}
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(FsmState), "OnEnter")]
		private static void OnFSMStateEntered(FsmState __instance)
		{
			//IL_037f: Unknown result type (might be due to invalid IL or missing references)
			//IL_058d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0426: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0562: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e2: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)control == (Object)null)
			{
				enable = false;
				return;
			}
			switch (__instance.Name)
			{
			case "Battle Start":
				stunCounter = 0;
				phase2 = false;
				risingSlashedOnce = false;
				diveFollowUpSelected = false;
				risingSlashing = false;
				windSlashedOnce = false;
				dashStabbedOnce = true;
				isCrossStitching = false;
				healthManager.IsInvincible = true;
				break;
			case "Stun Recover":
			case "Damage Recover":
				stunCounter = 0;
				if (healthManager.hp <= PHASE_2_THRESHOLD && !phase2)
				{
					healthManager.hp = PHASE_2_THRESHOLD;
					phase2 = true;
					Object.Destroy((Object)(object)FSMUtility.LocateMyFSM(gameObj, "Stun Control"));
					control.SetState("Rising Slash Antic");
				}
				break;
			case "Rising Slash Antic":
			{
				risingSlashing = true;
				float x = ((Component)control).transform.position.x;
				FsmUtil.GetFirstActionOfType<SetVelocityByScale>(control, "Rising Slash").speed = FsmFloat.op_Implicit(-60f);
				ChangeTelegraphy(__instance, "FINISHED", 0.6f);
				if (phase2)
				{
					FsmUtil.GetFirstActionOfType<SetVelocityByScale>(control, "Rising Slash").ySpeed = FsmFloat.op_Implicit(13.70306f);
					((MonoBehaviour)control).StartCoroutine(FixRisingSlash(1.39f, x));
					ChangeTelegraphy(__instance, "FINISHED", 1.4f);
				}
				else
				{
					FsmUtil.GetFirstActionOfType<SetVelocityByScale>(control, "Rising Slash").ySpeed = FsmFloat.op_Implicit(((Component)HeroController.instance).transform.position.y * 3f);
				}
				break;
			}
			case "Rising Slash Followup":
				if (phase2)
				{
					if (!risingSlashedOnce)
					{
						risingSlashedOnce = true;
						control.SetState("Near Air Attack");
					}
					else
					{
						risingSlashedOnce = false;
						control.SetState("Far Air Attack");
					}
				}
				break;
			case "Dive Antic":
				ChangeTelegraphy(__instance, "FINISHED", 0.3f);
				((MonoBehaviour)control).StartCoroutine(diveTurnAround(((Component)control).transform.position.x));
				break;
			case "Dive Land":
				if (phase2 && !diveFollowUpSelected)
				{
					diveFollowUpSelected = true;
					string[] array2 = new string[3] { "Rapid Slash Dash", "Dash Slash 1", "Windslash G" };
					((MonoBehaviour)control).StartCoroutine(scheduleNextState(0.2f, Extensions.GetRandomElement<string>(array2), disableDiveFollowup: true));
				}
				if (risingSlashing)
				{
					risingSlashing = false;
				}
				break;
			case "WindSlash Type":
				FsmUtil.GetLastActionOfType<SetFloatValue>(control, "Windslash A").floatValue = FsmFloat.op_Implicit(0f - (60f - ((Component)HeroController.instance).transform.position.y * 3f));
				break;
			case "WindSlash Antic":
				if (((Component)control).transform.position.y < 7f)
				{
					ChangeTelegraphy(__instance, "FINISHED", 0.4f);
				}
				else if (phase2)
				{
					ChangeTelegraphy(__instance, "FINISHED", 0.6f);
				}
				break;
			case "WindSlash":
			{
				bool flag = ((Component)control).transform.position.y > 10f;
				if (phase2 && windSlashedOnce)
				{
					windSlashedOnce = false;
					((MonoBehaviour)control).StartCoroutine(scheduleNextState(0.2f, flag ? "Dive Dir" : "DashStab Antic"));
				}
				else if (flag && !windSlashedOnce)
				{
					windSlashedOnce = true;
				}
				break;
			}
			case "DashStab Antic":
				if (phase2)
				{
					if (dashStabbedOnce)
					{
						ChangeTelegraphy(__instance, "FINISHED", 0.5f);
						FsmUtil.GetFirstActionOfType<SetVelocityByScale>(control, "DashStab Dash").speed = FsmFloat.op_Implicit(-200f);
					}
					else
					{
						ChangeTelegraphy(__instance, "FINISHED", 0.1f);
						FsmUtil.GetFirstActionOfType<SetVelocityByScale>(control, "DashStab Dash").speed = FsmFloat.op_Implicit(-150f);
					}
				}
				else
				{
					ChangeTelegraphy(__instance, "FINISHED", 0.5f);
				}
				break;
			case "DashStab Dash":
				ChangeTelegraphy(__instance, "FINISHED", phase2 ? 0.02f : 0.05f);
				break;
			case "Stab 1":
				if (phase2)
				{
					((MonoBehaviour)control).StartCoroutine(delayedTurnAround(0.15f));
					if (dashStabbedOnce)
					{
						((MonoBehaviour)control).StartCoroutine(scheduleNextState(0.2f, "DashStab Antic"));
						dashStabbedOnce = false;
					}
					else
					{
						dashStabbedOnce = true;
					}
				}
				break;
			case "CrossSlash Recoil":
			{
				string[] array = new string[2] { "Dive Dir", "Windslash A" };
				if (!risingSlashing)
				{
					((MonoBehaviour)control).StartCoroutine(scheduleNextState(phase2 ? 0.2f : 0.1f, Extensions.GetRandomElement<string>(array)));
				}
				if (!phase2 && risingSlashing)
				{
					risingSlashing = false;
				}
				break;
			}
			case "Hornet Dead":
				if ((Object)(object)control != (Object)null)
				{
					deathReset();
				}
				break;
			case "Parry Clash":
				isCrossStitching = true;
				if (phase2)
				{
					healthManager.IsInvincible = true;
				}
				((MonoBehaviour)control).StartCoroutine(disableInvincibility());
				break;
			}
		}

		public void FixedUpdate()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			if (!enable)
			{
				return;
			}
			if (risingSlashing)
			{
				Vector3 position = ((Component)HeroController.instance).transform.position;
				if ((double)position.x > 51.62)
				{
					((Component)HeroController.instance).transform.position = new Vector3(51.61f, position.y, position.z);
				}
				if ((double)position.x < 27.51)
				{
					((Component)HeroController.instance).transform.position = new Vector3(27.525f, position.y, position.z);
				}
			}
			if (HeroController.instance.IsParrying() && !isCrossStitching && HeroController.instance.silkSpecialFSM.ActiveStateName != "Parry Stance")
			{
				if (stunCounter % 10 == 0 && stunCounter != 0)
				{
					HeroController.instance.AddSilk(PARRY_SILK_GAIN_MULTIPLIER, true);
				}
				if (healthManager.hp > PARRY_DAMAGE)
				{
					HealthManager obj = healthManager;
					obj.hp -= PARRY_DAMAGE;
				}
				else
				{
					healthManager.hp = 1;
				}
				stunCounter += PARRY_DAMAGE;
				if (stunCounter >= STUN_QUOTA && !phase2 && ((Component)control).transform.position.y < 8f && !risingSlashing)
				{
					control.SendEvent("STUN");
				}
				healthManager.SpriteFlash.FlashEnemyHit();
			}
			if (!phase2)
			{
				if (stunStates.Contains(control.ActiveStateName) && healthManager.IsInvincible)
				{
					healthManager.IsInvincible = false;
				}
				else if (!stunStates.Contains(control.ActiveStateName) && !healthManager.IsInvincible)
				{
					healthManager.IsInvincible = true;
				}
			}
			else if (healthManager.hp <= 0)
			{
				deathReset();
			}
		}

		private static void ChangeTelegraphy(FsmState state, string eventName, float delay)
		{
			((MonoBehaviour)control).StartCoroutine(ForceNextState(state, eventName, delay));
		}

		private static void removeEventFromState(string stateName, string eventName)
		{
			FsmState val = ((IEnumerable<FsmState>)control.FsmStates).FirstOrDefault((Func<FsmState, bool>)((FsmState state) => state.Name == stateName));
			val.Transitions = val.Transitions.Where((FsmTransition t) => t.EventName != eventName).ToArray();
		}

		private static void deathReset()
		{
			gameObj = null;
			enable = false;
			control = null;
			healthManager = null;
			stunCounter = 0;
			phase2 = false;
			risingSlashedOnce = false;
			diveFollowUpSelected = false;
			risingSlashing = false;
			windSlashedOnce = false;
			dashStabbedOnce = true;
			isCrossStitching = false;
		}

		private static IEnumerator WaitAndPatch()
		{
			yield return (object)new WaitForSeconds(2f);
			Harmony.CreateAndPatchAll(typeof(Language_Get_Patch), (string)null);
		}

		private static IEnumerator disableInvincibility()
		{
			yield return (object)new WaitForSeconds(1.5f);
			isCrossStitching = false;
			if (phase2)
			{
				healthManager.IsInvincible = false;
			}
		}

		private static IEnumerator ForceNextState(FsmState state, string eventName, float delay)
		{
			yield return (object)new WaitForSeconds(delay);
			FsmTransition transition = ((IEnumerable<FsmTransition>)state.Transitions).FirstOrDefault((Func<FsmTransition, bool>)((FsmTransition t) => t.EventName == eventName));
			if (transition != null)
			{
				control.SetState(transition.ToState);
			}
		}

		private static IEnumerator scheduleNextState(float delay, string state, bool disableDiveFollowup = false)
		{
			yield return (object)new WaitForSeconds(delay);
			control.SetState(state);
			if (disableDiveFollowup)
			{
				diveFollowUpSelected = false;
			}
		}

		private static IEnumerator FixRisingSlash(float delay, float startingX)
		{
			yield return (object)new WaitForSeconds(delay);
			float knightX = ((Component)control).transform.position.x;
			float hornetX = ((Component)HeroController.instance).transform.position.x;
			int sign = ((!((knightX - hornetX) * (knightX - startingX) > 0f)) ? 1 : (-1));
			FsmUtil.GetFirstActionOfType<SetVelocityByScale>(control, "Rising Slash").speed = FsmFloat.op_Implicit(60f * (float)sign);
		}

		private static IEnumerator diveTurnAround(float startingX)
		{
			yield return (object)new WaitForSeconds(0.5f);
			float knightX = ((Component)control).transform.position.x;
			float hornetX = ((Component)HeroController.instance).transform.position.x;
			if (knightX > startingX)
			{
				if (hornetX < knightX)
				{
					Extensions.FlipLocalScale(((Component)control).transform, true, false, false);
				}
			}
			else if (hornetX > knightX)
			{
				Extensions.FlipLocalScale(((Component)control).transform, true, false, false);
			}
		}

		private static IEnumerator delayedTurnAround(float delay)
		{
			yield return (object)new WaitForSeconds(delay);
			Extensions.FlipLocalScale(((Component)control).transform, true, false, false);
		}
	}
	[HarmonyPatch(typeof(SpawnObjectFromGlobalPool), "OnEnter")]
	public static class Patch_SpawnObjectFromGlobalPool_OnEnter
	{
		private static readonly Vector3 CROSSSLASH = new Vector3(2.5f, 2.5f, 1f);

		private static readonly Vector3 PROJECTILE = new Vector3(2.25f, 2.2f, 1f);

		[HarmonyPostfix]
		private static void Postfix(SpawnObjectFromGlobalPool __instance)
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)PrimedSentinel.control == (Object)null || (Object)(object)__instance.storeObject.Value == (Object)null)
			{
				return;
			}
			GameObject gameObject = __instance.storeObject.Value.gameObject;
			if (!((Object)(object)gameObject == (Object)null))
			{
				Transform transform = gameObject.transform;
				if (((Object)transform).name.StartsWith("Song Knight CrossSlash"))
				{
					transform.localScale = CROSSSLASH;
					MakeProjectileRenderAboveWalls(__instance.storeObject.Value.gameObject);
				}
				else if (((Object)transform).name.StartsWith("Song Knight Projectile"))
				{
					transform.localScale = PROJECTILE;
					__instance.storeObject.Value.gameObject.GetComponent<Collider2D>().isTrigger = true;
					MakeProjectileIgnoreEnvironment(__instance.storeObject.Value.gameObject);
					RemoveProjectileWallEvents(__instance.storeObject.Value.gameObject);
					MakeProjectileRenderAboveWalls(__instance.storeObject.Value.gameObject);
				}
			}
		}

		private static void MakeProjectileIgnoreEnvironment(GameObject projectile)
		{
			Collider2D[] componentsInChildren = projectile.GetComponentsInChildren<Collider2D>(true);
			if (componentsInChildren == null || componentsInChildren.Length == 0)
			{
				return;
			}
			Collider2D[] array = componentsInChildren;
			foreach (Collider2D val in array)
			{
				int num = LayerMask.NameToLayer("Terrain");
				if (num >= 0)
				{
					Physics2D.IgnoreLayerCollision(projectile.layer, num, true);
				}
				val.isTrigger = true;
			}
		}

		private static void MakeProjectileRenderAboveWalls(GameObject projectile)
		{
			tk2dSprite[] componentsInChildren = projectile.GetComponentsInChildren<tk2dSprite>(true);
			tk2dSprite[] array = componentsInChildren;
			foreach (tk2dSprite val in array)
			{
				((tk2dBaseSprite)val).SortingOrder = 1000;
			}
		}

		private static void RemoveProjectileWallEvents(GameObject projectile)
		{
			PlayMakerFSM val = FSMUtility.LocateMyFSM(projectile, "Control");
			FsmState[] fsmStates = val.FsmStates;
			foreach (FsmState val2 in fsmStates)
			{
				FsmTransition[] array = val2.Transitions.Where((FsmTransition t) => !t.EventName.Equals("WALL", StringComparison.OrdinalIgnoreCase)).ToArray();
				if (array.Length != val2.Transitions.Length)
				{
					val2.Transitions = array;
				}
			}
			string[] array2 = new string[2] { "Wall End", "Floor?" };
			foreach (string text in array2)
			{
				FsmState state = FsmUtil.GetState(val, text);
				if (state != null)
				{
					state.Transitions = Array.Empty<FsmTransition>();
					state.Actions = Array.Empty<FsmStateAction>();
				}
			}
		}
	}
	[HarmonyPatch(typeof(Language), "Get")]
	[HarmonyPatch(new Type[]
	{
		typeof(string),
		typeof(string)
	})]
	public static class Language_Get_Patch
	{
		private static void Postfix(string key, string sheetTitle, ref string __result)
		{
			if (key == "SONG_KNIGHT_SUPER")
			{
				__result = "The Last Sentinel";
			}
			if (key == "SONG_KNIGHT_MAIN")
			{
				__result = "Auric Aegis";
			}
		}
	}
}