using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PluginConfig.API;
using PluginConfig.API.Fields;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("AirFlip")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Air Flip")]
[assembly: AssemblyTitle("AirFlip")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[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 AirFlip
{
internal static class AirFlipConfig
{
private static BoolField enabled;
private static IntField maxFlips;
private static IntField staminaPerFlip;
private static IntField landingTolerance;
private static IntField failedLandingDamage;
private static FloatField slowDuration;
private static BoolField explosions;
private static BoolField styleBonuses;
internal static bool Enabled
{
get
{
if (enabled != null)
{
return enabled.value;
}
return true;
}
}
internal static int MaxFlips
{
get
{
if (maxFlips == null)
{
return 0;
}
return maxFlips.value;
}
}
internal static int StaminaPerFlip
{
get
{
if (staminaPerFlip == null)
{
return 1;
}
return staminaPerFlip.value;
}
}
internal static int LandingTolerance
{
get
{
if (landingTolerance == null)
{
return 85;
}
return landingTolerance.value;
}
}
internal static int FailedLandingDamage
{
get
{
if (failedLandingDamage == null)
{
return 10;
}
return failedLandingDamage.value;
}
}
internal static float SlowDuration
{
get
{
if (slowDuration == null)
{
return 2f;
}
return slowDuration.value;
}
}
internal static bool ExplosionsEnabled
{
get
{
if (explosions != null)
{
return explosions.value;
}
return true;
}
}
internal static bool StyleBonusesEnabled
{
get
{
if (styleBonuses != null)
{
return styleBonuses.value;
}
return true;
}
}
internal static void Initialize()
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Expected O, but got Unknown
//IL_003a: 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_0056: Expected O, but got Unknown
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Expected O, but got Unknown
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Expected O, but got Unknown
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Expected O, but got Unknown
//IL_0088: Expected O, but got Unknown
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Expected O, but got Unknown
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Expected O, but got Unknown
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Expected O, but got Unknown
//IL_00dd: Expected O, but got Unknown
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Expected O, but got Unknown
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
//IL_0107: Expected O, but got Unknown
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Expected O, but got Unknown
//IL_011c: Expected O, but got Unknown
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Expected O, but got Unknown
PluginConfigurator obj = PluginConfigurator.Create("Air Flip", "dev.ultrakill.airflip");
enabled = new BoolField(obj.rootPanel, "Enable Air Flip", "enabled", true);
ConfigPanel val = new ConfigPanel(obj.rootPanel, "Gameplay", "gameplay");
maxFlips = new IntField(val, "Maximum flips per jump (0 = unlimited)", "max_flips", 0, 0, int.MaxValue);
staminaPerFlip = new IntField(val, "Stamina cost per flip", "stamina_per_flip", 1, 0, 3);
landingTolerance = new IntField(val, "Landing angle tolerance", "landing_tolerance", 85, 45, 90);
ConfigPanel val2 = new ConfigPanel(obj.rootPanel, "Failed flip", "failed_flip");
failedLandingDamage = new IntField(val2, "Damage", "damage", 10, 0, int.MaxValue);
slowDuration = new FloatField(val2, "Slow duration (seconds)", "slow_duration", 2f, 0f, 5f);
ConfigPanel val3 = new ConfigPanel(obj.rootPanel, "Rewards", "rewards");
explosions = new BoolField(val3, "Enable explosions", "explosions", true);
styleBonuses = new BoolField(val3, "Enable style bonuses", "style_bonuses", true);
}
}
[BepInPlugin("dev.ultrakill.airflip", "Air Flip", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Log;
private void Awake()
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
Log = ((BaseUnityPlugin)this).Logger;
AirFlipConfig.Initialize();
new Harmony("dev.ultrakill.airflip").PatchAll(typeof(Plugin).Assembly);
((BaseUnityPlugin)this).Logger.LogInfo((object)"Air Flip loaded");
}
}
internal static class FlipState
{
internal static bool Airborne;
internal static bool FlipStarted;
internal static float FreePitch;
internal static float StartPitch;
internal static float PitchNet;
internal static float MaxPitchNet;
internal static float MinPitchNet;
internal static bool Recovering;
internal static float RecoveryPitch;
internal static float SlowUntil;
internal static float PreviousWalkSpeed;
internal static void Reset()
{
Airborne = false;
FlipStarted = false;
PitchNet = 0f;
MaxPitchNet = 0f;
MinPitchNet = 0f;
}
internal static int CompletedTurns()
{
double num = Math.Max(0.0, Math.Floor(((double)MaxPitchNet + 60.0) / 360.0));
double num2 = Math.Max(0.0, Math.Floor((0.0 - (double)MinPitchNet + 60.0) / 360.0));
double num3 = num + num2;
int num4 = ((num3 >= 2147483647.0) ? int.MaxValue : ((int)num3));
int maxFlips = AirFlipConfig.MaxFlips;
if (maxFlips <= 0)
{
return num4;
}
return Math.Min(num4, maxFlips);
}
internal static void Land(NewMovement player)
{
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
CameraController val = (((Object)(object)player != (Object)null) ? player.cc : null);
Transform val2 = (((Object)(object)val != (Object)null && (Object)(object)val.cam != (Object)null) ? ((Component)val.cam).transform : null);
if ((Object)(object)val2 == (Object)null)
{
Reset();
return;
}
val.rotationX = Mathf.DeltaAngle(0f, val.rotationX);
if (!FlipStarted)
{
BeginRecoveryIfOutsideLimit(val);
Reset();
return;
}
bool flag = Mathf.Abs(Mathf.DeltaAngle(StartPitch, val.rotationX)) <= (float)AirFlipConfig.LandingTolerance;
bool flag2 = val2.up.y <= -0.5f;
bool num = (Object)(object)player.gc != (Object)null && player.gc.heavyFall;
int num2 = CompletedTurns();
if (num2 > 0)
{
player.boostCharge = Mathf.Max(0f, player.boostCharge - 100f * (float)AirFlipConfig.StaminaPerFlip * (float)num2);
}
bool flag3 = num && flag2;
bool flag4 = flag && num2 >= 1;
int num3 = ((flag4 || flag3) ? Mathf.Max(1, num2) : 0);
if (flag3)
{
SpawnFlipBlast(player, 1.5f + 0.12f * (float)(num3 - 1), ScaledBlastDamage(150, 25, num3));
AwardFlipStyle(player, num3, backSlam: true);
}
else if (flag4)
{
SpawnFlipBlast(player, 1.1f + 0.12f * (float)(num3 - 1), ScaledBlastDamage(80, 25, num3));
AwardFlipStyle(player, num3, backSlam: false);
}
else if (!flag)
{
ApplyNonLethalFlipPenalty(player);
if (AirFlipConfig.SlowDuration > 0f)
{
SlowUntil = Time.time + AirFlipConfig.SlowDuration;
}
}
BeginRecoveryIfOutsideLimit(val);
Reset();
}
private static void BeginRecoveryIfOutsideLimit(CameraController camera)
{
if (Mathf.Abs(camera.rotationX) <= 85f)
{
Recovering = false;
return;
}
RecoveryPitch = Mathf.Clamp(StartPitch, -85f, 85f);
Recovering = Mathf.Abs(RecoveryPitch - camera.rotationX) > 1f;
}
private static void AwardFlipStyle(NewMovement player, int flips, bool backSlam)
{
if (flips < 1 || !AirFlipConfig.StyleBonusesEnabled)
{
return;
}
string text = (backSlam ? "airflip.poolofblood" : "airflip.flip");
int num = (int)Math.Min(2147483647L, 100 + (long)(flips - 1) * 75L);
try
{
StyleHUD instance = MonoSingleton<StyleHUD>.Instance;
if (instance != null)
{
instance.AddPoints(num, text, ((Component)player).gameObject, (EnemyIdentifier)null, flips, "", "");
}
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Could not award Pool of Blood style: " + ex.Message));
}
}
private static int ScaledBlastDamage(int baseDamage, int perExtraTurn, int flips)
{
long val = baseDamage + (long)Math.Max(0, flips - 1) * (long)perExtraTurn;
return (int)Math.Min(2147483647L, val);
}
private static void ApplyNonLethalFlipPenalty(NewMovement player)
{
if (!((Object)(object)player == (Object)null) && !player.dead && AirFlipConfig.FailedLandingDamage > 0)
{
int num = Mathf.Min(AirFlipConfig.FailedLandingDamage, Mathf.Max(0, player.hp - 1));
if (num > 0)
{
player.GetHurt(num, true, 1f, false, false, 0.35f, true);
}
else
{
player.antiHp = Mathf.Min(99f, player.antiHp + 3.5f);
}
}
}
private static void SpawnFlipBlast(NewMovement player, float size, int damage)
{
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: 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_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: 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_013a: Unknown result type (might be due to invalid IL or missing references)
//IL_0140: Unknown result type (might be due to invalid IL or missing references)
if (!AirFlipConfig.ExplosionsEnabled)
{
return;
}
DefaultReferenceManager instance = MonoSingleton<DefaultReferenceManager>.Instance;
if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance.explosion == (Object)null))
{
Vector3 val = (((Object)(object)player.gc != (Object)null) ? ((Component)player.gc).transform.position : ((Component)player).transform.position);
GameObject val2 = Object.Instantiate<GameObject>(instance.explosion, val, Quaternion.identity);
Explosion[] componentsInChildren = val2.GetComponentsInChildren<Explosion>(true);
foreach (Explosion obj in componentsInChildren)
{
obj.maxSize *= size;
obj.speed *= size;
obj.damage = Mathf.Max(obj.damage * 2, damage);
obj.enemyDamageMultiplier = Mathf.Max(obj.enemyDamageMultiplier, 1.5f);
obj.enemy = false;
obj.canHit = (AffectedSubjects)2;
}
Light[] componentsInChildren2 = val2.GetComponentsInChildren<Light>(true);
foreach (Light obj2 in componentsInChildren2)
{
obj2.range *= size;
}
ParticleSystem[] componentsInChildren3 = val2.GetComponentsInChildren<ParticleSystem>(true);
for (int i = 0; i < componentsInChildren3.Length; i++)
{
MainModule main = componentsInChildren3[i].main;
((MainModule)(ref main)).scalingMode = (ParticleSystemScalingMode)0;
}
Transform transform = val2.transform;
transform.localScale *= size;
CameraController cc = player.cc;
if (cc != null)
{
cc.CameraShake(size);
}
}
}
}
[HarmonyPatch(typeof(CameraController), "LateUpdate")]
[HarmonyPriority(0)]
internal static class FreeAirPitch
{
private static void Prefix(CameraController __instance)
{
if ((Object)(object)__instance == (Object)null)
{
return;
}
NewMovement nm = __instance.nm;
if (!CanControl(__instance, nm))
{
StopAirFlip(__instance);
}
else if (!AirFlipConfig.Enabled)
{
if (FlipState.Airborne || FlipState.Recovering)
{
NormalizeAndClampPitch(__instance);
}
StopAirFlip(__instance);
}
else if (nm.gc.onGround)
{
if (FlipState.Airborne)
{
FlipState.Land(nm);
}
}
else if (!FlipState.Airborne)
{
FlipState.Airborne = true;
FlipState.FreePitch = __instance.rotationX;
FlipState.StartPitch = __instance.rotationX;
FlipState.PitchNet = 0f;
FlipState.MaxPitchNet = 0f;
FlipState.MinPitchNet = 0f;
FlipState.FlipStarted = false;
}
}
private static void Postfix(CameraController __instance)
{
if ((Object)(object)__instance == (Object)null)
{
return;
}
NewMovement nm = __instance.nm;
if (!CanControl(__instance, nm))
{
StopAirFlip(__instance);
}
else if (!AirFlipConfig.Enabled)
{
StopAirFlip(__instance);
}
else if (nm.gc.onGround)
{
if (FlipState.Recovering)
{
float rotationX = __instance.rotationX;
RecoverPitch(__instance);
if (Mathf.Abs(rotationX - __instance.rotationX) > 0.01f)
{
__instance.ApplyRotations(false);
}
}
}
else if (FlipState.Airborne)
{
float num = __instance.rotationX - FlipState.FreePitch;
FlipState.FreePitch = __instance.rotationX;
FlipState.PitchNet += num;
FlipState.MaxPitchNet = Mathf.Max(FlipState.MaxPitchNet, FlipState.PitchNet);
FlipState.MinPitchNet = Mathf.Min(FlipState.MinPitchNet, FlipState.PitchNet);
if (FlipState.MaxPitchNet >= 150f || FlipState.MinPitchNet <= -150f)
{
FlipState.FlipStarted = true;
}
}
}
private static void NormalizeAndClampPitch(CameraController camera)
{
if (!((Object)(object)camera == (Object)null))
{
float rotationX = camera.rotationX;
camera.rotationX = Mathf.Clamp(Mathf.DeltaAngle(0f, rotationX), -90f, 90f);
if (Mathf.Abs(rotationX - camera.rotationX) > 0.01f)
{
camera.ApplyRotations(false);
}
}
}
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
List<CodeInstruction> list = new List<CodeInstruction>(instructions);
MethodInfo methodInfo = AccessTools.Method(typeof(Mathf), "Abs", new Type[1] { typeof(float) }, (Type[])null);
MethodInfo operand = AccessTools.Method(typeof(FreeAirPitch), "ClampPitchForVanilla", (Type[])null, (Type[])null);
int num = 0;
for (int i = 0; i + 1 < list.Count; i++)
{
if (CodeInstructionExtensions.Calls(list[i], methodInfo) && list[i + 1].opcode == OpCodes.Ldc_R4 && list[i + 1].operand is float num2 && Mathf.Approximately(num2, 90f))
{
list[i].operand = operand;
num++;
}
}
if (num != 1)
{
Plugin.Log.LogWarning((object)("Camera pitch clamp patch found " + num + " targets (expected one)."));
}
return list;
}
private static float ClampPitchForVanilla(float angle)
{
if (!AirFlipConfig.Enabled || !FlipState.Airborne)
{
return Mathf.Abs(angle);
}
return 0f;
}
private static bool CanControl(CameraController camera, NewMovement player)
{
if ((Object)(object)camera == (Object)null || (Object)(object)player == (Object)null || (Object)(object)player.gc == (Object)null || player.dead || player.levelOver || !player.activated || !camera.activated)
{
return false;
}
GameStateManager instance = GameStateManager.Instance;
if (!((Object)(object)instance == (Object)null))
{
return !instance.CameraLocked;
}
return true;
}
private static void StopAirFlip(CameraController camera)
{
FlipState.Recovering = false;
FlipState.Reset();
}
private static void RecoverPitch(CameraController camera)
{
if (FlipState.Recovering && !((Object)(object)camera == (Object)null))
{
camera.rotationX = Mathf.MoveTowards(camera.rotationX, FlipState.RecoveryPitch, 240f * Time.deltaTime);
if (Mathf.Abs(FlipState.RecoveryPitch - camera.rotationX) <= 1f)
{
camera.rotationX = FlipState.RecoveryPitch;
FlipState.Recovering = false;
}
}
}
}
[HarmonyPatch(typeof(NewMovement), "LandingImpact")]
internal static class LandingFlip
{
private static void Prefix(NewMovement __instance)
{
FlipState.Land(__instance);
}
}
[HarmonyPatch(typeof(NewMovement), "Update")]
internal static class LandingSlow
{
private static void Prefix(NewMovement __instance, out float __state)
{
__state = __instance.walkSpeed;
if (FlipState.PreviousWalkSpeed > 0f)
{
__instance.walkSpeed = FlipState.PreviousWalkSpeed;
}
}
private static void Postfix(NewMovement __instance, float __state)
{
FlipState.PreviousWalkSpeed = __instance.walkSpeed;
if (Time.time < FlipState.SlowUntil)
{
__instance.walkSpeed *= 0.5f;
}
}
}
[HarmonyPatch(typeof(StyleHUD), "Start")]
internal static class RegisterFlipStyle
{
private static void Postfix(StyleHUD __instance)
{
__instance.RegisterStyleItem("airflip.poolofblood", "<color=#B00020>POOL OF BLOOD</color>");
__instance.RegisterStyleItem("airflip.flip", "<color=#FF6B35>FLIP</color>");
}
}
}