Decompiled source of AntiMaterialRifle v1.2.0
BepInEx/plugins/AntiMaterialRifle.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Pigeon.Math; using Pigeon.Movement; using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("AntiMaterialRifle")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("AntiMaterialRifle")] [assembly: AssemblyTitle("AntiMaterialRifle")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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; } } } public sealed class BallisticSniperBehaviour : MonoBehaviour { [Serializable] public struct Data { public bool singleRoundReload; public float shellDamageMult; public float fullHpDamageMult; public int bonusBounces; public float postBounceHoming; public bool overpressure; public float overpressureChargeDuration; public float overpressureDamageMult; public float overpressureMoveMult; public int overpressureMagPenalty; public int extraBulletsPerShot; public float twinLinkFenceDamage; public float twinLinkFenceRadius; public float exhaustionCooldown; public float exhaustionSlowDuration; public float exhaustionSlowStrength; public float longwatchAimSeconds; public float longwatchRangeBonus; public float longwatchGravityMult; public float longwatchSpeedMult; public float scouterInterval; public float scouterRadius; public int pierceTargets; public float pierceFalloff; public float spotterRadius; public float spotterDuration; public float deadboltDuration; public bool deathMark; public float deathMarkFuse; public float deathMarkRadius; public float deathMarkDamageScale; public float deathMarkHeadshotFuseMult; public float deathMarkStackScale; public bool autoTrigger; public float autoTriggerFireInterval; public float autoTriggerDamageMult; public int autoTriggerMagBonus; public float autoTriggerAdsSpread; public bool highExplosive; public float c4Damage; public float c4Radius; public float c4ThrowForce; public float c4ArmTime; public bool clipped; public float clippedReloadMult; public bool anchor; public float anchorSpeedThreshold; public bool oneInTheChamber; public float disruptDuration; public float heavyGrainDamageMult; public float reserveAmmoMult; public float rotAmount; public float rotSplashRadius; public float waterAmount; public float repositionMoveBonus; public float repositionAdsMoveMult; public float echoDelay; public float echoDamageScale; public float echoShockAmount; public float transferRelayScale; public float syncWindow; public float syncDamageMult; public bool overkill; } public struct DeathMarkEntry { public ITarget target; public float detonateAt; public float stacks; public Vector3 lastPos; public bool fromHeadshot; } public struct PendingEcho { public float fireAt; public Vector3 position; public Quaternion rotation; public float damage; public float speed; public float gravity; } [SerializeField] private Data data = CreateDefaultData(); private Data prefabSnapshot = CreateDefaultData(); private string description = "Anti-Material Rifle"; public readonly List<DeathMarkEntry> DeathMarks = new List<DeathMarkEntry>(8); public readonly List<PendingEcho> PendingEchoes = new List<PendingEcho>(4); public readonly List<ITarget> TwinShotHits = new List<ITarget>(4); private Gun boundGun; private bool hooksBound; private bool moveHookBound; private GameObject c4Visual; private readonly List<ISelectable> activeHighlights = new List<ISelectable>(16); private float highlightClearAt = -999f; private BulletData lastFiredBullet; private bool hasLastFiredBullet; private bool hasPendingOverkill; private float pendingOverkill; private ITarget pendingOverkillParent; private Vector3 pendingOverkillPos; private Gun pendingOverkillGun; private EffectType pendingOverkillEffect; private float pendingOverkillEffectAmt; public bool IsTubeReloading { get; set; } public float AimHoldTime { get; private set; } public float LastKillTime { get; set; } = -999f; public float ExhaustionReadyAt { get; set; } public bool ExhaustionShotArmed { get; set; } public float LastScouterPulse { get; set; } = -999f; public bool ChamberBonusReady { get; set; } public bool LastReloadWasFullTopOff { get; set; } public bool BlockAutoReloadForChamber { get; set; } public bool C4Deployed { get; set; } public Vector3 C4Position { get; set; } public float C4DeployedAt { get; set; } public float ReloadHoldTime { get; set; } public bool ReloadHeld { get; set; } public ref Data WeaponData => ref data; public string Description => description; public bool SingleRoundReload { get { if (data.singleRoundReload) { return !data.clipped; } return false; } } public Data GetPrefabSnapshot() { return prefabSnapshot; } public static Data CreateDefaultData() { return new Data { singleRoundReload = true, shellDamageMult = 1f, fullHpDamageMult = 1f, bonusBounces = 0, postBounceHoming = 0f, overpressure = false, overpressureChargeDuration = 0f, overpressureDamageMult = 1f, overpressureMoveMult = 1f, overpressureMagPenalty = 0, extraBulletsPerShot = 0, twinLinkFenceDamage = 0f, twinLinkFenceRadius = 0f, exhaustionCooldown = 0f, exhaustionSlowDuration = 0f, exhaustionSlowStrength = 0f, longwatchAimSeconds = 0f, longwatchRangeBonus = 0f, longwatchGravityMult = 1f, longwatchSpeedMult = 1f, scouterInterval = 0f, scouterRadius = 0f, pierceTargets = 0, pierceFalloff = 0f, spotterRadius = 0f, spotterDuration = 0f, deadboltDuration = 0f, deathMark = false, deathMarkFuse = 2f, deathMarkRadius = 4f, deathMarkDamageScale = 1.2f, deathMarkHeadshotFuseMult = 0.6f, deathMarkStackScale = 0.35f, autoTrigger = false, autoTriggerFireInterval = 0.35f, autoTriggerDamageMult = 0.5f, autoTriggerMagBonus = 5, autoTriggerAdsSpread = 0.8f, highExplosive = false, c4Damage = 220f, c4Radius = 8f, c4ThrowForce = 18f, c4ArmTime = 0.45f, clipped = false, clippedReloadMult = 1f, anchor = false, anchorSpeedThreshold = 0.15f, oneInTheChamber = false, disruptDuration = 0f, heavyGrainDamageMult = 1f, reserveAmmoMult = 1f, rotAmount = 0f, rotSplashRadius = 0f, waterAmount = 0f, repositionMoveBonus = 0f, repositionAdsMoveMult = 1f, echoDelay = 0f, echoDamageScale = 0f, echoShockAmount = 0f, transferRelayScale = 0f, syncWindow = 0f, syncDamageMult = 1f, overkill = false }; } public void InitializeAsPrefab(string desc) { description = desc ?? "Anti-Material Rifle"; data = CreateDefaultData(); prefabSnapshot = data; ResetRuntime(); } public void RestoreFromPrefab() { data = prefabSnapshot; } public void CapturePrefabSnapshot() { prefabSnapshot = data; } public void CopyFrom(BallisticSniperBehaviour template) { if (!((Object)(object)template == (Object)null)) { description = template.description; prefabSnapshot = template.prefabSnapshot; data = prefabSnapshot; ResetRuntime(); } } public void ResetRuntime() { IsTubeReloading = false; AimHoldTime = 0f; LastKillTime = -999f; ExhaustionReadyAt = 0f; ExhaustionShotArmed = false; LastScouterPulse = -999f; ChamberBonusReady = false; LastReloadWasFullTopOff = false; BlockAutoReloadForChamber = false; C4Deployed = false; ReloadHoldTime = 0f; ReloadHeld = false; DeathMarks.Clear(); PendingEchoes.Clear(); TwinShotHits.Clear(); hasLastFiredBullet = false; hasPendingOverkill = false; pendingOverkill = 0f; pendingOverkillParent = null; pendingOverkillGun = null; ClearHighlights(); DestroyC4Visual(); } public void InterruptTubeReload(Gun gun) { IsTubeReloading = false; if ((Object)(object)gun == (Object)null) { return; } try { if (gun.Reloading) { gun.CancelReload(); } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] CancelReload: " + ex.Message)); } } } public void OnUpgradesApplied(Gun gun) { boundGun = gun; BindHooks(gun, bind: true); ApplyGunDataMutations(gun); WeaponRegistration.EnsureProjectileBullet(gun); } public void OnUpgradesCleared(Gun gun) { BindHooks(gun, bind: false); data = prefabSnapshot; ResetRuntime(); } private void BindHooks(Gun gun, bool bind) { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: 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_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Expected O, but got Unknown //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Expected O, but got Unknown //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_0155: 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) if ((Object)(object)gun == (Object)null || (bind && hooksBound) || (!bind && !hooksBound)) { return; } try { if (bind) { gun.OnDamageTarget = (DamageCallback)Delegate.Combine((Delegate?)(object)gun.OnDamageTarget, (Delegate?)new DamageCallback(OnDamageTarget)); gun.OnBeforeDamage = (MutableDamageCallback)Delegate.Combine((Delegate?)(object)gun.OnBeforeDamage, (Delegate?)new MutableDamageCallback(OnBeforeDamage)); gun.OnKillTarget = (KillCallback)Delegate.Combine((Delegate?)(object)gun.OnKillTarget, (Delegate?)new KillCallback(OnKillTarget)); if ((Object)(object)gun.Player != (Object)null) { Player player = gun.Player; player.OnSetMovementSpeed += (RefAction<float>)HandleSetMoveSpeed; moveHookBound = true; } hooksBound = true; } else { gun.OnDamageTarget = (DamageCallback)Delegate.Remove((Delegate?)(object)gun.OnDamageTarget, (Delegate?)new DamageCallback(OnDamageTarget)); gun.OnBeforeDamage = (MutableDamageCallback)Delegate.Remove((Delegate?)(object)gun.OnBeforeDamage, (Delegate?)new MutableDamageCallback(OnBeforeDamage)); gun.OnKillTarget = (KillCallback)Delegate.Remove((Delegate?)(object)gun.OnKillTarget, (Delegate?)new KillCallback(OnKillTarget)); if ((Object)(object)gun.Player != (Object)null && moveHookBound) { Player player2 = gun.Player; player2.OnSetMovementSpeed -= (RefAction<float>)HandleSetMoveSpeed; moveHookBound = false; } hooksBound = false; } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)$"[BallisticSniper] BindHooks({bind}): {ex.Message}"); } } } private void HandleSetMoveSpeed(ref float speed) { if (data.repositionMoveBonus > 0f) { speed *= 1f + data.repositionMoveBonus; } bool flag = false; try { flag = (Object)(object)boundGun != (Object)null && boundGun.IsAiming; } catch { } if (flag && data.repositionAdsMoveMult < 0.99f) { speed *= data.repositionAdsMoveMult; } if (!data.overpressure || !((Object)(object)boundGun != (Object)null)) { return; } try { if (boundGun.GunData.chargeData.duration > 0.01f && boundGun.GunData.chargeData.time > 0.01f) { speed *= data.overpressureMoveMult; } } catch { } } public void ApplyGunDataMutations(Gun gun) { //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)gun == (Object)null)) { ref GunData gunData = ref gun.GunData; if (data.heavyGrainDamageMult > 1f) { gunData.damage *= data.heavyGrainDamageMult; } if (data.reserveAmmoMult > 1f) { gunData.ammoCapacity = Mathf.Max(1, Mathf.RoundToInt((float)gunData.ammoCapacity * data.reserveAmmoMult)); } if (data.bonusBounces > 0) { gunData.maxBounces = Mathf.Max(gunData.maxBounces, data.bonusBounces); } if (data.extraBulletsPerShot > 0) { gunData.bulletsPerShot = Mathf.Max(1, gunData.bulletsPerShot + data.extraBulletsPerShot); } if (data.clipped) { gunData.refillAmmoOnReload = true; gunData.reloadDuration = Mathf.Max(0.25f, gunData.reloadDuration * data.clippedReloadMult); data.singleRoundReload = false; } if (data.autoTrigger) { gunData.automatic = 1; gunData.fireInterval = data.autoTriggerFireInterval; gunData.damage *= data.autoTriggerDamageMult; gunData.magazineSize += data.autoTriggerMagBonus; } if (data.overpressure) { gunData.chargeData.duration = data.overpressureChargeDuration; gunData.chargeData.fireWhenFullyCharged = true; gunData.chargeData.fireOnRelease = false; gunData.chargeData.canFireWhileCharging = false; gunData.chargeData.coolDownSpeed = 2.5f; gunData.damage *= data.overpressureDamageMult; gunData.magazineSize = Mathf.Max(1, gunData.magazineSize - data.overpressureMagPenalty); } if (data.rotAmount > 0f) { gunData.damageEffect = (EffectType)7; gunData.damageEffectAmount = Mathf.Max(gunData.damageEffectAmount, data.rotAmount); } else if (data.waterAmount > 0f) { gunData.damageEffect = (EffectType)9; gunData.damageEffectAmount = Mathf.Max(gunData.damageEffectAmount, data.waterAmount); } } } public void Tick(float dt, Gun gun) { if (!((Object)(object)gun == (Object)null) && ((NetworkBehaviour)gun).IsOwner) { if (gun.IsAiming) { AimHoldTime += dt; } else { AimHoldTime = 0f; } if (data.exhaustionCooldown > 0f && Time.time >= ExhaustionReadyAt) { ExhaustionShotArmed = true; } if (data.oneInTheChamber && ChamberBonusReady && gun.RemainingAmmoCount <= 0) { OnMagazineEmptied(gun); } TickDeathMarks(gun); TickEchoes(gun); TickScouter(gun); } } private void TickDeathMarks(Gun gun) { //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: 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_006a: Unknown result type (might be due to invalid IL or missing references) if (!data.deathMark || DeathMarks.Count == 0) { return; } for (int num = DeathMarks.Count - 1; num >= 0; num--) { DeathMarkEntry value = DeathMarks[num]; if (value.target != null && ((ISelectable)value.target).Exists() && value.target.IsAlive) { value.lastPos = ((IFollowable)value.target).GetHealthbarPosition(); } DeathMarks[num] = value; if (!(Time.time < value.detonateAt)) { float num2 = gun.GunData.damage * data.deathMarkDamageScale * (1f + (value.stacks - 1f) * data.deathMarkStackScale); float num3 = data.deathMarkRadius * (1f + (value.stacks - 1f) * 0.15f); try { GameManager.Instance.SpawnExplosionObserverSeeThrough((IDamageSource)(object)gun, value.lastPos, num3, (TargetType)5, new DamageData(num2, (EffectType)0, 0f, (DamageFlags)16), ((NetworkBehaviour)gun).OwnerClientId, 12f); } catch { try { GameManager.Instance.SpawnExplosionFirstPerson((IDamageSource)(object)gun, value.lastPos, num3, (TargetType)5, new DamageData(num2, (EffectType)0, 0f, (DamageFlags)16), 2f); } catch { } } DeathMarks.RemoveAt(num); } } } private void TickEchoes(Gun gun) { if (data.echoDelay <= 0f || PendingEchoes.Count == 0) { return; } for (int num = PendingEchoes.Count - 1; num >= 0; num--) { if (!(Time.time < PendingEchoes[num].fireAt)) { PendingEcho echo = PendingEchoes[num]; PendingEchoes.RemoveAt(num); FireEchoBullet(gun, echo); } } } private void FireEchoBullet(Gun gun, PendingEcho echo) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_005b: 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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) try { BulletData bulletData; if (hasLastFiredBullet) { bulletData = lastFiredBullet; bulletData.position = echo.position; bulletData.rotation = echo.rotation; bulletData.direction = echo.rotation * Vector3.forward; } else { Vector3 position = echo.position; Quaternion rotation = echo.rotation; bulletData = ((GunData)(ref gun.GunData)).GetBulletData(ref position, ref rotation); } bulletData.damage = echo.damage; bulletData.speed = echo.speed; bulletData.gravity = echo.gravity; bulletData.damageEffect = (EffectType)2; bulletData.damageEffectAmount = Mathf.Max(data.echoShockAmount, 10f); IBullet bullet = gun.GetBullet(); if (bullet != null) { Action<IBullet> action = ResolveBulletRelease(gun); gun.ModifyBulletData(ref bulletData, (BulletFlags)11); bullet.Initialize(bulletData, (IDamageSource)(object)gun, action, (BulletFlags)11); } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] Echo fire failed: " + ex.Message)); } } } private static Action<IBullet> ResolveBulletRelease(Gun gun) { try { FieldInfo fieldInfo = AccessTools.Field(typeof(Gun), "releaseBulletToPool"); if (fieldInfo != null && fieldInfo.GetValue(gun) is Action<IBullet> result) { return result; } } catch { } return delegate { }; } private void TickScouter(Gun gun) { //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: 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_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: 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_00f5: Unknown result type (might be due to invalid IL or missing references) if (highlightClearAt > 0f && Time.time >= highlightClearAt) { ClearHighlights(); } if (data.scouterInterval <= 0f || !gun.IsAiming || Time.time - LastScouterPulse < data.scouterInterval) { return; } LastScouterPulse = Time.time; try { Player player = gun.Player; if ((Object)(object)player == (Object)null) { return; } float num = ((data.scouterRadius > 0f) ? data.scouterRadius : 50f); Vector3 val = ((Component)player).transform.position + Vector3.up * 1.4f; Vector3 forward = ((Component)player).transform.forward; try { if ((Object)(object)gun.playerLook != (Object)null) { val = ((Component)gun.playerLook).transform.position; forward = ((Component)gun.playerLook).transform.forward; } } catch { } Vector3 val2 = val + forward * (num * 0.5f); int num2 = -1; try { RaycastHit val3 = default(RaycastHit); if (Physics.Raycast(val + forward * 0.35f, forward, ref val3, num * 2f, num2, (QueryTriggerInteraction)1)) { bool flag = false; try { if ((Object)(object)((RaycastHit)(ref val3)).collider != (Object)null && ((Component)((RaycastHit)(ref val3)).collider).transform.IsChildOf(((Component)player).transform)) { flag = true; } } catch { } if (!flag) { val2 = ((RaycastHit)(ref val3)).point; } } } catch { } Collider[] array = Physics.OverlapSphere(val2, num, -1, (QueryTriggerInteraction)1); int num3 = 0; float num4 = 0.15f; for (int i = 0; i < array.Length && num3 < 32; i++) { ITarget target = IDamageSource.GetTarget((Component)(object)array[i]); if (target == null || !target.IsAlive) { continue; } try { Vector3 val4 = ((IFollowable)target).GetHealthbarPosition() - val; if (((Vector3)(ref val4)).sqrMagnitude > 0.01f && Vector3.Dot(((Vector3)(ref val4)).normalized, forward) < num4) { continue; } } catch { } ISelectable val5 = (ISelectable)(object)target; if (val5 != null) { HighlightTarget(val5, 2.5f); num3++; } } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] Scouter: " + ex.Message)); } } } private void HighlightTarget(ISelectable selectable, float duration) { if (selectable == null) { return; } try { Highlighter.RegisterObjectForHighlight(selectable); if (!activeHighlights.Contains(selectable)) { activeHighlights.Add(selectable); } highlightClearAt = Mathf.Max(highlightClearAt, Time.time + duration); } catch { } } private void ClearHighlights() { for (int i = 0; i < activeHighlights.Count; i++) { try { Highlighter.RemoveObjectFromHighlighting(activeHighlights[i]); } catch { } } activeHighlights.Clear(); highlightClearAt = -999f; } private void DestroyC4Visual() { if ((Object)(object)c4Visual != (Object)null) { try { Object.Destroy((Object)(object)c4Visual); } catch { } c4Visual = null; } } public void ModifyBulletData(ref BulletData bullet, Gun gun) { //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) if (data.longwatchAimSeconds > 0f && AimHoldTime >= data.longwatchAimSeconds) { bullet.speed *= data.longwatchSpeedMult; bullet.gravity *= data.longwatchGravityMult; bullet.range.falloffStartDistance += data.longwatchRangeBonus; bullet.range.falloffEndDistance += data.longwatchRangeBonus; bullet.range.maxDamageRange += data.longwatchRangeBonus; } if (data.bonusBounces > 0) { bullet.maxBounces = Mathf.Max(bullet.maxBounces, data.bonusBounces); } if (data.rotAmount > 0f) { bullet.damageEffect = (EffectType)7; bullet.damageEffectAmount = Mathf.Max(bullet.damageEffectAmount, data.rotAmount); } else if (data.waterAmount > 0f) { bullet.damageEffect = (EffectType)9; bullet.damageEffectAmount = Mathf.Max(bullet.damageEffectAmount, data.waterAmount); } } public void OnBulletFired(IBullet bullet, ref BulletData bulletData) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) lastFiredBullet = bulletData; hasLastFiredBullet = true; if (data.pierceTargets > 0 && bullet != null) { SniperProjectilePierceHook.ResetBullet(bullet); } } public void OnShotFired(Gun gun) { //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) TwinShotHits.Clear(); if (BlockAutoReloadForChamber) { BlockAutoReloadForChamber = false; try { IUpgradable prefab = gun.Prefab; IWeapon val = (IWeapon)(object)((prefab is IWeapon) ? prefab : null); if (val != null) { gun.GunData.autoReloadWhenEmpty = val.GunData.autoReloadWhenEmpty; } else { gun.GunData.autoReloadWhenEmpty = true; } } catch { } } if (data.echoDelay > 0f && (Object)(object)gun != (Object)null) { try { Vector3 position = (hasLastFiredBullet ? lastFiredBullet.position : (((Object)(object)gun.GunData.firePoint != (Object)null) ? gun.GunData.firePoint.position : ((Component)gun).transform.position)); Quaternion rotation = (hasLastFiredBullet ? lastFiredBullet.rotation : (((Object)(object)gun.Player != (Object)null) ? ((Component)gun.Player.playerLook).transform.rotation : ((Component)gun).transform.rotation)); PendingEchoes.Add(new PendingEcho { fireAt = Time.time + data.echoDelay, position = position, rotation = rotation, damage = gun.GunData.damage * ((data.echoDamageScale > 0f) ? data.echoDamageScale : 0.85f), speed = (hasLastFiredBullet ? lastFiredBullet.speed : gun.GunData.bulletSpeed), gravity = (hasLastFiredBullet ? lastFiredBullet.gravity : gun.GunData.bulletGravity) }); } catch { } } } public void OnMagazineEmptied(Gun gun) { if (!data.oneInTheChamber || !ChamberBonusReady || (Object)(object)gun == (Object)null) { return; } gun.RemainingAmmo = 1f; ChamberBonusReady = false; BlockAutoReloadForChamber = true; try { gun.GunData.autoReloadWhenEmpty = false; } catch { } } public void OnFullReloadCompleted(Gun gun) { if (data.oneInTheChamber) { LastReloadWasFullTopOff = true; ChamberBonusReady = true; BlockAutoReloadForChamber = false; } } private void OnBeforeDamage(ref DamageCallbackData callback) { //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: 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) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) IDamageSource source = callback.source; object obj = ((source is Gun) ? source : null); if (obj == null) { IDamageSource source2 = callback.source; IDamageSource obj2 = ((source2 != null) ? source2.ParentSource : null); obj = ((obj2 is Gun) ? obj2 : null); } Gun val = (Gun)obj; if ((Object)(object)val == (Object)null || !IsOurGear((IGear)(object)val)) { return; } ITarget target = callback.target; if (target == null) { return; } if (data.shellDamageMult > 1.01f && IsShellTarget(target)) { callback.damageData.damage *= data.shellDamageMult; } if (data.fullHpDamageMult > 1.01f && GetHealthFraction(target) >= 0.98f) { callback.damageData.damage *= data.fullHpDamageMult; } if (data.syncWindow > 0f && data.syncDamageMult > 1.01f && SniperAllyDamageTracker.WasDamagedByAlly(target, val, data.syncWindow)) { callback.damageData.damage *= data.syncDamageMult; } if (data.overkill && IsShellTarget(target)) { EnemyPart val2 = (EnemyPart)(object)((target is EnemyPart) ? target : null); if (val2 != null) { try { float health = val2.Health; float damage = callback.damageData.damage; if (health > 0f && damage > health + 0.01f) { pendingOverkill = damage - health; ref ITarget reference = ref pendingOverkillParent; IEnemyComponent parent = val2.Parent; reference = (ITarget)(object)((parent is ITarget) ? parent : null); pendingOverkillPos = callback.position; pendingOverkillGun = val; pendingOverkillEffect = callback.damageData.effect; pendingOverkillEffectAmt = callback.damageData.effectAmount; hasPendingOverkill = true; } } catch { } } } if (!(data.transferRelayScale > 0f) || !(callback.damageData.damage <= 0.01f)) { return; } try { float num = val.GunData.damage * data.transferRelayScale; IDamageSource.DamageTarget((IDamageSource)(object)val, target, new DamageData(num, (EffectType)(-1), 0f, (DamageFlags)0), callback.position, (Collider)null); } catch { } } private void ApplyPendingOverkill() { //IL_0018: 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_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) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) if (!hasPendingOverkill) { return; } float num = pendingOverkill; ITarget val = pendingOverkillParent; Vector3 val2 = pendingOverkillPos; Gun val3 = pendingOverkillGun; EffectType val4 = pendingOverkillEffect; float num2 = pendingOverkillEffectAmt; hasPendingOverkill = false; pendingOverkill = 0f; pendingOverkillParent = null; pendingOverkillGun = null; if (num <= 0.01f || val == null || !val.IsAlive || (Object)(object)val3 == (Object)null) { return; } try { IDamageSource.DamageTarget((IDamageSource)(object)val3, val, new DamageData(num, val4, num2 * 0.5f, (DamageFlags)0), val2, (Collider)null); } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] Overkill carry: " + ex.Message)); } } } private static bool IsShellTarget(ITarget target) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 try { EnemyPart val = (EnemyPart)(object)((target is EnemyPart) ? target : null); if (val != null) { if ((val.ComponentType & 4) != 0) { return true; } if ((val.ComponentType & 2) == 0 && (int)val.ComponentType != 1) { return true; } } } catch { } return (((object)((target is Component) ? target : null))?.GetType().Name ?? ((object)target).GetType().Name).IndexOf("Shell", StringComparison.OrdinalIgnoreCase) >= 0; } private static float GetHealthFraction(ITarget target) { try { EnemyPart val = (EnemyPart)(object)((target is EnemyPart) ? target : null); if (val != null) { return val.NormalizedHealth; } } catch { } try { float maxHealth = target.MaxHealth; if (maxHealth > 0f) { EnemyPart val2 = (EnemyPart)(object)((target is EnemyPart) ? target : null); if (val2 != null) { return val2.Health / maxHealth; } } } catch { } return 0.5f; } private void OnDamageTarget(in DamageCallbackData callback) { //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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) if (callback.source == null) { return; } IDamageSource source = callback.source; Gun val = (Gun)(((object)((source is Gun) ? source : null)) ?? ((object)/*isinst with value type is only supported in some contexts*/)); if ((Object)(object)val == (Object)null || !IsOurGear((IGear)(object)val) || callback.damageData.damage <= 0f) { return; } ITarget target = callback.target; if (target == null) { return; } if (BlockAutoReloadForChamber && val.RemainingAmmoCount <= 0) { BlockAutoReloadForChamber = false; } if (data.deathMark) { ApplyDeathMark(target, callback.position, headshot: false); } if (data.spotterRadius > 0f) { float duration = ((data.spotterDuration > 0f) ? data.spotterDuration : 6f); ISelectable val2 = (ISelectable)(object)target; if (val2 != null) { HighlightTarget(val2, duration); } try { Collider[] array = Physics.OverlapSphere(callback.position, data.spotterRadius, -1, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length && i < 32; i++) { ITarget target2 = IDamageSource.GetTarget((Component)(object)array[i]); if (target2 != null && target2.IsAlive && target2 != target) { ISelectable val3 = (ISelectable)(object)target2; if (val3 != null) { HighlightTarget(val3, duration); } } } } catch { } } if (data.rotSplashRadius > 0f && data.rotAmount > 0f) { try { GameManager.Instance.SpawnExplosionFirstPerson((IDamageSource)(object)val, callback.position, data.rotSplashRadius, (TargetType)5, new DamageData(0f, (EffectType)7, data.rotAmount, (DamageFlags)16), 1.5f); } catch { } } if (data.twinLinkFenceDamage > 0f && !TwinShotHits.Contains(target)) { TwinShotHits.Add(target); if (TwinShotHits.Count >= 2) { TryTwinFence(val); } } if (ExhaustionShotArmed && data.exhaustionSlowDuration > 0f) { ExhaustionShotArmed = false; ExhaustionReadyAt = Time.time + data.exhaustionCooldown; try { target.SlowTargetThisTick(Mathf.Clamp01(1f - data.exhaustionSlowStrength * 0.05f)); IDamageSource.DamageTarget((IDamageSource)(object)val, target, new DamageData(0f, (EffectType)10, data.exhaustionSlowStrength, (DamageFlags)0), callback.position, (Collider)null); } catch { } } if (!(data.disruptDuration > 0f)) { return; } try { string text = ((object)((target is Component) ? target : null))?.GetType().Name ?? ""; if (text.IndexOf("Shield", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Bubble", StringComparison.OrdinalIgnoreCase) >= 0) { IDamageSource.DamageTarget((IDamageSource)(object)val, target, new DamageData(val.GunData.damage * 3.5f, (EffectType)(-1), 0f, (DamageFlags)0), callback.position, (Collider)null); } } catch { } } private void ApplyDeathMark(ITarget target, Vector3 pos, bool headshot) { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: 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) //IL_0073: Unknown result type (might be due to invalid IL or missing references) float num = data.deathMarkFuse * (headshot ? data.deathMarkHeadshotFuseMult : 1f); for (int i = 0; i < DeathMarks.Count; i++) { if (DeathMarks[i].target == target) { DeathMarkEntry value = DeathMarks[i]; value.stacks += 1f; value.detonateAt = Mathf.Min(value.detonateAt, Time.time + num); value.lastPos = pos; DeathMarks[i] = value; return; } } DeathMarks.Add(new DeathMarkEntry { target = target, detonateAt = Time.time + num, stacks = 1f, lastPos = pos, fromHeadshot = headshot }); } private void TryTwinFence(Gun gun) { //IL_00bb: 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_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) if (TwinShotHits.Count < 2) { return; } try { ITarget val = TwinShotHits[0]; ITarget val2 = TwinShotHits[1]; Vector3 healthbarPosition = ((IFollowable)val).GetHealthbarPosition(); Vector3 healthbarPosition2 = ((IFollowable)val2).GetHealthbarPosition(); if (Vector3.Distance(healthbarPosition, healthbarPosition2) < 0.05f) { TwinShotHits.Clear(); return; } float num = Mathf.Max(14f, data.twinLinkFenceDamage * 0.15f); float twinLinkFenceDamage = data.twinLinkFenceDamage; try { IDamageSource.DamageTarget((IDamageSource)(object)gun, val, new DamageData(twinLinkFenceDamage * 0.5f, (EffectType)2, num, (DamageFlags)0), healthbarPosition, (Collider)null); IDamageSource.DamageTarget((IDamageSource)(object)gun, val2, new DamageData(twinLinkFenceDamage * 0.5f, (EffectType)2, num, (DamageFlags)0), healthbarPosition2, (Collider)null); } catch { } Vector3 val3 = (healthbarPosition + healthbarPosition2) * 0.5f; try { GameManager.Instance.SpawnExplosionFirstPerson((IDamageSource)(object)gun, val3, Mathf.Max(1.2f, data.twinLinkFenceRadius * 0.5f), (TargetType)5, new DamageData(twinLinkFenceDamage * 0.35f, (EffectType)2, num, (DamageFlags)16), 1.2f); } catch { } for (int i = 0; i < 2; i++) { ITarget obj3 = TwinShotHits[i]; EnemyPart val4 = (EnemyPart)(object)((obj3 is EnemyPart) ? obj3 : null); if (val4 == null) { continue; } IEnemyComponent parent = val4.Parent; ITarget val5 = (ITarget)(object)((parent is ITarget) ? parent : null); if (val5 != null && val5.IsAlive) { try { IDamageSource.DamageTarget((IDamageSource)(object)gun, val5, new DamageData(twinLinkFenceDamage * 0.4f, (EffectType)2, num, (DamageFlags)0), ((IFollowable)val5).GetHealthbarPosition(), (Collider)null); } catch { } } } } catch { } TwinShotHits.Clear(); } private void OnKillTarget(in KillCallbackData callback) { if (callback.source == null) { return; } IDamageSource source = callback.source; Gun val = (Gun)(((object)((source is Gun) ? source : null)) ?? ((object)/*isinst with value type is only supported in some contexts*/)); if (!((Object)(object)val == (Object)null) && IsOurGear((IGear)(object)val)) { LastKillTime = Time.time; if (data.overkill) { ApplyPendingOverkill(); } } } public bool IsDeadboltActive() { if (data.deadboltDuration > 0f) { return Time.time - LastKillTime <= data.deadboltDuration; } return false; } public bool IsLongwatchActive() { if (data.longwatchAimSeconds > 0f) { return AimHoldTime >= data.longwatchAimSeconds; } return false; } public bool IsAnchored(Gun gun) { //IL_002a: 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) if (!data.anchor || (Object)(object)((gun != null) ? gun.Player : null) == (Object)null) { return false; } try { Vector3 velocity = gun.Player.Velocity; velocity.y = 0f; return ((Vector3)(ref velocity)).sqrMagnitude <= data.anchorSpeedThreshold * data.anchorSpeedThreshold && !gun.Player.IsSprinting && !gun.Player.Sliding; } catch { return false; } } public void TryThrowOrDetonateC4(Gun gun) { //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01da: 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_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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_0031: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: 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) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: 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) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) if (!data.highExplosive || (Object)(object)gun == (Object)null || !((NetworkBehaviour)gun).IsOwner) { return; } if (C4Deployed) { try { GameManager.Instance.SpawnExplosionFirstPerson((IDamageSource)(object)gun, C4Position, data.c4Radius, (TargetType)5, new DamageData(data.c4Damage, (EffectType)0, 0f, (DamageFlags)16), 3f); } catch { try { GameManager.Instance.SpawnExplosionObserverSeeThrough((IDamageSource)(object)gun, C4Position, data.c4Radius, (TargetType)5, new DamageData(data.c4Damage, (EffectType)0, 0f, (DamageFlags)16), ((NetworkBehaviour)gun).OwnerClientId, 12f); } catch { } } DestroyC4Visual(); C4Deployed = false; return; } try { PlayerLook val = gun.Player?.playerLook; Vector3 val2 = (((Object)(object)val != (Object)null) ? ((Component)val).transform.position : ((Component)gun).transform.position); Vector3 val3 = (((Object)(object)val != (Object)null) ? ((Component)val).transform.forward : ((Component)gun).transform.forward); C4Position = val2 + val3 * data.c4ThrowForce * 0.65f + Vector3.up * 0.5f; RaycastHit val4 = default(RaycastHit); if (Physics.Raycast(C4Position + Vector3.up * 2f, Vector3.down, ref val4, 40f)) { C4Position = ((RaycastHit)(ref val4)).point + Vector3.up * 0.15f; } C4Deployed = true; C4DeployedAt = Time.time; SpawnC4Visual(C4Position); } catch { C4Position = ((Component)gun).transform.position + ((Component)gun).transform.forward * 10f; C4Deployed = true; C4DeployedAt = Time.time; SpawnC4Visual(C4Position); } } private void SpawnC4Visual(Vector3 pos) { //IL_002d: 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) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) DestroyC4Visual(); try { c4Visual = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)c4Visual).name = "BallisticSniper_C4"; c4Visual.transform.position = pos; c4Visual.transform.localScale = Vector3.one * 0.35f; Collider component = c4Visual.GetComponent<Collider>(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } Renderer component2 = c4Visual.GetComponent<Renderer>(); if ((Object)(object)component2 != (Object)null) { component2.material.color = new Color(0.15f, 0.15f, 0.15f, 1f); } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] C4 visual: " + ex.Message)); } } } private void OnDestroy() { if ((Object)(object)boundGun != (Object)null) { BindHooks(boundGun, bind: false); } ClearHighlights(); DestroyC4Visual(); } public static bool TryGet(IGear gear, out BallisticSniperBehaviour behaviour) { behaviour = null; if ((Object)(object)((gear != null) ? gear.gameObject : null) == (Object)null) { return false; } behaviour = gear.gameObject.GetComponent<BallisticSniperBehaviour>(); if ((Object)(object)behaviour != (Object)null) { return true; } bool num = (Object)(object)((IUpgradable)gear).Info != (Object)null && (((IUpgradable)gear).Info.APIName == "ballistic_sniper" || ((IUpgradable)gear).Info.ID == 87421); BallisticSniperBehaviour ballisticSniperBehaviour = null; IUpgradable prefab = ((IUpgradable)gear).Prefab; Component val = (Component)(object)((prefab is Component) ? prefab : null); if (val != null) { ballisticSniperBehaviour = val.GetComponent<BallisticSniperBehaviour>(); } if (!num && (Object)(object)ballisticSniperBehaviour == (Object)null) { return false; } string desc = (((Object)(object)ballisticSniperBehaviour != (Object)null) ? ballisticSniperBehaviour.Description : "Heavy kinetic bolt-action rifle. High single-shot damage, low capacity, and a deliberate single-round reload. Built for long-range elimination."); behaviour = gear.gameObject.AddComponent<BallisticSniperBehaviour>(); behaviour.InitializeAsPrefab(desc); if ((Object)(object)ballisticSniperBehaviour != (Object)null) { behaviour.CopyFrom(ballisticSniperBehaviour); } return true; } public static bool IsOurGear(IGear gear) { if ((Object)(object)((gear != null) ? ((IUpgradable)gear).Info : null) == (Object)null) { return false; } if (!(((IUpgradable)gear).Info.APIName == "ballistic_sniper")) { return ((IUpgradable)gear).Info.ID == 87421; } return true; } public static bool IsOurGear(IUpgradable gear) { if ((Object)(object)((gear != null) ? gear.Info : null) == (Object)null) { return false; } if (!(gear.Info.APIName == "ballistic_sniper")) { return gear.Info.ID == 87421; } return true; } } internal static class BallisticSniperCombatHooks { public static void Apply(Harmony harmony) { TryPatch(harmony, typeof(SniperGunUpdateHook)); TryPatch(harmony, typeof(SniperModifyBulletHook)); TryPatch(harmony, typeof(SniperCartridgeModifyBulletHook)); TryPatch(harmony, typeof(SniperOnFireHook)); TryPatch(harmony, typeof(SniperCartridgeOnFireHook)); TryPatch(harmony, typeof(SniperOnFiredBulletHook)); TryPatch(harmony, typeof(SniperRecoilHook)); TryPatch(harmony, typeof(SniperUpgradesEnabledHook)); TryPatch(harmony, typeof(SniperUpgradesDisabledHook)); TryPatch(harmony, typeof(SniperReloadHoldC4Hook)); TryPatch(harmony, typeof(SniperCanReloadHook)); TryPatch(harmony, typeof(SniperProjectileBounceHomingHook)); TryPatch(harmony, typeof(SniperProjectilePierceHook)); TryPatch(harmony, typeof(SniperAllyDamageTracker)); } private static void TryPatch(Harmony harmony, Type patchClass) { try { harmony.PatchAll(patchClass); } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogWarning((object)("[BallisticSniper] Skipped patch " + patchClass.Name + ": " + ex.Message)); } } } } [HarmonyPatch(typeof(Gun), "Update")] internal static class SniperGunUpdateHook { [HarmonyPostfix] private static void Postfix(Gun __instance) { try { if (!((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).IsOwner && BallisticSniperBehaviour.TryGet((IGear)(object)__instance, out var behaviour)) { behaviour.Tick(Time.deltaTime, __instance); } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] Update: " + ex.Message)); } } } } [HarmonyPatch(typeof(Gun), "ModifyBulletData")] internal static class SniperModifyBulletHook { [HarmonyPostfix] private static void Postfix(Gun __instance, ref BulletData data) { try { if (!((Object)(object)__instance == (Object)null) && !(__instance is CartridgeSMG) && BallisticSniperBehaviour.TryGet((IGear)(object)__instance, out var behaviour)) { behaviour.ModifyBulletData(ref data, __instance); } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] ModifyBullet: " + ex.Message)); } } } } [HarmonyPatch(typeof(CartridgeSMG), "ModifyBulletData")] internal static class SniperCartridgeModifyBulletHook { [HarmonyPostfix] private static void Postfix(CartridgeSMG __instance, ref BulletData data, BulletFlags flags) { try { if (!((Object)(object)__instance == (Object)null) && BallisticSniperBehaviour.TryGet((IGear)(object)__instance, out var behaviour)) { behaviour.ModifyBulletData(ref data, (Gun)(object)__instance); } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] SMG ModifyBullet: " + ex.Message)); } } } } [HarmonyPatch(typeof(Gun), "OnFire")] internal static class SniperOnFireHook { [HarmonyPostfix] private static void Postfix(Gun __instance) { try { if (!((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).IsOwner && BallisticSniperBehaviour.TryGet((IGear)(object)__instance, out var behaviour)) { behaviour.OnShotFired(__instance); } } catch { } } } [HarmonyPatch(typeof(CartridgeSMG), "OnFire")] internal static class SniperCartridgeOnFireHook { [HarmonyPostfix] private static void Postfix(CartridgeSMG __instance, int numBullets) { try { if (!((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).IsOwner && BallisticSniperBehaviour.TryGet((IGear)(object)__instance, out var behaviour)) { behaviour.OnShotFired((Gun)(object)__instance); } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] Cartridge OnFire: " + ex.Message)); } } } } [HarmonyPatch(typeof(Gun), "OnFiredBullet")] internal static class SniperOnFiredBulletHook { [HarmonyPostfix] private static void Postfix(Gun __instance, IBullet bullet, BulletFlags flags, int shotIndex, ref BulletData bulletData) { try { if (!((Object)(object)__instance == (Object)null) && bullet != null && BallisticSniperBehaviour.TryGet((IGear)(object)__instance, out var behaviour)) { behaviour.OnBulletFired(bullet, ref bulletData); } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] OnFiredBullet: " + ex.Message)); } } } } [HarmonyPatch(typeof(Gun), "AddRecoil")] internal static class SniperRecoilHook { [HarmonyPrefix] private static void Prefix(Gun __instance, ref float multiplier) { try { if (!((Object)(object)__instance == (Object)null) && BallisticSniperBehaviour.TryGet((IGear)(object)__instance, out var behaviour) && behaviour.IsAnchored(__instance)) { multiplier = 0f; } } catch { } } } [HarmonyPatch(typeof(Gun), "OnUpgradesEnabled")] internal static class SniperUpgradesEnabledHook { [HarmonyPostfix] private static void Postfix(Gun __instance) { try { if (!((Object)(object)__instance == (Object)null) && BallisticSniperBehaviour.TryGet((IGear)(object)__instance, out var behaviour)) { behaviour.OnUpgradesApplied(__instance); } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] OnUpgradesEnabled: " + ex.Message)); } } } } [HarmonyPatch(typeof(Gun), "OnUpgradesDisabled")] internal static class SniperUpgradesDisabledHook { [HarmonyPrefix] private static void Prefix(Gun __instance) { try { if (!((Object)(object)__instance == (Object)null) && BallisticSniperBehaviour.TryGet((IGear)(object)__instance, out var behaviour)) { behaviour.OnUpgradesCleared(__instance); } } catch { } } } [HarmonyPatch(typeof(Gun), "OnReloadPerformed")] internal static class SniperReloadHoldC4Hook { [HarmonyPrefix] private static bool Prefix(Gun __instance) { try { if ((Object)(object)__instance == (Object)null || !((NetworkBehaviour)__instance).IsOwner) { return true; } if (!BallisticSniperBehaviour.TryGet((IGear)(object)__instance, out var behaviour)) { return true; } if (!behaviour.WeaponData.highExplosive) { return true; } if (behaviour.C4Deployed) { behaviour.TryThrowOrDetonateC4(__instance); return false; } if (__instance.RemainingAmmoCount >= __instance.GunData.magazineSize) { behaviour.TryThrowOrDetonateC4(__instance); return false; } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] C4 reload: " + ex.Message)); } } return true; } } [HarmonyPatch(typeof(Gun), "CanReload")] internal static class SniperCanReloadHook { [HarmonyPrefix] private static bool Prefix(Gun __instance, ref bool __result) { try { if ((Object)(object)__instance == (Object)null || !((NetworkBehaviour)__instance).IsOwner) { return true; } if (!BallisticSniperBehaviour.TryGet((IGear)(object)__instance, out var behaviour)) { return true; } if (!behaviour.WeaponData.oneInTheChamber) { return true; } if (behaviour.BlockAutoReloadForChamber && __instance.RemainingAmmoCount > 0) { __result = false; return false; } } catch { } return true; } } [HarmonyPatch(typeof(SimpleProjectileBullet), "Bounce")] internal static class SniperProjectileBounceHomingHook { [HarmonyPostfix] private static void Postfix(SimpleProjectileBullet __instance, ref RaycastHit hit) { //IL_00a2: 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_00b1: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_0130: 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_0137: 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_0220: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)__instance == (Object)null) { return; } IDamageSource parentSource = __instance.ParentSource; Gun val = (Gun)(object)((parentSource is Gun) ? parentSource : null); if (val == null || !BallisticSniperBehaviour.TryGet((IGear)(object)val, out var behaviour) || (behaviour.WeaponData.postBounceHoming <= 0f && behaviour.WeaponData.bonusBounces <= 0)) { return; } FieldInfo fieldInfo = AccessTools.Field(typeof(SimpleProjectileBullet), "data"); FieldInfo fieldInfo2 = AccessTools.Field(typeof(SimpleProjectileBullet), "velocity"); if (fieldInfo == null || !(fieldInfo.GetValue(__instance) is BulletData val2)) { return; } Vector3 point = ((RaycastHit)(ref hit)).point; float num = Mathf.Max(25f, behaviour.WeaponData.postBounceHoming * 8f); ITarget val3 = null; float num2 = float.MaxValue; int num3 = val2.targetCollisionMask; if (num3 == 0) { num3 = -1; } Collider[] array = Physics.OverlapSphere(point, num, num3, (QueryTriggerInteraction)1); ITarget target = IDamageSource.GetTarget((Component)(object)((RaycastHit)(ref hit)).collider); Vector3 val4; for (int i = 0; i < array.Length; i++) { ITarget target2 = IDamageSource.GetTarget((Component)(object)array[i]); if (target2 != null && target2.IsAlive && target2 != target) { val4 = ((IFollowable)target2).GetHealthbarPosition() - point; float sqrMagnitude = ((Vector3)(ref val4)).sqrMagnitude; if (sqrMagnitude < num2) { num2 = sqrMagnitude; val3 = target2; } } } if (val3 == null) { return; } val4 = ((IFollowable)val3).GetHealthbarPosition() - point; Vector3 normalized = ((Vector3)(ref val4)).normalized; float num4 = Mathf.Clamp01(behaviour.WeaponData.postBounceHoming / 8f); num4 = Mathf.Max(num4, 0.75f); val4 = Vector3.Slerp(val2.direction, normalized, num4); val2.direction = ((Vector3)(ref val4)).normalized; fieldInfo.SetValue(__instance, val2); if (fieldInfo2 != null) { val4 = (Vector3)fieldInfo2.GetValue(__instance); float num5 = ((Vector3)(ref val4)).magnitude; if (num5 < 1f) { num5 = ((val2.speed > 0f) ? val2.speed : 220f); } fieldInfo2.SetValue(__instance, val2.direction * num5); } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] Projectile bounce homing: " + ex.Message)); } } } } [HarmonyPatch(typeof(SimpleProjectileBullet), "OnHit")] internal static class SniperProjectilePierceHook { private static readonly Dictionary<int, int> HitCounts = new Dictionary<int, int>(32); private static readonly FieldInfo BouncesField = AccessTools.Field(typeof(SimpleProjectileBullet), "bounces"); private static readonly FieldInfo DataField = AccessTools.Field(typeof(SimpleProjectileBullet), "data"); private static readonly FieldInfo IsAliveField = AccessTools.Field(typeof(SimpleProjectileBullet), "isAlive"); private static readonly FieldInfo VelocityField = AccessTools.Field(typeof(SimpleProjectileBullet), "velocity"); private static readonly FieldInfo PositionNextField = AccessTools.Field(typeof(SimpleProjectileBullet), "positionNext"); public static void ResetBullet(IBullet bullet) { if (bullet != null) { HitCounts[((object)bullet).GetHashCode()] = 0; } } [HarmonyPrefix] private static bool Prefix(SimpleProjectileBullet __instance, ref RaycastHit hit, ref Vector3 direction, ITarget target) { //IL_015c: 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_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0180: 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_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: 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_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0248: 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_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011f: 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) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0136: 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) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)__instance == (Object)null) { return true; } IDamageSource parentSource = __instance.ParentSource; Gun val = (Gun)(object)((parentSource is Gun) ? parentSource : null); if (val == null) { return true; } if (!BallisticSniperBehaviour.TryGet((IGear)(object)val, out var behaviour)) { return true; } if (behaviour.WeaponData.pierceTargets <= 0) { return true; } if (target == null || !IBullet.CanDamageTarget(target, (IBullet)(object)__instance)) { return true; } int hashCode = ((object)__instance).GetHashCode(); HitCounts.TryGetValue(hashCode, out var value); int pierceTargets = behaviour.WeaponData.pierceTargets; if (value >= pierceTargets) { return true; } float num = ((behaviour.WeaponData.pierceFalloff > 0f) ? behaviour.WeaponData.pierceFalloff : 0.25f); float num2 = ((value == 0) ? 1f : Mathf.Pow(Mathf.Clamp01(1f - num), (float)value)); if (BulletFlagsExtensions.IsOwner(__instance.Flags)) { BulletData val2 = (BulletData)((DataField != null && DataField.GetValue(__instance) is BulletData val3) ? val3 : default(BulletData)); float num3 = 1f; try { ref RangeData range = ref val2.range; Vector3 val4 = ((RaycastHit)(ref hit)).point - val2.position; num3 = ((RangeData)(ref range)).GetDamageMultiplier(((Vector3)(ref val4)).magnitude); } catch { } float num4 = val2.damage * num3 * num2; float num5 = val2.damageEffectAmount * num3 * num2; IDamageSource.DamageTarget((IDamageSource)(object)__instance, target, new DamageData(num4, val2.damageEffect, num5, val2.damageFlags), ((RaycastHit)(ref hit)).point, ((RaycastHit)(ref hit)).collider); } HitCounts[hashCode] = value + 1; Vector3 val5 = ((((Vector3)(ref direction)).sqrMagnitude > 0.001f) ? ((Vector3)(ref direction)).normalized : ((Component)__instance).transform.forward); Vector3 val6 = ((RaycastHit)(ref hit)).point + val5 * 0.35f; if (PositionNextField != null) { PositionNextField.SetValue(__instance, val6); } if (DataField != null && DataField.GetValue(__instance) is BulletData val7) { val7.position = val6; DataField.SetValue(__instance, val7); } if (IsAliveField != null) { IsAliveField.SetValue(__instance, true); } return false; } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] Projectile pierce: " + ex.Message)); } return true; } } } [HarmonyPatch(typeof(EnemyPart), "Damage")] internal static class SniperAllyDamageTracker { private struct HitRecord { public ulong ownerId; public float time; } private static readonly Dictionary<int, List<HitRecord>> Recent = new Dictionary<int, List<HitRecord>>(64); [HarmonyPostfix] private static void Postfix(EnemyPart __instance, DamageData data, IDamageSource source, Vector3 position) { try { if ((Object)(object)__instance == (Object)null || source == null) { return; } ulong num = ResolveOwnerId(source); if (num == ulong.MaxValue) { return; } int instanceID = ((Object)__instance).GetInstanceID(); if (!Recent.TryGetValue(instanceID, out var value)) { value = new List<HitRecord>(4); Recent[instanceID] = value; } float time = Time.time; for (int num2 = value.Count - 1; num2 >= 0; num2--) { if (time - value[num2].time > 6f) { value.RemoveAt(num2); } } value.Add(new HitRecord { ownerId = num, time = time }); if (value.Count > 8) { value.RemoveAt(0); } } catch { } } public static bool WasDamagedByAlly(ITarget target, Gun selfGun, float windowSeconds) { if (target == null || (Object)(object)selfGun == (Object)null || windowSeconds <= 0f) { return false; } try { EnemyPart val = (EnemyPart)(object)((target is EnemyPart) ? target : null); int instanceID; if (val != null) { instanceID = ((Object)val).GetInstanceID(); } else { Component val2 = (Component)(object)((target is Component) ? target : null); if (val2 == null) { return false; } instanceID = ((Object)val2).GetInstanceID(); } if (!Recent.TryGetValue(instanceID, out var value) || value.Count == 0) { return false; } ulong ownerClientId = ((NetworkBehaviour)selfGun).OwnerClientId; float time = Time.time; for (int num = value.Count - 1; num >= 0; num--) { if (!(time - value[num].time > windowSeconds) && value[num].ownerId != ownerClientId && value[num].ownerId != ulong.MaxValue) { return true; } } } catch { } return false; } private static ulong ResolveOwnerId(IDamageSource source) { try { IDamageSource val = source.GetBase(); Gun val2 = (Gun)(object)((val is Gun) ? val : null); if (val2 != null) { return ((NetworkBehaviour)val2).OwnerClientId; } Player val3 = (Player)(object)((val is Player) ? val : null); if (val3 != null) { return ((NetworkBehaviour)val3).OwnerClientId; } Gun val4 = (Gun)(object)((source is Gun) ? source : null); if (val4 != null) { return ((NetworkBehaviour)val4).OwnerClientId; } } catch { } return ulong.MaxValue; } } [HarmonyPatch(typeof(Gun), "OnAmmoLoaded")] internal static class BallisticSniperReloadHook { [HarmonyPostfix] private static void Postfix(Gun __instance) { try { if ((Object)(object)__instance == (Object)null || !((NetworkBehaviour)__instance).IsOwner || !BallisticSniperBehaviour.TryGet((IGear)(object)__instance, out var behaviour)) { return; } if (!behaviour.SingleRoundReload) { if (__instance.RemainingAmmoCount >= __instance.GunData.magazineSize) { behaviour.OnFullReloadCompleted(__instance); } } else { LoadOneRound(__instance, behaviour); } } catch (Exception arg) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogError((object)$"[BallisticSniper] OnAmmoLoaded hook failed: {arg}"); } } } private static void LoadOneRound(Gun gun, BallisticSniperBehaviour behaviour) { ref GunData gunData = ref gun.GunData; int num = Mathf.Max(gunData.magazineSize, 1); int remainingAmmoCount = gun.RemainingAmmoCount; if (remainingAmmoCount >= num) { behaviour.IsTubeReloading = false; behaviour.OnFullReloadCompleted(gun); return; } bool flag = false; if (gunData.hasLimitedAmmo) { if (gun.StoredAmmo >= 1f) { gun.StoredAmmo -= 1f; gun.RemainingAmmo = remainingAmmoCount + 1; flag = true; } } else { gun.RemainingAmmo = remainingAmmoCount + 1; flag = true; } if (!flag) { behaviour.IsTubeReloading = false; return; } if (gun.RemainingAmmoCount < num && (!gunData.hasLimitedAmmo || gun.StoredAmmo >= 1f)) { behaviour.IsTubeReloading = true; ((MonoBehaviour)gun).StartCoroutine(ContinueReloadAfterCurrent(gun)); return; } behaviour.IsTubeReloading = false; if (gun.RemainingAmmoCount >= num) { behaviour.OnFullReloadCompleted(gun); } } private static IEnumerator ContinueReloadAfterCurrent(Gun gun) { float timeout = 5f; while ((Object)(object)gun != (Object)null && gun.Reloading && timeout > 0f) { timeout -= Time.unscaledDeltaTime; yield return null; } yield return null; if ((Object)(object)gun == (Object)null || !((NetworkBehaviour)gun).IsOwner || !gun.Active || !BallisticSniperBehaviour.TryGet((IGear)(object)gun, out var behaviour) || !behaviour.IsTubeReloading || !behaviour.SingleRoundReload || gun.Reloading) { yield break; } ref GunData gunData = ref gun.GunData; if (gun.RemainingAmmoCount >= gunData.magazineSize) { behaviour.IsTubeReloading = false; yield break; } if (gunData.hasLimitedAmmo && gun.StoredAmmo < 1f) { behaviour.IsTubeReloading = false; yield break; } try { gun.Reload(); } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] Continue reload: " + ex.Message)); } behaviour.IsTubeReloading = false; } } } [HarmonyPatch(typeof(Gun), "Update")] internal static class BallisticSniperReloadInterruptHook { [HarmonyPrefix] private static void Prefix(Gun __instance) { try { if (!((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).IsOwner && __instance.Active && BallisticSniperBehaviour.TryGet((IGear)(object)__instance, out var behaviour) && behaviour.SingleRoundReload && (__instance.Reloading || behaviour.IsTubeReloading) && __instance.RemainingAmmoCount >= 1 && IsFirePressedOrHeld()) { behaviour.InterruptTubeReload(__instance); } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] Reload interrupt: " + ex.Message)); } } } private static bool IsFirePressedOrHeld() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) try { if (PlayerInput.Controls == null) { return false; } PlayerActions player = PlayerInput.Controls.Player; InputAction fire = ((PlayerActions)(ref player)).Fire; return fire.IsPressed() || fire.WasPressedThisFrame(); } catch { return false; } } } [HarmonyPatch(typeof(Gun), "GetReloadDuration")] internal static class BallisticSniperReloadDurationHook { [HarmonyPostfix] private static void Postfix(Gun __instance, ref float __result) { try { if (!((Object)(object)__instance == (Object)null) && BallisticSniperBehaviour.TryGet((IGear)(object)__instance, out var behaviour) && behaviour.SingleRoundReload) { int num = Mathf.Max(__instance.GunData.magazineSize, 1); __result = Mathf.Max(__result / (float)num, 0.12f); } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] GetReloadDuration: " + ex.Message)); } } } } [HarmonyPatch(typeof(Gun), "GetSpread")] internal static class BallisticSniperSpreadHook { private const float AdsSpread = 0.04f; private const float AdsMovingSpread = 1.15f; [HarmonyPostfix] private static void Postfix(Gun __instance, ref Vector2 __result) { //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) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)__instance == (Object)null || !BallisticSniperBehaviour.TryGet((IGear)(object)__instance, out var behaviour)) { return; } if (behaviour.IsDeadboltActive()) { __result = Vector2.zero; return; } bool isAiming = __instance.IsAiming; if (behaviour.WeaponData.autoTrigger && isAiming) { float autoTriggerAdsSpread = behaviour.WeaponData.autoTriggerAdsSpread; float num = Random.Range(0f, MathF.PI * 2f); float num2 = Random.Range(0f, autoTriggerAdsSpread); __result = new Vector2(Mathf.Cos(num) * num2, Mathf.Sin(num) * num2); } else if (isAiming) { float num3 = (IsMovingWhileScoped(__instance) ? 1.15f : 0.04f); if (num3 <= 0.001f) { __result = Vector2.zero; return; } float num4 = Random.Range(0f, MathF.PI * 2f); float num5 = Random.Range(0f, num3); __result = new Vector2(Mathf.Cos(num4) * num5, Mathf.Sin(num4) * num5); } } catch (Exception ex) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogDebug((object)("[BallisticSniper] GetSpread: " + ex.Message)); } } } private static bool IsMovingWhileScoped(Gun gun) { //IL_002a: 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) try { Player player = gun.Player; if ((Object)(object)player == (Object)null) { return false; } if (player.IsSprinting || player.Sliding) { return true; } try { Vector3 velocity = player.Velocity; velocity.y = 0f; if (((Vector3)(ref velocity)).sqrMagnitude > 0.122499995f) { return true; } } catch { } } catch { } return false; } } [Serializable] public class MatchGradeRoundsProperty : UpgradeProperty { public Range<float> damageBonus = new Range<float>(0.12f, 0.22f); public override IEnumerator<StatData> GetStatData(Random rand, IUpgradable gear, UpgradeInstance upgrade) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) yield return StatData.Create("Damage:", damageBonus, upgrade, ref rand, (OverrideType)2, (LabelType)1, default(BoostParams), (Range<float>?)null); } public override void Apply(IGear gear, UpgradeInstance upgrade, ref Random rand) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) IWeapon val = (IWeapon)(object)((gear is IWeapon) ? gear : null); if (val != null) { float value = damageBonus.GetValue(ref rand, upgrade, default(BoostParams)); val.GunData.damage *= 1f + value; } } public override void Remove(IGear gear, IGear prefab, UpgradeInstance upgrade, ref Random rand) { IWeapon val = (IWeapon)(object)((gear is IWeapon) ? gear : null); if (val != null) { IWeapon val2 = (IWeapon)(object)((prefab is IWeapon) ? prefab : null); if (val2 != null) { val.GunData.damage = val2.GunData.damage; } } } } [BepInPlugin("sparroh.antimaterialrifle", "AntiMaterialRifle", "1.2.0")] [MycoMod(/*Could not decode attribute arguments.*/)] public class SparrohPlugin : BaseUnityPlugin { public const string PluginGUID = "sparroh.antimaterialrifle"; public const string PluginName = "AntiMaterialRifle"; public const string PluginVersion = "1.2.0"; public const int GearId = 87421; public const string GearApiName = "ballistic_sniper"; public const string GearDisplayName = "Anti-Material Rifle"; public const string GearDescription = "Heavy kinetic bolt-action rifle. High single-shot damage, low capacity, and a deliberate single-round reload. Built for long-range elimination."; public const string BaseTypeName = "CartridgeSMG"; internal static ManualLogSource Logger; internal static SparrohPlugin Instance; internal static ConfigEntry<bool> GrantAllUpgrades; public static IUpgradable CustomWeaponPrefab; private Harmony _harmony; private bool _gearRegistered; private void Awake() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown Instance = this; Logger = ((BaseUnityPlugin)this).Logger; GrantAllUpgrades = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "GrantAllUpgrades", true, "Grant one unlocked inventory instance of each Anti-Material Rifle upgrade on load. Idempotent (tops up to 1). Disable before shipping if players should earn drops normally."); _harmony = new Harmony("sparroh.antimaterialrifle"); _harmony.PatchAll(typeof(GlobalLoadHook)); _harmony.PatchAll(typeof(PlayerDataPersistenceHooks)); _harmony.PatchAll(typeof(BallisticSniperReloadHook)); _harmony.PatchAll(typeof(BallisticSniperReloadInterruptHook)); _harmony.PatchAll(typeof(BallisticSniperReloadDurationHook)); _harmony.PatchAll(typeof(BallisticSniperSpreadHook)); _harmony.PatchAll(typeof(GearSelectionWindowHooks)); PlayerData.AddRegisterUpgradesCallback((Action)RegisterUpgrades); BallisticSniperCombatHooks.Apply(_harmony); SpawnGearHooks.Apply(_harmony); TryRegisterGear("Awake"); if (PlayerData.Instance != null) { RegisterUpgrades(); } Logger.LogInfo((object)"AntiMaterialRifle v1.2.0 loaded."); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; Instance = null; } internal void TryRegisterGear(string reason) { if (_gearRegistered) { return; } if ((Object)(object)Global.Instance == (Object)null || Global.Instance.AllGear == null || Global.Instance.AllGear.Length == 0) { Logger.LogDebug((object)("[BallisticSniper] Global.AllGear not ready yet (" + reason + ").")); return; } try { if (WeaponRegistration.TryCreateAndRegister("sparroh.antimaterialrifle", 87421, "ballistic_sniper", "Anti-Material Rifle", "Heavy kinetic bolt-action rifle. High single-shot damage, low capacity, and a deliberate single-round reload. Built for long-range elimination.", "CartridgeSMG", autoUnlock: true, Logger, out CustomWeaponPrefab)) { _gearRegistered = true; Logger.LogInfo((object)("[BallisticSniper] Registered gear 'Anti-Material Rifle' " + string.Format("(api={0}, id={1}) via {2}.", "ballistic_sniper", 87421, reason))); if (PlayerData.Instance != null) { RegisterUpgrades(); } } } catch (Exception arg) { Logger.LogError((object)$"[BallisticSniper] Gear registration failed: {arg}"); } } internal void RegisterUpgrades() { try { if (PlayerData.Instance == null) { Logger.LogDebug((object)"[BallisticSniper] Deferring upgrades — PlayerData.Instance null."); return; } IUpgradable val = ResolveRegisteredGear(); if (val == null) { Logger.LogDebug((object)"[BallisticSniper] Deferring upgrades until gear is registered."); return; } WeaponRegistration.EnsureGearData(val, autoUnlock: true, Logger); if (PlayerData.GetGearData(val) == null && PlayerData.GetGearData(val.Info.ID) == null) { Logger.LogDebug((object)"[BallisticSniper] Deferring upgrades — GearData not bound yet."); return; } CustomWeaponPrefab = val; SniperUpgrades.RegisterAll(Logger); } catch (Exception arg) { Logger.LogError((object)$"[BallisticSniper] Upgrade registration failed: {arg}"); } } internal static IUpgradable ResolveRegisteredGear() { if (CustomWeaponPrefab != null) { return CustomWeaponPrefab; } if (WeaponRegistration.CatalogGear != null) { return WeaponRegistration.CatalogGear; } return WeaponRegistration.FindGearSafe("ballistic_sniper", 87421); } } [HarmonyPatch(typeof(Global), "LoadInstance")] internal static class GlobalLoadHook { [HarmonyPostfix] private static void Postfix() { SparrohPlugin.Instance?.TryRegisterGear("Global.LoadInstance"); } } [HarmonyPatch(typeof(PlayerData), "OnAwake")] internal static class PlayerDataPersistenceHooks { [HarmonyPrefix] private static void Prefix() { SparrohPlugin.Instance?.TryRegisterGear("PlayerData.OnAwake.Prefix"); } [HarmonyPostfix] private static void Postfix() { try { SparrohPlugin.Instance?.TryRegisterGear("PlayerData.OnAwake.Postfix"); SparrohPlugin.Instance?.RegisterUpgrades(); IUpgradable val = SparrohPlugin.ResolveRegisteredGear(); if (val == null) { ManualLogSource logger = SparrohPlugin.Logger; if (logger != null) { logger.LogWarning((object)"[BallisticSniper] Persistence: gear missing after OnAwake."); } return; } GearData gearData = PlayerData.GetGearData(val); if (gearData == null) { WeaponRegistration.EnsureGearData(val, autoUnlock: true, SparrohPlugin.Logger); gearData = PlayerData.GetGearData(val); } else { gearData.Gear = val; } if (gearData != null) { if (!gearData.IsUnlocked) { gearData.Unlock(); } ManualLogSource logger2 = SparrohPlugin.Logger; if (logger2 != null) { string text = $"[BallisticSniper] Persistence OK: level={gearData.Level} unlocked={gearData.IsUnlocked} "; string text2 = $"equipped={gearData.EquippedUpgradeCount} xp={gearData.LevelXP} "; object arg = PlayerData.HasUpgrades(val); GearInfo info = val.Info; logger2.LogInfo((object)(text + text2 + $"HasUpgrades={arg} HasGrid={((info != null) ? new bool?(info.HasUpgradeGrid) : ((bool?)null))}.")); } } SniperUpgrades.GrantAllInstances(SparrohPlugin.Logger); } catch (Exception arg2) { ManualLogSource logger3 = SparrohPlugin.Logger; if (logger3 != null) { logger3.LogError((object)$"[BallisticSniper] Persistence postfix failed: {arg2}"); } } } } public static class SniperUpgradePatterns { public static HexMap Small() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0027: Expected O, but got Unknown HexMap val = new HexMap(2, 2); Set(val, 0, 0, enabled: true, 4); Set(val, 1, 0, enabled: true, 16); Set(val, 0, 1, enabled: true, 1); return val; } public static HexMap Line() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0028: Expected O, but got Unknown HexMap val = new HexMap(3, 1); Set(val, 0, 0, enabled: true, 4); Set(val, 1, 0, enabled: true, 20); Set(val, 2, 0, enabled: true, 16); return val; } public static HexMap Medium() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_003b: Expected O, but got Unknown HexMap val = new HexMap(3, 2); Set(val, 0, 0, enabled: true, 8); Set(val, 1, 0, enabled: true, 16); Set(val, 2, 0, enabled: true, 0); Set(val, 0, 1, enabled: true, 4); Set(val, 1, 1, enabled: true, 2); return val; } public static HexMap Large() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_003a: Expected O, but got Unknown HexMap val = new HexMap(3, 3); Set(val, 1, 0, enabled: true, 4); Set(val, 0, 1, enabled: true, 2); Set(val, 1, 1, enabled: true, 0); Set(val, 2, 1, enabled: true, 0); Set(val, 1, 2, enabled: true, 1); return val; } public static HexMap Wide() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_0045: Expected O, but got Unknown HexMap val = new HexMap(4, 2); Set(val, 0, 0, enabled: true, 4); Set(val, 1, 0, enabled: true, 8); Set(val, 2, 0, enabled: true, 16); Set(val, 1, 1, enabled: true, 1); Set(val, 2, 1, enabled: true, 1); Set(val, 3, 1, enabled: true, 0); return val; } public static HexMap Exotic() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0059: Expected O, but got Unknown HexMap val = new HexMap(4, 3); Set(val, 1, 0, enabled: true, 4); Set(val, 2, 0, enabled: true, 16); Set(val, 0, 1, enabled: true, 2); Set(val, 1, 1, enabled: true, 0); Set(val, 2, 1, enabled: true, 0); Set(val, 3, 1, enabled: true, 0); Set(val, 1, 2, enabled: true, 1); Set(val, 2, 2, enabled: true, 1); return val; } public static HexMap BoundaryIncursion() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0012: Expected O, but got Unknown HexMap val = new HexMap(1, 1); Set(val, 0, 0, enabled: true, 0); return val; } private static void Set(HexMap map, int x, int y, bool enabled, byte connections) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) ref Node reference = ref map[x, y]; reference.enabled = enabled; reference.connections = (Direction)connections; } } [Serializable] public class SniperProp_Hullbreaker : UpgradeProperty { public Range<float> mult = new Range<float>(1.9f, 2.3f); public override IEnumerator<StatData> GetStatData(Random rand, IUpgradable gear, UpgradeInstance upgrade) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) yield return StatData.Create("Shell damage:", mult, upgrade, ref rand, (OverrideType)2, (LabelType)1, default(BoostParams), (Range<float>?)null); } public override void Apply(IGear gear, UpgradeInstance upgrade, ref Random rand) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (BallisticSniperBehaviour.TryGet(gear, out var behaviour)) { behaviour.WeaponData.shellDamageMult *= mult.GetValue(ref rand, upgrade, default(BoostParams)); } } public override void Remove(IGear gear, IGear prefab, UpgradeInstance upgrade, ref Random rand) { if (BallisticSniperBehaviour.TryGet(gear, out var behaviour)) { behaviour.WeaponData.shellDamageMult = behaviour.GetPrefabSnapshot().shellDamageMult; } } } [Serializable] public class SniperProp_Subsonic : UpgradeProperty { public Range<float> mult = new Range<float>(2.1f, 2.6f); public override IEnumerator<StatData> GetStatData(Random rand, IUpgradable gear, UpgradeInstance upgrade) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) yield return StatData.Create("Full-HP damage:", mult, upgrade, ref rand, (OverrideType)2, (LabelType)1, default(BoostParams), (Range<float>?)null); } public override void Apply(IGear gear, UpgradeInstance upgrade, ref Random rand) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (BallisticSniperBehaviour.TryGet(gear, out var behaviour)) { behaviour.WeaponData.fullHpDamageMult *= mult.GetValue(ref rand, upgrade, default(BoostParams)); } } public override void Remove(IGear gear, IGear prefab, UpgradeInstance upgrade, ref Random rand) { if (BallisticSniperBehaviour.TryGet(gear, out var behaviour)) { behaviour.WeaponData.fullHpDamageMult = behaviour.GetPrefabSnapshot().fullHpDamageMult; } } } [Serializable] public class SniperProp_RicochetProtocol : UpgradeProperty { public Rang