Decompiled source of Sandevistan v1.8.7

plugins/Sandevistan.dll

Decompiled 9 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using RoR2;
using RoR2.Projectile;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Rendering;
using UnityEngine.Rendering.PostProcessing;

[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("Sandevistan")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Sandevistan")]
[assembly: AssemblyTitle("Sandevistan")]
[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 Sandevistan
{
	[BepInPlugin("com.ror2mods.sandevistan", "Sandevistan", "1.8.7")]
	[DefaultExecutionOrder(32000)]
	public sealed class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(EntityStateMachine), "ManagedFixedUpdate")]
		private static class EnemyStateTimePatch
		{
			private static void Prefix(EntityStateMachine __instance, ref float deltaTime)
			{
				if (_worldEffectsActive && IsEnemy((Component)(object)__instance))
				{
					deltaTime *= _activeEnemyTimeScale;
				}
			}
		}

		[HarmonyPatch(typeof(GenericSkill), "ExecuteIfReady")]
		private static class SkillProjectileParryPatch
		{
			private static void Postfix(GenericSkill __instance, bool __result)
			{
				if (__result && _worldEffectsActive && !((Object)(object)_activePlayerBody == (Object)null) && (Object)(object)((Component)__instance).GetComponentInParent<CharacterBody>() == (Object)(object)_activePlayerBody)
				{
					_parryWindowUntil = Time.unscaledTime + 0.2f;
				}
			}
		}

		[HarmonyPatch(typeof(ProjectileSimple), "SetForwardSpeed")]
		private static class EnemyProjectileSpeedPatch
		{
			private static void Prefix(ProjectileSimple __instance, ref float speed)
			{
				if (_worldEffectsActive && IsEnemyProjectile((Component)(object)__instance))
				{
					speed *= _activeProjectileTimeScale;
				}
			}
		}

		[HarmonyPatch(typeof(ProjectileSimple), "FixedUpdate")]
		private static class EnemyProjectileLifetimePatch
		{
			private static void Prefix(ProjectileSimple __instance)
			{
				if (_worldEffectsActive && IsEnemyProjectile((Component)(object)__instance))
				{
					float num = 1f - _activeProjectileTimeScale;
					float num2 = Time.deltaTime * num;
					Traverse val = Traverse.Create((object)__instance);
					val.Field("stopwatch").SetValue((object)Mathf.Max(0f, val.Field("stopwatch").GetValue<float>() - num2));
					val.Field("oscillationStopwatch").SetValue((object)Mathf.Max(0f, val.Field("oscillationStopwatch").GetValue<float>() - num2));
				}
			}
		}

		[HarmonyPatch(typeof(MissileController), "FixedUpdate")]
		private static class EnemyMissileTimePatch
		{
			private struct MissileState
			{
				public float MaxVelocity;

				public float Acceleration;
			}

			private static void Prefix(MissileController __instance, out MissileState __state)
			{
				__state = default(MissileState);
				if (_worldEffectsActive && IsEnemyProjectile((Component)(object)__instance))
				{
					Traverse val = Traverse.Create((object)__instance);
					__state.MaxVelocity = val.Field("maxVelocity").GetValue<float>();
					__state.Acceleration = val.Field("acceleration").GetValue<float>();
					val.Field("maxVelocity").SetValue((object)(__state.MaxVelocity * _activeProjectileTimeScale));
					val.Field("acceleration").SetValue((object)(__state.Acceleration * _activeProjectileTimeScale));
					float value = val.Field("timer").GetValue<float>();
					float num = Time.deltaTime * (1f - _activeProjectileTimeScale);
					val.Field("timer").SetValue((object)Mathf.Max(0f, value - num));
				}
			}

			private static void Postfix(MissileController __instance, MissileState __state)
			{
				if (!(__state.MaxVelocity <= 0f) || !(__state.Acceleration <= 0f))
				{
					Traverse obj = Traverse.Create((object)__instance);
					obj.Field("maxVelocity").SetValue((object)__state.MaxVelocity);
					obj.Field("acceleration").SetValue((object)__state.Acceleration);
				}
			}
		}

		[HarmonyPatch(typeof(ProjectileImpactExplosion), "FixedUpdate")]
		private static class EnemyProjectileExplosionLifetimePatch
		{
			private static void Prefix(ProjectileImpactExplosion __instance)
			{
				if (_worldEffectsActive && IsEnemyProjectile((Component)(object)__instance))
				{
					float num = Time.fixedDeltaTime * (1f - _activeProjectileTimeScale);
					Traverse val = Traverse.Create((object)__instance);
					val.Field("stopwatch").SetValue((object)Mathf.Max(0f, val.Field("stopwatch").GetValue<float>() - num));
					if (val.Field("timerAfterImpact").GetValue<bool>())
					{
						val.Field("stopwatchAfterImpact").SetValue((object)Mathf.Max(0f, val.Field("stopwatchAfterImpact").GetValue<float>() - num));
					}
				}
			}
		}

		[HarmonyPatch(typeof(HoldoutZoneController), "DoUpdate")]
		private static class TeleporterChargeTimePatch
		{
			private static void Prefix(HoldoutZoneController __instance, ref float deltaTime)
			{
				TeleporterInteraction instance = TeleporterInteraction.instance;
				if (_worldEffectsActive && (Object)(object)instance != (Object)null && (Object)(object)instance.holdoutZoneController == (Object)(object)__instance)
				{
					deltaTime *= _activeTeleporterTimeScale;
				}
			}
		}

		private struct LayerState
		{
			public readonly GameObject GameObject;

			public readonly int Layer;

			public LayerState(GameObject gameObject, int layer)
			{
				GameObject = gameObject;
				Layer = layer;
			}
		}

		private struct EnemyBodyState
		{
			public readonly float BaseMoveSpeed;

			public readonly float BaseAttackSpeed;

			public readonly float BaseAcceleration;

			public EnemyBodyState(float baseMoveSpeed, float baseAttackSpeed, float baseAcceleration)
			{
				BaseMoveSpeed = baseMoveSpeed;
				BaseAttackSpeed = baseAttackSpeed;
				BaseAcceleration = baseAcceleration;
			}
		}

		private struct AudioSourceState
		{
			public readonly float Pitch;

			public readonly float Volume;

			public AudioSourceState(float pitch, float volume)
			{
				Pitch = pitch;
				Volume = volume;
			}
		}

		private struct AudioFilterState
		{
			public readonly AudioLowPassFilter Filter;

			public readonly bool Created;

			public readonly bool Enabled;

			public readonly float CutoffFrequency;

			public readonly float Resonance;

			public AudioFilterState(AudioLowPassFilter filter, bool created, bool enabled, float cutoffFrequency, float resonance)
			{
				Filter = filter;
				Created = created;
				Enabled = enabled;
				CutoffFrequency = cutoffFrequency;
				Resonance = resonance;
			}
		}

		private sealed class BodyStatChange
		{
			private readonly CharacterBody _body;

			private readonly float _moveSpeedDelta;

			private readonly float _attackSpeedDelta;

			private readonly float _accelerationDelta;

			private bool _applied;

			public BodyStatChange(CharacterBody body, float multiplier)
			{
				_body = body;
				_moveSpeedDelta = body.baseMoveSpeed * (multiplier - 1f);
				_attackSpeedDelta = body.baseAttackSpeed * (multiplier - 1f);
				_accelerationDelta = body.baseAcceleration * (multiplier - 1f);
			}

			public void Apply()
			{
				if (!((Object)(object)_body == (Object)null) && !_applied)
				{
					CharacterBody body = _body;
					body.baseMoveSpeed += _moveSpeedDelta;
					CharacterBody body2 = _body;
					body2.baseAttackSpeed += _attackSpeedDelta;
					CharacterBody body3 = _body;
					body3.baseAcceleration += _accelerationDelta;
					_body.RecalculateStats();
					_applied = true;
				}
			}

			public void Restore()
			{
				if (!((Object)(object)_body == (Object)null) && _applied)
				{
					CharacterBody body = _body;
					body.baseMoveSpeed -= _moveSpeedDelta;
					CharacterBody body2 = _body;
					body2.baseAttackSpeed -= _attackSpeedDelta;
					CharacterBody body3 = _body;
					body3.baseAcceleration -= _accelerationDelta;
					_body.RecalculateStats();
					_applied = false;
				}
			}
		}

		private sealed class Afterimage
		{
			public readonly GameObject GameObject;

			public readonly GameObject GlowObject;

			public readonly Mesh Mesh;

			public readonly Mesh OutlineMesh;

			public readonly Material[] Materials;

			public readonly Material[] GlowMaterials;

			public readonly float ExpiresAt;

			public readonly float Lifetime;

			public Afterimage(GameObject gameObject, GameObject glowObject, Mesh mesh, Mesh outlineMesh, Material[] materials, Material[] glowMaterials, float createdAt, float lifetime)
			{
				GameObject = gameObject;
				GlowObject = glowObject;
				Mesh = mesh;
				OutlineMesh = outlineMesh;
				Materials = materials;
				GlowMaterials = glowMaterials;
				Lifetime = lifetime;
				ExpiresAt = createdAt + lifetime;
			}

			public void Destroy()
			{
				if ((Object)(object)GameObject != (Object)null)
				{
					Object.Destroy((Object)(object)GameObject);
				}
				if ((Object)(object)GlowObject != (Object)null)
				{
					Object.Destroy((Object)(object)GlowObject);
				}
				if ((Object)(object)Mesh != (Object)null)
				{
					Object.Destroy((Object)(object)Mesh);
				}
				if ((Object)(object)OutlineMesh != (Object)null)
				{
					Object.Destroy((Object)(object)OutlineMesh);
				}
				Material[] materials = Materials;
				foreach (Material val in materials)
				{
					if ((Object)(object)val != (Object)null)
					{
						Object.Destroy((Object)(object)val);
					}
				}
				materials = GlowMaterials;
				foreach (Material val2 in materials)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						Object.Destroy((Object)(object)val2);
					}
				}
			}
		}

		private const string PluginGuid = "com.ror2mods.sandevistan";

		private const string PluginName = "Sandevistan";

		private const string PluginVersion = "1.8.7";

		private const int MaximumAfterimages = 160;

		private const float ParryWindowSeconds = 0.2f;

		private const float ParryRadius = 3.5f;

		private static readonly Color OrangeTrailColor = new Color(1f, 0.34f, 0.025f, 0.9f);

		private static readonly Color PurpleTrailColor = new Color(0.78f, 0.1f, 1f, 0.9f);

		private static readonly Color BlueTrailColor = new Color(0.08f, 0.43f, 1f, 0.9f);

		private static readonly Color GreenTrailColor = new Color(0.1f, 1f, 0.24f, 0.9f);

		private static bool _worldEffectsActive;

		private static float _activeEnemyTimeScale = 0.1f;

		private static float _activeProjectileTimeScale = 0.25f;

		private static float _activeTeleporterTimeScale = 0.65f;

		private static CharacterBody _activePlayerBody;

		private static float _parryWindowUntil;

		private static bool _enhancedMode;

		private readonly List<Afterimage> _afterimages = new List<Afterimage>();

		private readonly Dictionary<CharacterBody, EnemyBodyState> _enemyBodies = new Dictionary<CharacterBody, EnemyBodyState>();

		private readonly Dictionary<Animator, float> _enemyAnimators = new Dictionary<Animator, float>();

		private readonly Dictionary<AudioSource, AudioSourceState> _audioSources = new Dictionary<AudioSource, AudioSourceState>();

		private readonly Dictionary<GameObject, AudioFilterState> _audioFilters = new Dictionary<GameObject, AudioFilterState>();

		private readonly List<LayerState> _playerRenderLayers = new List<LayerState>();

		private Harmony _harmony;

		private ConfigEntry<KeyCode> _activationKey;

		private ConfigEntry<KeyCode> _enhancedActivationKey;

		private ConfigEntry<float> _duration;

		private ConfigEntry<float> _cooldown;

		private ConfigEntry<float> _soloPlayerMultiplier;

		private ConfigEntry<float> _skillCooldownMultiplier;

		private ConfigEntry<float> _fieldOfViewIncreasePercent;

		private ConfigEntry<float> _coopStatMultiplier;

		private ConfigEntry<float> _enemyTimeScale;

		private ConfigEntry<float> _projectileTimeScaleEntry;

		private ConfigEntry<float> _teleporterTimeScaleEntry;

		private ConfigEntry<float> _soundPitch;

		private ConfigEntry<float> _soundVolume;

		private ConfigEntry<float> _soundLowPassCutoff;

		private ConfigEntry<float> _afterimageInterval;

		private ConfigEntry<float> _afterimageLifetime;

		private bool _active;

		private bool _soloActivation;

		private bool _loggedEnemyCountForActivation;

		private float _activeUntil;

		private float _cooldownUntil;

		private float _nextAfterimageAt;

		private float _nextEnemyAudioUpdate;

		private float _nextAudioUpdate;

		private CharacterBody _activeBody;

		private BodyStatChange _bodyStatChange;

		private Shader _afterimageShader;

		private Camera _worldCamera;

		private Camera _heroCamera;

		private GameObject _heroCameraObject;

		private GameObject _worldVisualVolumeObject;

		private PostProcessProfile _worldVisualProfile;

		private PostProcessLayer _postProcessLayer;

		private LayerMask _originalVolumeLayers;

		private int _heroRenderLayer = -1;

		private bool _originalWorldCameraMaskSaved;

		private int _originalWorldCameraMask;

		private bool _visualEffectActive;

		private bool _originalWorldCameraFovSaved;

		private float _originalWorldCameraFov;

		private float _lastAppliedWorldCameraFov;

		private float _fieldOfViewBlend;

		private AudioListener _audioListener;

		private float _originalAudioListenerVolume;

		private bool _originalAudioListenerVolumeSaved;

		private bool _loggedMissingAudioListener;

		private void Awake()
		{
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Expected O, but got Unknown
			//IL_0343: Unknown result type (might be due to invalid IL or missing references)
			//IL_0348: Unknown result type (might be due to invalid IL or missing references)
			_activationKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "ActivationKey", (KeyCode)118, "Клавиша активации.");
			_enhancedActivationKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "EnhancedActivationKey", (KeyCode)98, "Клавиша активации режима с тройным замедлением.");
			_duration = ((BaseUnityPlugin)this).Config.Bind<float>("General", "DurationSeconds", 6f, "Длительность способности в реальном времени.");
			_cooldown = ((BaseUnityPlugin)this).Config.Bind<float>("General", "CooldownSeconds", 5f, "Перезарядка после окончания способности.");
			_soloPlayerMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Singleplayer", "PlayerSpeedMultiplier", 1.15f, "Скорость движения и атаки локального игрока относительно обычного времени.");
			_skillCooldownMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("General", "SkillCooldownMultiplier", 2f, "Скорость перезарядки навыков локального игрока во время способности.");
			_fieldOfViewIncreasePercent = ((BaseUnityPlugin)this).Config.Bind<float>("General", "FieldOfViewIncreasePercent", 20f, "Увеличение поля зрения локальной камеры во время способности.");
			_coopStatMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Coop", "LocalStatMultiplier", 1.15f, "Множитель скорости движения и атаки локального игрока в кооперативе.");
			_enemyTimeScale = ((BaseUnityPlugin)this).Config.Bind<float>("World", "EnemyTimeScale", 0.1f, "Множитель скорости состояний и движения врагов.");
			_projectileTimeScaleEntry = ((BaseUnityPlugin)this).Config.Bind<float>("World", "EnemyProjectileTimeScale", 0.25f, "Множитель скорости вражеских снарядов и ракет.");
			_teleporterTimeScaleEntry = ((BaseUnityPlugin)this).Config.Bind<float>("World", "TeleporterChargeTimeScale", 0.65f, "Множитель скорости зарядки телепорта.");
			_soundPitch = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "GlobalSoundPitch", 0.82f, "Множитель высоты Unity AudioSource во время способности.");
			_soundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "GlobalSoundVolume", 0.7f, "Множитель громкости Unity AudioSource во время способности.");
			_soundLowPassCutoff = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "LowPassCutoffFrequency", 1400f, "Частота среза общего фильтра низких частот во время способности.");
			_afterimageInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "AfterimageIntervalSeconds", 0.04f, "Интервал создания визуального следа.");
			_afterimageLifetime = ((BaseUnityPlugin)this).Config.Bind<float>("Visuals", "AfterimageLifetimeSeconds", 1.25f, "Время жизни одного силуэта.");
			_enemyTimeScale.Value = Mathf.Clamp(_enemyTimeScale.Value, 0.1f, 1f);
			_projectileTimeScaleEntry.Value = Mathf.Clamp(_projectileTimeScaleEntry.Value, 0.1f, 1f);
			_teleporterTimeScaleEntry.Value = Mathf.Clamp(_teleporterTimeScaleEntry.Value, 0.1f, 1f);
			_afterimageShader = Shader.Find("Standard");
			if ((Object)(object)_afterimageShader == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Не найден шейдер Standard; цветные силуэты отключены.");
			}
			_harmony = new Harmony("com.ror2mods.sandevistan");
			_harmony.PatchAll();
			_activeEnemyTimeScale = _enemyTimeScale.Value;
			_activeProjectileTimeScale = _projectileTimeScaleEntry.Value;
			_activeTeleporterTimeScale = _teleporterTimeScaleEntry.Value;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Sandevistan загружен. Клавиша активации: " + ((object)_activationKey.Value/*cast due to .constrained prefix*/).ToString()));
		}

		private void Update()
		{
			//IL_00fe: 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)
			UpdateAfterimages();
			UpdateEnemyEffects();
			UpdateAudioEffects();
			if ((Object)(object)Run.instance == (Object)null)
			{
				if (_active)
				{
					EndAbility(startCooldown: false);
				}
				_worldEffectsActive = false;
				_cooldownUntil = 0f;
			}
			else if (_active)
			{
				if (!((Object)(object)_activeBody == (Object)null) && !((Object)(object)_activeBody.healthComponent == (Object)null) && _activeBody.healthComponent.alive)
				{
					LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
					if (!((Object)(object)((firstLocalUser != null) ? firstLocalUser.cachedBody : null) != (Object)(object)_activeBody) && !(Time.unscaledTime >= _activeUntil))
					{
						if (Time.unscaledTime >= _nextAfterimageAt)
						{
							SpawnAfterimages(_activeBody);
							_nextAfterimageAt = Time.unscaledTime + Mathf.Max(0.01f, _afterimageInterval.Value);
						}
						AdvanceLocalSkillCooldowns();
						ReflectNearbyProjectiles();
						return;
					}
				}
				EndAbility(startCooldown: true);
			}
			else if (Input.GetKeyDown(_activationKey.Value) && Time.unscaledTime >= _cooldownUntil)
			{
				TryActivate(enhancedMode: false);
			}
			else if (Input.GetKeyDown(_enhancedActivationKey.Value) && Time.unscaledTime >= _cooldownUntil)
			{
				TryActivate(enhancedMode: true);
			}
		}

		private void LateUpdate()
		{
			if (_active || _originalWorldCameraFovSaved)
			{
				UpdateHeroOverlayCamera();
			}
		}

		private void TryActivate(bool enhancedMode)
		{
			LocalUser firstLocalUser = LocalUserManager.GetFirstLocalUser();
			CharacterBody val = ((firstLocalUser != null) ? firstLocalUser.cachedBody : null);
			if (!((Object)(object)val == (Object)null) && !((Object)(object)val.healthComponent == (Object)null) && val.healthComponent.alive)
			{
				int count = NetworkUser.readOnlyInstancesList.Count;
				_soloActivation = count <= 1;
				_activeBody = val;
				_activePlayerBody = val;
				_enhancedMode = enhancedMode;
				_parryWindowUntil = 0f;
				float multiplier = (_soloActivation ? Mathf.Max(1f, _soloPlayerMultiplier.Value) : Mathf.Max(1f, _coopStatMultiplier.Value));
				_bodyStatChange = new BodyStatChange(val, multiplier);
				_bodyStatChange.Apply();
				CreateMaskedWorldVisual(val);
				float num = (enhancedMode ? (1f / 3f) : 1f);
				_activeEnemyTimeScale = Mathf.Max(0.01f, _enemyTimeScale.Value * num);
				_activeProjectileTimeScale = Mathf.Max(0.01f, _projectileTimeScaleEntry.Value * num);
				_activeTeleporterTimeScale = Mathf.Max(0.01f, _teleporterTimeScaleEntry.Value * num);
				_worldEffectsActive = NetworkServer.active || _soloActivation;
				_active = true;
				_loggedEnemyCountForActivation = false;
				_activeUntil = Time.unscaledTime + Mathf.Max(0.1f, _duration.Value);
				_nextAfterimageAt = Time.unscaledTime;
				((BaseUnityPlugin)this).Logger.LogInfo((object)(_worldEffectsActive ? ((enhancedMode ? "Усиленный Сандвистан x3 активирован. " : "Сандвистан активирован. ") + "Выборочное замедление мира включено. Скорость врагов: " + _activeEnemyTimeScale.ToString("0.00") + ".") : "Сандвистан активирован: только локальное усиление игрока. Для замедления мира нужно быть хостом."));
			}
		}

		private void EndAbility(bool startCooldown)
		{
			if (_bodyStatChange != null)
			{
				_bodyStatChange.Restore();
				_bodyStatChange = null;
			}
			_worldEffectsActive = false;
			_activePlayerBody = null;
			_parryWindowUntil = 0f;
			_enhancedMode = false;
			ClearMaskedWorldVisual(!startCooldown);
			RestoreEnemyEffects();
			RestoreAudioEffects();
			_active = false;
			_activeBody = null;
			ClearAfterimages();
			if (startCooldown)
			{
				_cooldownUntil = Time.unscaledTime + Mathf.Max(0f, _cooldown.Value);
			}
		}

		private void AdvanceLocalSkillCooldowns()
		{
			SkillLocator val = (((Object)(object)_activeBody != (Object)null) ? _activeBody.skillLocator : null);
			GenericSkill[] array = (((Object)(object)val != (Object)null) ? val.AllSkills : null);
			if (array == null)
			{
				return;
			}
			float num = Time.unscaledDeltaTime * Mathf.Max(0f, _skillCooldownMultiplier.Value - 1f);
			if (num <= 0f)
			{
				return;
			}
			GenericSkill[] array2 = array;
			foreach (GenericSkill val2 in array2)
			{
				if (!((Object)(object)val2 == (Object)null) && !val2.isCooldownBlocked && val2.stock < val2.maxStock)
				{
					float finalRechargeInterval = val2.GetFinalRechargeInterval();
					val2.rechargeStopwatch = Mathf.Min(finalRechargeInterval, val2.rechargeStopwatch + num);
				}
			}
		}

		private void ReflectNearbyProjectiles()
		{
			//IL_003c: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0238: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			if (!_active || !_worldEffectsActive || (Object)(object)_activeBody == (Object)null || Time.unscaledTime > _parryWindowUntil || !NetworkServer.active)
			{
				return;
			}
			Collider[] array = Physics.OverlapSphere(((Component)_activeBody).transform.position, 3.5f, -1, (QueryTriggerInteraction)2);
			HashSet<ProjectileController> hashSet = new HashSet<ProjectileController>();
			Collider[] array2 = array;
			foreach (Collider val in array2)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				ProjectileController componentInParent = ((Component)val).GetComponentInParent<ProjectileController>();
				if ((Object)(object)componentInParent == (Object)null || !IsEnemyProjectile((Component)(object)componentInParent) || !hashSet.Add(componentInParent) || (Object)(object)componentInParent.teamFilter == (Object)null)
				{
					continue;
				}
				Vector3 position = ((Component)componentInParent).transform.position;
				Transform val2 = FindNearestEnemyTransform(position);
				Vector3 val3 = (((Object)(object)val2 != (Object)null) ? (val2.position - position) : Vector3.zero);
				Rigidbody val4 = ((Component)componentInParent).GetComponent<Rigidbody>();
				if ((Object)(object)val4 == (Object)null)
				{
					val4 = ((Component)componentInParent).GetComponentInChildren<Rigidbody>();
				}
				float num;
				Vector3 velocity;
				if (!((Object)(object)val4 != (Object)null))
				{
					num = 0f;
				}
				else
				{
					velocity = val4.velocity;
					num = ((Vector3)(ref velocity)).magnitude;
				}
				float num2 = num;
				Vector3 val5;
				if (((Vector3)(ref val3)).sqrMagnitude < 0.001f)
				{
					if ((Object)(object)val4 != (Object)null)
					{
						velocity = val4.velocity;
						if (((Vector3)(ref velocity)).sqrMagnitude > 0.001f)
						{
							velocity = val4.velocity;
							val5 = -((Vector3)(ref velocity)).normalized;
							goto IL_0179;
						}
					}
					val5 = -((Component)componentInParent).transform.forward;
					goto IL_0179;
				}
				goto IL_017b;
				IL_017b:
				((Vector3)(ref val3)).Normalize();
				((Component)componentInParent).transform.forward = val3;
				componentInParent.owner = ((Component)_activeBody).gameObject;
				componentInParent.Networkowner = ((Component)_activeBody).gameObject;
				componentInParent.teamFilter.teamIndex = (TeamIndex)1;
				ProjectileSimple component = ((Component)componentInParent).GetComponent<ProjectileSimple>();
				if ((Object)(object)component != (Object)null)
				{
					num2 = Mathf.Max(num2, component.desiredForwardSpeed);
					float num3 = num2 / Mathf.Max(0.01f, _activeProjectileTimeScale);
					component.desiredForwardSpeed = Mathf.Max(num3, 10f);
					if ((Object)(object)val4 != (Object)null)
					{
						val4.velocity = val3 * component.desiredForwardSpeed;
					}
				}
				else if ((Object)(object)val4 != (Object)null)
				{
					val4.velocity = val3 * Mathf.Max(num2, 10f);
				}
				MissileController component2 = ((Component)componentInParent).GetComponent<MissileController>();
				if ((Object)(object)component2 != (Object)null && (Object)(object)val2 != (Object)null)
				{
					ProjectileTargetComponent value = Traverse.Create((object)component2).Field("targetComponent").GetValue<ProjectileTargetComponent>();
					if ((Object)(object)value != (Object)null)
					{
						value.target = val2;
					}
				}
				continue;
				IL_0179:
				val3 = val5;
				goto IL_017b;
			}
			if (hashSet.Count > 0)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Сандвистан: отражено снарядов: " + hashSet.Count + "."));
			}
			_parryWindowUntil = 0f;
		}

		private static Transform FindNearestEnemyTransform(Vector3 origin)
		{
			//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_004f: 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)
			CharacterBody val = null;
			float num = float.MaxValue;
			foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList)
			{
				if (!((Object)(object)readOnlyInstances == (Object)null) && IsEnemy((Component)(object)readOnlyInstances) && !((Object)(object)readOnlyInstances.healthComponent == (Object)null) && readOnlyInstances.healthComponent.alive)
				{
					Vector3 val2 = readOnlyInstances.corePosition - origin;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (sqrMagnitude < num)
					{
						num = sqrMagnitude;
						val = readOnlyInstances;
					}
				}
			}
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val.coreTransform;
		}

		private void UpdateEnemyEffects()
		{
			if (!_worldEffectsActive)
			{
				RestoreEnemyEffects();
			}
			else
			{
				UpdateEnemyEffectsCore();
			}
		}

		private void CreateMaskedWorldVisual(CharacterBody body)
		{
			//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_01df: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_0246: Unknown result type (might be due to invalid IL or missing references)
			//IL_024b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0312: 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_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Expected O, but got Unknown
			//IL_03c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cb: Expected O, but got Unknown
			CameraRigController val = null;
			foreach (CameraRigController readOnlyInstances in CameraRigController.readOnlyInstancesList)
			{
				if ((Object)(object)readOnlyInstances != (Object)null && (Object)(object)readOnlyInstances.targetBody == (Object)(object)body)
				{
					val = readOnlyInstances;
					break;
				}
			}
			Transform val2 = (((Object)(object)body != (Object)null && (Object)(object)body.modelLocator != (Object)null) ? body.modelLocator.modelTransform : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val.sceneCam == (Object)null || (Object)(object)val2 == (Object)null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Сандвистан: маскированный экранный эффект недоступен — не найдена камера или модель игрока.");
				return;
			}
			_worldCamera = val.sceneCam;
			_originalWorldCameraFov = _worldCamera.fieldOfView;
			_lastAppliedWorldCameraFov = _originalWorldCameraFov;
			_fieldOfViewBlend = 0f;
			_originalWorldCameraFovSaved = true;
			PostProcessLayer component = ((Component)_worldCamera).GetComponent<PostProcessLayer>();
			if ((Object)(object)component == (Object)null || !((Behaviour)component).enabled)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Сандвистан: экранный эффект отключён, так как на камере игрока нет активного PostProcessLayer.");
				return;
			}
			int num = FindUnusedRenderLayer();
			if (num < 0)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Сандвистан: не найден свободный слой для чистого рендеринга модели игрока; экранный эффект отключён.");
				return;
			}
			_postProcessLayer = component;
			_originalVolumeLayers = component.volumeLayer;
			_heroRenderLayer = num;
			_originalWorldCameraMask = _worldCamera.cullingMask;
			_originalWorldCameraMaskSaved = true;
			Renderer[] componentsInChildren = ((Component)val2).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val3 in componentsInChildren)
			{
				if (!((Object)(object)val3 == (Object)null))
				{
					_playerRenderLayers.Add(new LayerState(((Component)val3).gameObject, ((Component)val3).gameObject.layer));
					((Component)val3).gameObject.layer = _heroRenderLayer;
				}
			}
			Camera worldCamera = _worldCamera;
			worldCamera.cullingMask &= ~(1 << _heroRenderLayer);
			LayerMask volumeLayer = default(LayerMask);
			((LayerMask)(ref volumeLayer)).value = ((LayerMask)(ref component.volumeLayer)).value | (1 << _heroRenderLayer);
			component.volumeLayer = volumeLayer;
			_worldVisualProfile = ScriptableObject.CreateInstance<PostProcessProfile>();
			ColorGrading obj = _worldVisualProfile.AddSettings<ColorGrading>();
			((ParameterOverride)obj.colorFilter).overrideState = true;
			((ParameterOverride<Color>)(object)obj.colorFilter).value = new Color(0.94f, 1f, 0.78f, 1f);
			((ParameterOverride)obj.saturation).overrideState = true;
			((ParameterOverride<float>)(object)obj.saturation).value = -2f;
			((ParameterOverride)obj.postExposure).overrideState = true;
			((ParameterOverride<float>)(object)obj.postExposure).value = 0.45f;
			Vignette obj2 = _worldVisualProfile.AddSettings<Vignette>();
			((PostProcessEffectSettings)obj2).active = true;
			((ParameterOverride)obj2.intensity).overrideState = true;
			((ParameterOverride<float>)(object)obj2.intensity).value = 0.14f;
			((ParameterOverride)obj2.smoothness).overrideState = true;
			((ParameterOverride<float>)(object)obj2.smoothness).value = 0.8f;
			((ParameterOverride)obj2.roundness).overrideState = true;
			((ParameterOverride<float>)(object)obj2.roundness).value = 1f;
			((ParameterOverride)obj2.color).overrideState = true;
			((ParameterOverride<Color>)(object)obj2.color).value = new Color(0.035f, 0.075f, 0.005f, 1f);
			MotionBlur obj3 = _worldVisualProfile.AddSettings<MotionBlur>();
			((ParameterOverride)obj3.shutterAngle).overrideState = true;
			((ParameterOverride<float>)(object)obj3.shutterAngle).value = 150f;
			((ParameterOverride)obj3.sampleCount).overrideState = true;
			((ParameterOverride<int>)(object)obj3.sampleCount).value = 12;
			_worldVisualVolumeObject = new GameObject("SandevistanWorldPostProcess");
			_worldVisualVolumeObject.layer = _heroRenderLayer;
			PostProcessVolume obj4 = _worldVisualVolumeObject.AddComponent<PostProcessVolume>();
			obj4.isGlobal = true;
			obj4.priority = 1000f;
			obj4.weight = 1f;
			obj4.sharedProfile = _worldVisualProfile;
			obj4.targetLayer = _postProcessLayer;
			_heroCameraObject = new GameObject("SandevistanHeroOverlayCamera");
			_heroCamera = _heroCameraObject.AddComponent<Camera>();
			_heroCamera.CopyFrom(_worldCamera);
			_heroCamera.clearFlags = (CameraClearFlags)4;
			_heroCamera.cullingMask = 1 << _heroRenderLayer;
			_heroCamera.depth = _worldCamera.depth + 0.1f;
			_heroCamera.useOcclusionCulling = false;
			_heroCamera.allowMSAA = false;
			_heroCamera.targetTexture = _worldCamera.targetTexture;
			_visualEffectActive = true;
			UpdateHeroOverlayCamera();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Сандвистан: жёлто-лаймовая тонировка и размытие мира включены; герой рендерится чистым проходом.");
		}

		private int FindUnusedRenderLayer()
		{
			bool[] array = new bool[32];
			Renderer[] array2 = Object.FindObjectsOfType<Renderer>(true);
			foreach (Renderer val in array2)
			{
				if ((Object)(object)val != (Object)null && val.enabled && ((Component)val).gameObject.activeInHierarchy)
				{
					array[((Component)val).gameObject.layer] = true;
				}
			}
			for (int num = 31; num >= 8; num--)
			{
				if (!array[num])
				{
					return num;
				}
			}
			return -1;
		}

		private void UpdateHeroOverlayCamera()
		{
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_worldCamera == (Object)null)
			{
				return;
			}
			if (_originalWorldCameraFovSaved)
			{
				float fieldOfView = _worldCamera.fieldOfView;
				if (!Mathf.Approximately(fieldOfView, _lastAppliedWorldCameraFov))
				{
					_originalWorldCameraFov = fieldOfView;
				}
				_fieldOfViewBlend = Mathf.MoveTowards(_fieldOfViewBlend, _active ? 1f : 0f, Time.unscaledDeltaTime / 0.3f);
				float num = 1f + Mathf.Clamp(_fieldOfViewIncreasePercent.Value, 0f, 20f) * 0.01f;
				_lastAppliedWorldCameraFov = _originalWorldCameraFov * (1f + (num - 1f) * _fieldOfViewBlend);
				_worldCamera.fieldOfView = _lastAppliedWorldCameraFov;
				if (!_active && _fieldOfViewBlend <= 0f)
				{
					_worldCamera.fieldOfView = _originalWorldCameraFov;
					_lastAppliedWorldCameraFov = _originalWorldCameraFov;
					_originalWorldCameraFovSaved = false;
					if (!_visualEffectActive)
					{
						_worldCamera = null;
					}
				}
			}
			if (_visualEffectActive && !((Object)(object)_heroCamera == (Object)null))
			{
				Transform transform = ((Component)_worldCamera).transform;
				((Component)_heroCamera).transform.SetPositionAndRotation(transform.position, transform.rotation);
				_heroCamera.fieldOfView = _worldCamera.fieldOfView;
				_heroCamera.orthographic = _worldCamera.orthographic;
				_heroCamera.orthographicSize = _worldCamera.orthographicSize;
				_heroCamera.aspect = _worldCamera.aspect;
				_heroCamera.nearClipPlane = _worldCamera.nearClipPlane;
				_heroCamera.farClipPlane = _worldCamera.farClipPlane;
				_heroCamera.rect = _worldCamera.rect;
				_heroCamera.targetDisplay = _worldCamera.targetDisplay;
				_heroCamera.targetTexture = _worldCamera.targetTexture;
				_heroCamera.projectionMatrix = _worldCamera.projectionMatrix;
				_heroCamera.worldToCameraMatrix = _worldCamera.worldToCameraMatrix;
				_heroCamera.depth = _worldCamera.depth + 0.1f;
			}
		}

		private void ClearMaskedWorldVisual(bool restoreFovImmediately)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			if (restoreFovImmediately && _originalWorldCameraFovSaved && (Object)(object)_worldCamera != (Object)null)
			{
				_worldCamera.fieldOfView = _originalWorldCameraFov;
				_originalWorldCameraFovSaved = false;
			}
			if (_originalWorldCameraMaskSaved && (Object)(object)_worldCamera != (Object)null)
			{
				_worldCamera.cullingMask = _originalWorldCameraMask;
			}
			if ((Object)(object)_postProcessLayer != (Object)null)
			{
				_postProcessLayer.volumeLayer = _originalVolumeLayers;
			}
			foreach (LayerState playerRenderLayer in _playerRenderLayers)
			{
				if ((Object)(object)playerRenderLayer.GameObject != (Object)null)
				{
					playerRenderLayer.GameObject.layer = playerRenderLayer.Layer;
				}
			}
			_playerRenderLayers.Clear();
			_visualEffectActive = false;
			if ((Object)(object)_heroCameraObject != (Object)null)
			{
				Object.Destroy((Object)(object)_heroCameraObject);
			}
			if ((Object)(object)_worldVisualVolumeObject != (Object)null)
			{
				Object.Destroy((Object)(object)_worldVisualVolumeObject);
			}
			if ((Object)(object)_worldVisualProfile != (Object)null)
			{
				Object.Destroy((Object)(object)_worldVisualProfile);
			}
			_heroCamera = null;
			_heroCameraObject = null;
			if (restoreFovImmediately || !_originalWorldCameraFovSaved)
			{
				_worldCamera = null;
			}
			_postProcessLayer = null;
			_worldVisualVolumeObject = null;
			_worldVisualProfile = null;
			_originalWorldCameraMaskSaved = false;
			if (restoreFovImmediately)
			{
				_originalWorldCameraFovSaved = false;
			}
			_heroRenderLayer = -1;
		}

		private void UpdateEnemyEffectsCore()
		{
			if (Time.unscaledTime < _nextEnemyAudioUpdate)
			{
				return;
			}
			_nextEnemyAudioUpdate = Time.unscaledTime + 0.1f;
			foreach (CharacterBody readOnlyInstances in CharacterBody.readOnlyInstancesList)
			{
				if ((Object)(object)readOnlyInstances == (Object)null || !IsEnemy((Component)(object)readOnlyInstances))
				{
					continue;
				}
				if (!_enemyBodies.ContainsKey(readOnlyInstances))
				{
					float activeEnemyTimeScale = _activeEnemyTimeScale;
					_enemyBodies.Add(readOnlyInstances, new EnemyBodyState(readOnlyInstances.baseMoveSpeed, readOnlyInstances.baseAttackSpeed, readOnlyInstances.baseAcceleration));
					readOnlyInstances.baseMoveSpeed *= activeEnemyTimeScale;
					readOnlyInstances.baseAttackSpeed *= activeEnemyTimeScale;
					readOnlyInstances.baseAcceleration *= activeEnemyTimeScale;
					readOnlyInstances.RecalculateStats();
				}
				if (!((Object)(object)readOnlyInstances.modelLocator != (Object)null) || !((Object)(object)readOnlyInstances.modelLocator.modelTransform != (Object)null))
				{
					continue;
				}
				Animator[] componentsInChildren = ((Component)readOnlyInstances.modelLocator.modelTransform).GetComponentsInChildren<Animator>(true);
				foreach (Animator val in componentsInChildren)
				{
					if (!((Object)(object)val == (Object)null))
					{
						if (!_enemyAnimators.TryGetValue(val, out var value))
						{
							value = val.speed;
							_enemyAnimators.Add(val, value);
						}
						val.speed = value * _activeEnemyTimeScale;
					}
				}
			}
			if (!_loggedEnemyCountForActivation)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Sandevistan: обнаружено врагов для замедления: " + _enemyBodies.Count + "."));
				_loggedEnemyCountForActivation = true;
			}
			List<CharacterBody> list = null;
			foreach (KeyValuePair<CharacterBody, EnemyBodyState> enemyBody in _enemyBodies)
			{
				if ((Object)(object)enemyBody.Key == (Object)null)
				{
					if (list == null)
					{
						list = new List<CharacterBody>();
					}
					list.Add(enemyBody.Key);
				}
			}
			if (list != null)
			{
				foreach (CharacterBody item in list)
				{
					_enemyBodies.Remove(item);
				}
			}
			List<Animator> list2 = null;
			foreach (KeyValuePair<Animator, float> enemyAnimator in _enemyAnimators)
			{
				if ((Object)(object)enemyAnimator.Key == (Object)null)
				{
					if (list2 == null)
					{
						list2 = new List<Animator>();
					}
					list2.Add(enemyAnimator.Key);
				}
			}
			if (list2 == null)
			{
				return;
			}
			foreach (Animator item2 in list2)
			{
				_enemyAnimators.Remove(item2);
			}
		}

		private void RestoreEnemyEffects()
		{
			foreach (KeyValuePair<CharacterBody, EnemyBodyState> enemyBody in _enemyBodies)
			{
				if (!((Object)(object)enemyBody.Key == (Object)null))
				{
					enemyBody.Key.baseMoveSpeed = enemyBody.Value.BaseMoveSpeed;
					enemyBody.Key.baseAttackSpeed = enemyBody.Value.BaseAttackSpeed;
					enemyBody.Key.baseAcceleration = enemyBody.Value.BaseAcceleration;
					enemyBody.Key.RecalculateStats();
				}
			}
			_enemyBodies.Clear();
			foreach (KeyValuePair<Animator, float> enemyAnimator in _enemyAnimators)
			{
				if ((Object)(object)enemyAnimator.Key != (Object)null)
				{
					enemyAnimator.Key.speed = enemyAnimator.Value;
				}
			}
			_enemyAnimators.Clear();
		}

		private void UpdateAudioEffects()
		{
			if (!_active)
			{
				RestoreAudioEffects();
			}
			else
			{
				if (Time.unscaledTime < _nextAudioUpdate)
				{
					return;
				}
				_nextAudioUpdate = Time.unscaledTime + 0.1f;
				AudioSource[] array = Object.FindObjectsOfType<AudioSource>(true);
				foreach (AudioSource val in array)
				{
					if (!((Object)(object)val == (Object)null))
					{
						if (!_audioSources.TryGetValue(val, out var value))
						{
							value = new AudioSourceState(val.pitch, val.volume);
							_audioSources.Add(val, value);
						}
						val.pitch = value.Pitch * Mathf.Clamp(_soundPitch.Value, 0.5f, 1f);
						if (!val.ignoreListenerVolume)
						{
							val.volume = value.Volume * Mathf.Clamp01(_soundVolume.Value);
						}
						ApplyAudioLowPass(((Component)val).gameObject);
					}
				}
				UpdateAudioListenerVolume();
				RemoveDestroyedAudioSources();
			}
		}

		private void ApplyAudioLowPass(GameObject sourceObject)
		{
			if ((Object)(object)sourceObject == (Object)null)
			{
				return;
			}
			if (!_audioFilters.TryGetValue(sourceObject, out var value))
			{
				AudioLowPassFilter val = sourceObject.GetComponent<AudioLowPassFilter>();
				bool flag = (Object)(object)val == (Object)null;
				if (flag)
				{
					val = sourceObject.AddComponent<AudioLowPassFilter>();
				}
				value = new AudioFilterState(val, flag, ((Behaviour)val).enabled, val.cutoffFrequency, val.lowpassResonanceQ);
				_audioFilters.Add(sourceObject, value);
			}
			if ((Object)(object)value.Filter != (Object)null)
			{
				((Behaviour)value.Filter).enabled = true;
				value.Filter.cutoffFrequency = Mathf.Clamp(_soundLowPassCutoff.Value, 500f, 5000f);
				value.Filter.lowpassResonanceQ = 1f;
			}
		}

		private void UpdateAudioListenerVolume()
		{
			if ((Object)(object)_audioListener == (Object)null)
			{
				_audioListener = (((Object)(object)_worldCamera != (Object)null) ? ((Component)_worldCamera).GetComponent<AudioListener>() : Object.FindObjectOfType<AudioListener>());
			}
			if ((Object)(object)_audioListener == (Object)null)
			{
				if (!_loggedMissingAudioListener)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"Сандвистан: не найден AudioListener; фильтр низких частот недоступен.");
					_loggedMissingAudioListener = true;
				}
				return;
			}
			if (!_originalAudioListenerVolumeSaved)
			{
				_originalAudioListenerVolume = AudioListener.volume;
				_originalAudioListenerVolumeSaved = true;
			}
			AudioListener.volume = _originalAudioListenerVolume * Mathf.Clamp01(_soundVolume.Value);
		}

		private void RemoveDestroyedAudioSources()
		{
			List<AudioSource> list = null;
			foreach (KeyValuePair<AudioSource, AudioSourceState> audioSource in _audioSources)
			{
				if ((Object)(object)audioSource.Key == (Object)null)
				{
					if (list == null)
					{
						list = new List<AudioSource>();
					}
					list.Add(audioSource.Key);
				}
			}
			List<GameObject> list2 = null;
			foreach (KeyValuePair<GameObject, AudioFilterState> audioFilter in _audioFilters)
			{
				if ((Object)(object)audioFilter.Key == (Object)null)
				{
					if (list2 == null)
					{
						list2 = new List<GameObject>();
					}
					list2.Add(audioFilter.Key);
				}
			}
			if (list2 != null)
			{
				foreach (GameObject item in list2)
				{
					_audioFilters.Remove(item);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (AudioSource item2 in list)
			{
				_audioSources.Remove(item2);
			}
		}

		private void RestoreAudioEffects()
		{
			foreach (KeyValuePair<AudioSource, AudioSourceState> audioSource in _audioSources)
			{
				if ((Object)(object)audioSource.Key != (Object)null)
				{
					audioSource.Key.pitch = audioSource.Value.Pitch;
					audioSource.Key.volume = audioSource.Value.Volume;
				}
			}
			_audioSources.Clear();
			foreach (KeyValuePair<GameObject, AudioFilterState> audioFilter in _audioFilters)
			{
				AudioFilterState value = audioFilter.Value;
				if (!((Object)(object)value.Filter == (Object)null))
				{
					if (value.Created)
					{
						Object.Destroy((Object)(object)value.Filter);
						continue;
					}
					((Behaviour)value.Filter).enabled = value.Enabled;
					value.Filter.cutoffFrequency = value.CutoffFrequency;
					value.Filter.lowpassResonanceQ = value.Resonance;
				}
			}
			_audioFilters.Clear();
			if (_originalAudioListenerVolumeSaved)
			{
				AudioListener.volume = _originalAudioListenerVolume;
				_originalAudioListenerVolumeSaved = false;
			}
			_audioListener = null;
			_loggedMissingAudioListener = false;
		}

		private void SpawnAfterimages(CharacterBody body)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Expected O, but got Unknown
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Expected O, but got Unknown
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_afterimageShader == (Object)null || (Object)(object)body.modelLocator == (Object)null || (Object)(object)body.modelLocator.modelTransform == (Object)null)
			{
				return;
			}
			SkinnedMeshRenderer[] componentsInChildren = ((Component)body.modelLocator.modelTransform).GetComponentsInChildren<SkinnedMeshRenderer>();
			foreach (SkinnedMeshRenderer val in componentsInChildren)
			{
				if (!((Object)(object)val == (Object)null) && ((Renderer)val).enabled && !((Object)(object)val.sharedMesh == (Object)null))
				{
					Mesh val2 = new Mesh
					{
						name = "SandevistanAfterimageMesh"
					};
					val.BakeMesh(val2);
					Mesh val3 = CreateOutlineMesh(val2, 0.015f);
					GameObject val4 = new GameObject("SandevistanAfterimage");
					val4.layer = ((Component)val).gameObject.layer;
					val4.transform.SetPositionAndRotation(((Component)val).transform.position, ((Component)val).transform.rotation);
					val4.transform.localScale = ((Component)val).transform.lossyScale * 1.005f;
					val4.AddComponent<MeshFilter>().sharedMesh = val2;
					MeshRenderer val5 = val4.AddComponent<MeshRenderer>();
					((Renderer)val5).shadowCastingMode = (ShadowCastingMode)0;
					((Renderer)val5).receiveShadows = false;
					((Renderer)val5).lightProbeUsage = (LightProbeUsage)0;
					((Renderer)val5).reflectionProbeUsage = (ReflectionProbeUsage)0;
					GameObject val6 = new GameObject("SandevistanAfterimageGlow");
					val6.layer = ((Component)val).gameObject.layer;
					val6.transform.SetPositionAndRotation(((Component)val).transform.position, ((Component)val).transform.rotation);
					val6.transform.localScale = ((Component)val).transform.lossyScale * 1.015f;
					val6.AddComponent<MeshFilter>().sharedMesh = val3;
					MeshRenderer val7 = val6.AddComponent<MeshRenderer>();
					((Renderer)val7).shadowCastingMode = (ShadowCastingMode)0;
					((Renderer)val7).receiveShadows = false;
					((Renderer)val7).lightProbeUsage = (LightProbeUsage)0;
					((Renderer)val7).reflectionProbeUsage = (ReflectionProbeUsage)0;
					((Renderer)val7).sortingOrder = 1;
					((Renderer)val5).sortingOrder = 2;
					Material[] sharedMaterials = ((Renderer)val).sharedMaterials;
					int num = Mathf.Max(1, sharedMaterials.Length);
					Material[] array = (Material[])(object)new Material[num];
					Material[] array2 = (Material[])(object)new Material[num];
					for (int j = 0; j < num; j++)
					{
						Texture texture = ((sharedMaterials.Length > j && (Object)(object)sharedMaterials[j] != (Object)null) ? sharedMaterials[j].mainTexture : null);
						array[j] = CreateAfterimageMaterial(OrangeTrailColor, texture, outline: false);
						array2[j] = CreateAfterimageMaterial(OrangeTrailColor, (Texture)(object)Texture2D.whiteTexture, outline: true);
					}
					((Renderer)val5).sharedMaterials = array;
					((Renderer)val7).sharedMaterials = array2;
					if (_afterimages.Count >= 160)
					{
						_afterimages[0].Destroy();
						_afterimages.RemoveAt(0);
					}
					_afterimages.Add(new Afterimage(val4, val6, val2, val3, array, array2, Time.unscaledTime, Mathf.Max(0.05f, _afterimageLifetime.Value)));
				}
			}
		}

		private static Mesh CreateOutlineMesh(Mesh sourceMesh, float thickness)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			Vector3[] vertices = sourceMesh.vertices;
			Vector3[] normals = sourceMesh.normals;
			if (normals.Length != vertices.Length)
			{
				sourceMesh.RecalculateNormals();
				normals = sourceMesh.normals;
			}
			for (int i = 0; i < vertices.Length; i++)
			{
				ref Vector3 reference = ref vertices[i];
				reference += normals[i] * thickness;
			}
			Mesh val = new Mesh
			{
				name = "SandevistanAfterimageOutlineMesh",
				vertices = vertices,
				normals = normals,
				subMeshCount = sourceMesh.subMeshCount
			};
			for (int j = 0; j < sourceMesh.subMeshCount; j++)
			{
				val.SetTriangles(sourceMesh.GetTriangles(j), j, false);
			}
			val.RecalculateBounds();
			return val;
		}

		private Material CreateAfterimageMaterial(Color color, Texture texture, bool outline)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: 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_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: 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_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: 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_00f2: Expected O, but got Unknown
			Material val = new Material(_afterimageShader)
			{
				color = color,
				renderQueue = 3000,
				mainTexture = texture
			};
			val.SetFloat("_Mode", 3f);
			val.SetInt("_SrcBlend", 5);
			val.SetInt("_DstBlend", 1);
			val.SetInt("_ZWrite", outline ? 1 : 0);
			val.SetInt("_Cull", outline ? 1 : 0);
			val.SetFloat("_Metallic", 0f);
			val.SetFloat("_Glossiness", 0f);
			val.EnableKeyword("_ALPHABLEND_ON");
			val.DisableKeyword("_ALPHAPREMULTIPLY_ON");
			val.DisableKeyword("_ALPHATEST_ON");
			val.EnableKeyword("_EMISSION");
			val.SetColor("_EmissionColor", new Color(color.r, color.g, color.b, 1f) * (outline ? 1.5f : 0.65f));
			return val;
		}

		private void UpdateAfterimages()
		{
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			float unscaledTime = Time.unscaledTime;
			for (int num = _afterimages.Count - 1; num >= 0; num--)
			{
				Afterimage afterimage = _afterimages[num];
				float num2 = afterimage.ExpiresAt - unscaledTime;
				if (num2 <= 0f || (Object)(object)afterimage.GameObject == (Object)null || (Object)(object)afterimage.GlowObject == (Object)null)
				{
					afterimage.Destroy();
					_afterimages.RemoveAt(num);
				}
				else
				{
					float num3 = 1f - Mathf.Clamp01(num2 / afterimage.Lifetime);
					float num4 = 1f - num3 * num3 * (3f - 2f * num3);
					Color color = EvaluateTrailColor(num3);
					SetMaterialColor(afterimage.Materials, color, num4);
					SetMaterialColor(afterimage.GlowMaterials, color, num4 * 0.45f);
				}
			}
		}

		private static Color EvaluateTrailColor(float age)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: 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)
			if (age < 1f / 3f)
			{
				return Color.Lerp(OrangeTrailColor, PurpleTrailColor, age * 3f);
			}
			if (age < 2f / 3f)
			{
				return Color.Lerp(PurpleTrailColor, BlueTrailColor, (age - 1f / 3f) * 3f);
			}
			return Color.Lerp(BlueTrailColor, GreenTrailColor, (age - 2f / 3f) * 3f);
		}

		private static void SetMaterialColor(Material[] materials, Color color, float fade)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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)
			foreach (Material val in materials)
			{
				if ((Object)(object)val != (Object)null)
				{
					Color color2 = color;
					color2.a *= fade;
					val.color = color2;
				}
			}
		}

		private void ClearAfterimages()
		{
			foreach (Afterimage afterimage in _afterimages)
			{
				afterimage.Destroy();
			}
			_afterimages.Clear();
		}

		private void OnGUI()
		{
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Expected O, but got Unknown
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)Run.instance == (Object)null))
			{
				string text;
				Color textColor = default(Color);
				if (_active)
				{
					text = (_enhancedMode ? "САНДВИСТАН x3  " : "САНДВИСТАН  ") + Mathf.Max(0f, _activeUntil - Time.unscaledTime).ToString("0.0") + "с";
					((Color)(ref textColor))..ctor(1f, 0.12f, 0.22f, 0.95f);
				}
				else if (Time.unscaledTime < _cooldownUntil)
				{
					text = "Сандвистан: " + (_cooldownUntil - Time.unscaledTime).ToString("0.0") + "с";
					((Color)(ref textColor))..ctor(1f, 0.65f, 0.22f, 0.9f);
				}
				else
				{
					text = "Сандвистан";
					((Color)(ref textColor))..ctor(0.95f, 0.95f, 1f, 0.75f);
				}
				GUIStyle val = new GUIStyle(GUI.skin.label)
				{
					alignment = (TextAnchor)4,
					fontSize = 22,
					fontStyle = (FontStyle)1
				};
				val.normal.textColor = textColor;
				GUI.Label(new Rect(((float)Screen.width - 420f) * 0.5f, 24f, 420f, 34f), text, val);
			}
		}

		private void OnDestroy()
		{
			EndAbility(startCooldown: false);
			ClearAfterimages();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private static bool IsEnemy(Component component)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Invalid comparison between Unknown and I4
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			CharacterBody val = component.GetComponent<CharacterBody>();
			if ((Object)(object)val == (Object)null)
			{
				val = component.GetComponentInParent<CharacterBody>();
			}
			TeamComponent val2 = (((Object)(object)val != (Object)null) ? val.teamComponent : component.GetComponentInParent<TeamComponent>());
			if ((Object)(object)val2 != (Object)null)
			{
				return (int)val2.teamIndex == 2;
			}
			return false;
		}

		private static bool IsEnemyProjectile(Component component)
		{
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Invalid comparison between Unknown and I4
			if ((Object)(object)component == (Object)null)
			{
				return false;
			}
			TeamFilter val = component.GetComponent<TeamFilter>();
			if ((Object)(object)val == (Object)null)
			{
				ProjectileController component2 = component.GetComponent<ProjectileController>();
				val = (((Object)(object)component2 != (Object)null) ? component2.teamFilter : null);
			}
			if ((Object)(object)val != (Object)null)
			{
				return (int)val.teamIndex == 2;
			}
			return false;
		}
	}
}