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";
}
}
}
}