using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Peak;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using Zorro.Settings;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyTitle("Useable Dynamite")]
[assembly: AssemblyDescription("PEAK plugin that makes dynamite a normal held/inventory item until primary-lit, while mesa hazards still auto-light.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Useable Dynamite")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("c6b6a11e-1b4e-4eec-8d52-1556e2cd79d2")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.0.0")]
[module: UnverifiableCode]
[BepInPlugin("tony4twentys.Useable_Dynamite", "Useable Dynamite", "2.0.0")]
[BepInProcess("PEAK.exe")]
public class UseableDynamitePlugin : BaseUnityPlugin
{
public const string PluginGuid = "tony4twentys.Useable_Dynamite";
public const string PluginName = "Useable Dynamite";
public const string PluginVersion = "2.0.0";
public const byte EventCode = 167;
public const string EventMagic = "tony4twentys.Useable_Dynamite";
public const int ProtocolVersion = 1;
internal const int GameplayPayloadLength = 26;
internal static ConfigEntry<bool> EnabledConfig;
internal static ConfigEntry<float> LightCastTimeConfig;
internal static ConfigEntry<bool> AllowPocketConfig;
internal static ConfigEntry<bool> AllowPocketWhileLitConfig;
internal static ConfigEntry<float> FuseTimeConfig;
internal static ConfigEntry<bool> HazardAutoLightConfig;
internal static ConfigEntry<float> HazardLightRadiusConfig;
internal static ConfigEntry<bool> LightOnThrowConfig;
internal static ConfigEntry<float> LightOnThrowMinChargeConfig;
internal static ConfigEntry<float> InHandInjuryConfig;
internal static ConfigEntry<float> ExplosionDamageMultiplierConfig;
internal static ConfigEntry<float> ExplosionRangeMultiplierConfig;
internal static ConfigEntry<float> ExplosionKnockbackMultiplierConfig;
internal static ConfigEntry<float> ExplosionVisualScaleConfig;
internal static ConfigEntry<bool> ExplosionCooksItemsConfig;
internal static ConfigEntry<float> ExplosionFallTimeMultiplierConfig;
internal static ConfigEntry<float> ExplosionVerticalKnockbackMultiplierConfig;
internal static ConfigEntry<bool> ExplosionLaunchItemsConfig;
internal static ConfigEntry<float> ExplosionItemKnockbackMultiplierConfig;
internal static ConfigEntry<bool> ExplosionRequireLineOfSightConfig;
internal static ConfigEntry<float> ThrowForceMultiplierConfig;
internal static ConfigEntry<int> CarryWeightConfig;
internal static ConfigEntry<bool> ExtinguishOnPocketConfig;
internal static ConfigEntry<bool> ResetFuseOnPocketConfig;
internal static ConfigEntry<bool> CleanupOrphanVfxConfig;
internal static ConfigEntry<bool> DisableFuseSmokeConfig;
internal static ConfigEntry<bool> DisableFuseSparksConfig;
internal static ConfigEntry<bool> ReduceExplosionOrbsConfig;
internal static ConfigEntry<float> ExplosionSmokeLifetimeConfig;
internal static ConfigEntry<bool> MuteExplosionAudioConfig;
internal static ConfigEntry<float> ExplosionVolumeConfig;
private Harmony _harmony;
private Coroutine _vfxCleanup;
private static GameplayValues _hostGameplay;
private static bool _hasHostGameplay;
internal static UseableDynamitePlugin Instance { get; private set; }
internal static ManualLogSource Log { get; private set; }
internal static bool Enabled
{
get
{
try
{
if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient && !DynamiteNet.HostModConfirmed)
{
return false;
}
}
catch
{
}
return Gameplay.Enabled;
}
}
internal static GameplayValues Gameplay => (DynamiteNet.UseHostGameplay && _hasHostGameplay) ? _hostGameplay : ReadLocalGameplay();
private void Awake()
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Expected O, but got Unknown
Instance = this;
Log = ((BaseUnityPlugin)this).Logger;
BindConfig();
DynamiteNet.Ensure();
_harmony = new Harmony("tony4twentys.Useable_Dynamite");
_harmony.PatchAll();
((BaseUnityPlugin)this).Logger.LogInfo((object)("Useable Dynamite v2.0.0 loaded. Photon " + (byte)167 + "."));
}
private void Start()
{
_vfxCleanup = ((MonoBehaviour)this).StartCoroutine(VfxCleanupLoop());
}
private void OnDestroy()
{
if (_vfxCleanup != null)
{
((MonoBehaviour)this).StopCoroutine(_vfxCleanup);
}
}
private void BindConfig()
{
EnabledConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch for the usable-item rules. Off = vanilla dynamite (self-lights when held).");
LightCastTimeConfig = ((BaseUnityPlugin)this).Config.Bind<float>("General", "LightCastTime", 0.4f, "Primary hold seconds before the fuse lights. 0 lights on the same press.");
AllowPocketConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowPocket", true, "Let unlit dynamite go into pockets and backpacks like a normal item.");
AllowPocketWhileLitConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "AllowPocketWhileLit", true, "If false, a lit stick cannot be pocketed and swapping slots drops it.");
FuseTimeConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Fuse", "FuseTime", 0f, "Fuse length in seconds when a stick lights. 0 keeps the vanilla prefab length.");
HazardAutoLightConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Fuse", "HazardAutoLight", true, "Naturally spawned mesa sticks auto-light when a player walks into their wick radius.");
HazardLightRadiusConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Fuse", "HazardLightRadius", 0f, "Override mesa auto-light radius in meters. 0 keeps the vanilla prefab radius. Larger radius lights more sticks at once.");
LightOnThrowConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Fuse", "LightOnThrow", false, "Light a player stick when it is thrown. Drops below MinThrowCharge stay unlit.");
LightOnThrowMinChargeConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Fuse", "LightOnThrowMinCharge", 0.1f, "Minimum throw charge (0-1) required for LightOnThrow. Matches vanilla throw threshold at 0.1.");
InHandInjuryConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Explosion", "InHandInjury", 0.25f, "Injury applied when a stick explodes in your own hand. Vanilla is 0.25.");
ExplosionDamageMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Explosion", "DamageMultiplier", 1f, "Multiplies blast status damage from the explosion prefab.");
ExplosionRangeMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Explosion", "RangeMultiplier", 1f, "Multiplies blast damage radius and visual spread. Higher hits more players/items and draws a bigger boom (worse FPS). Lower is cheaper.");
ExplosionKnockbackMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Explosion", "KnockbackMultiplier", 1f, "Multiplies blast knockback.");
ExplosionVisualScaleConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Explosion", "VisualScale", 1f, "Multiplies explosion VFX size only. Higher is heavier on GPU. Lower is cheaper. Does not change damage.");
ExplosionCooksItemsConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Explosion", "CooksItems", true, "If false, the blast will not cook nearby items.");
ExplosionFallTimeMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Explosion", "FallTimeMultiplier", 1f, "Multiplies how long victims stay ragdolled. Vanilla uses the prefab fallTime.");
ExplosionVerticalKnockbackMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Explosion", "VerticalKnockbackMultiplier", 1f, "Multiplies upward blast knockback only.");
ExplosionLaunchItemsConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Explosion", "LaunchItems", true, "If true, the blast can yeet nearby ground items. More flying items costs a bit more CPU.");
ExplosionItemKnockbackMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Explosion", "ItemKnockbackMultiplier", 1f, "Multiplies how hard launched items are thrown.");
ExplosionRequireLineOfSightConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Explosion", "RequireLineOfSight", false, "If true, terrain blocks blast damage, knockback, and cooking. Extra raycasts, slightly more CPU.");
ThrowForceMultiplierConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Item", "ThrowForceMultiplier", 1f, "Multiplies how hard a thrown stick flies. 1 keeps the prefab throw force.");
CarryWeightConfig = ((BaseUnityPlugin)this).Config.Bind<int>("Item", "CarryWeight", -1, "Inventory weight of a stick. -1 keeps the prefab weight.");
ExtinguishOnPocketConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Item", "ExtinguishOnPocket", true, "Snuff a lit stick when it is pocketed or put in a backpack.");
ResetFuseOnPocketConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Item", "ResetFuseOnPocket", true, "When ExtinguishOnPocket is on: true restores a full wick, false keeps the remaining fuse time.");
CleanupOrphanVfxConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("VFX", "CleanupOrphanVfx", true, "Destroy leftover fuse-smoke trackers after the stick is gone. Helps FPS if smoke trails leak. Tiny CPU scan once a second.");
DisableFuseSmokeConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("VFX", "DisableFuseSmoke", false, "Skip the lit-fuse smoke trail. Helps FPS when many sticks are lit. Does not change the explosion cloud.");
DisableFuseSparksConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("VFX", "DisableFuseSparks", false, "Hide fuse sparks (photosensitive sparks too). Slightly cheaper on GPU.");
ReduceExplosionOrbsConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("VFX", "ReduceExplosionOrbs", true, "Keep one center blast visual instead of vanilla chained orbs (4 plus sub-orbs). Helps FPS a lot. Extra orbs are VFX flashes, not extra damage. Off = prettier, heavier.");
ExplosionSmokeLifetimeConfig = ((BaseUnityPlugin)this).Config.Bind<float>("VFX", "ExplosionSmokeLifetime", 0f, "Seconds after the boom before lingering explosion smoke stops emitting and fades. 0 = vanilla (longest, heaviest). Lower fades the cloud sooner and helps FPS. Does not change fuse-trail smoke.");
MuteExplosionAudioConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("VFX", "MuteExplosionAudio", false, "Skip explosion sound. No CPU/GPU win; audio preference only.");
ExplosionVolumeConfig = ((BaseUnityPlugin)this).Config.Bind<float>("VFX", "ExplosionVolume", 1f, "Explosion sound volume multiplier. 1 is vanilla. 0 is silent. No performance change.");
HookHostGameplay<bool>(EnabledConfig);
HookHostGameplay<float>(LightCastTimeConfig);
HookHostGameplay<bool>(AllowPocketConfig);
HookHostGameplay<bool>(AllowPocketWhileLitConfig);
HookHostGameplay<float>(FuseTimeConfig);
HookHostGameplay<bool>(HazardAutoLightConfig);
HookHostGameplay<float>(HazardLightRadiusConfig);
HookHostGameplay<bool>(LightOnThrowConfig);
HookHostGameplay<float>(LightOnThrowMinChargeConfig);
HookHostGameplay<float>(InHandInjuryConfig);
HookHostGameplay<float>(ExplosionDamageMultiplierConfig);
HookHostGameplay<float>(ExplosionRangeMultiplierConfig);
HookHostGameplay<float>(ExplosionKnockbackMultiplierConfig);
HookHostGameplay<bool>(ExplosionCooksItemsConfig);
HookHostGameplay<float>(ExplosionFallTimeMultiplierConfig);
HookHostGameplay<float>(ExplosionVerticalKnockbackMultiplierConfig);
HookHostGameplay<bool>(ExplosionLaunchItemsConfig);
HookHostGameplay<float>(ExplosionItemKnockbackMultiplierConfig);
HookHostGameplay<bool>(ExplosionRequireLineOfSightConfig);
HookHostGameplay<float>(ThrowForceMultiplierConfig);
HookHostGameplay<int>(CarryWeightConfig);
HookHostGameplay<bool>(ExtinguishOnPocketConfig);
HookHostGameplay<bool>(ResetFuseOnPocketConfig);
}
private static void HookHostGameplay<T>(ConfigEntry<T> entry)
{
if (entry != null)
{
entry.SettingChanged += delegate
{
DynamiteNet.OnLocalSettingChanged();
};
}
}
internal static GameplayValues ReadLocalGameplay()
{
return new GameplayValues
{
Enabled = (EnabledConfig == null || EnabledConfig.Value),
LightCastTime = ((LightCastTimeConfig != null) ? LightCastTimeConfig.Value : 0.4f),
AllowPocket = (AllowPocketConfig == null || AllowPocketConfig.Value),
AllowPocketWhileLit = (AllowPocketWhileLitConfig == null || AllowPocketWhileLitConfig.Value),
FuseTime = ((FuseTimeConfig != null) ? FuseTimeConfig.Value : 0f),
HazardAutoLight = (HazardAutoLightConfig == null || HazardAutoLightConfig.Value),
HazardLightRadius = ((HazardLightRadiusConfig != null) ? HazardLightRadiusConfig.Value : 0f),
LightOnThrow = (LightOnThrowConfig != null && LightOnThrowConfig.Value),
LightOnThrowMinCharge = ((LightOnThrowMinChargeConfig != null) ? LightOnThrowMinChargeConfig.Value : 0.1f),
InHandInjury = ((InHandInjuryConfig != null) ? InHandInjuryConfig.Value : 0.25f),
DamageMultiplier = ((ExplosionDamageMultiplierConfig != null) ? ExplosionDamageMultiplierConfig.Value : 1f),
RangeMultiplier = ((ExplosionRangeMultiplierConfig != null) ? ExplosionRangeMultiplierConfig.Value : 1f),
KnockbackMultiplier = ((ExplosionKnockbackMultiplierConfig != null) ? ExplosionKnockbackMultiplierConfig.Value : 1f),
CooksItems = (ExplosionCooksItemsConfig == null || ExplosionCooksItemsConfig.Value),
FallTimeMultiplier = ((ExplosionFallTimeMultiplierConfig != null) ? ExplosionFallTimeMultiplierConfig.Value : 1f),
VerticalKnockbackMultiplier = ((ExplosionVerticalKnockbackMultiplierConfig != null) ? ExplosionVerticalKnockbackMultiplierConfig.Value : 1f),
LaunchItems = (ExplosionLaunchItemsConfig == null || ExplosionLaunchItemsConfig.Value),
ItemKnockbackMultiplier = ((ExplosionItemKnockbackMultiplierConfig != null) ? ExplosionItemKnockbackMultiplierConfig.Value : 1f),
RequireLineOfSight = (ExplosionRequireLineOfSightConfig != null && ExplosionRequireLineOfSightConfig.Value),
ThrowForceMultiplier = ((ThrowForceMultiplierConfig != null) ? ThrowForceMultiplierConfig.Value : 1f),
CarryWeight = ((CarryWeightConfig != null) ? CarryWeightConfig.Value : (-1)),
ExtinguishOnPocket = (ExtinguishOnPocketConfig == null || ExtinguishOnPocketConfig.Value),
ResetFuseOnPocket = (ResetFuseOnPocketConfig == null || ResetFuseOnPocketConfig.Value)
};
}
internal static object[] BuildGameplayPayload()
{
GameplayValues gameplayValues = ReadLocalGameplay();
return new object[26]
{
"tony4twentys.Useable_Dynamite",
1,
(byte)1,
gameplayValues.Enabled,
gameplayValues.LightCastTime,
gameplayValues.AllowPocket,
gameplayValues.AllowPocketWhileLit,
gameplayValues.FuseTime,
gameplayValues.HazardAutoLight,
gameplayValues.HazardLightRadius,
gameplayValues.LightOnThrow,
gameplayValues.LightOnThrowMinCharge,
gameplayValues.InHandInjury,
gameplayValues.DamageMultiplier,
gameplayValues.RangeMultiplier,
gameplayValues.KnockbackMultiplier,
gameplayValues.CooksItems,
gameplayValues.FallTimeMultiplier,
gameplayValues.VerticalKnockbackMultiplier,
gameplayValues.LaunchItems,
gameplayValues.ItemKnockbackMultiplier,
gameplayValues.RequireLineOfSight,
gameplayValues.ThrowForceMultiplier,
gameplayValues.CarryWeight,
gameplayValues.ExtinguishOnPocket,
gameplayValues.ResetFuseOnPocket
};
}
internal static void ApplyHostGameplay(object[] arr)
{
if (arr == null || arr.Length < 26)
{
throw new InvalidOperationException("Useable Dynamite config payload too short.");
}
_hostGameplay = new GameplayValues
{
Enabled = Convert.ToBoolean(arr[3]),
LightCastTime = Convert.ToSingle(arr[4]),
AllowPocket = Convert.ToBoolean(arr[5]),
AllowPocketWhileLit = Convert.ToBoolean(arr[6]),
FuseTime = Convert.ToSingle(arr[7]),
HazardAutoLight = Convert.ToBoolean(arr[8]),
HazardLightRadius = Convert.ToSingle(arr[9]),
LightOnThrow = Convert.ToBoolean(arr[10]),
LightOnThrowMinCharge = Convert.ToSingle(arr[11]),
InHandInjury = Convert.ToSingle(arr[12]),
DamageMultiplier = Convert.ToSingle(arr[13]),
RangeMultiplier = Convert.ToSingle(arr[14]),
KnockbackMultiplier = Convert.ToSingle(arr[15]),
CooksItems = Convert.ToBoolean(arr[16]),
FallTimeMultiplier = Convert.ToSingle(arr[17]),
VerticalKnockbackMultiplier = Convert.ToSingle(arr[18]),
LaunchItems = Convert.ToBoolean(arr[19]),
ItemKnockbackMultiplier = Convert.ToSingle(arr[20]),
RequireLineOfSight = Convert.ToBoolean(arr[21]),
ThrowForceMultiplier = Convert.ToSingle(arr[22]),
CarryWeight = Convert.ToInt32(arr[23]),
ExtinguishOnPocket = Convert.ToBoolean(arr[24]),
ResetFuseOnPocket = Convert.ToBoolean(arr[25])
};
_hasHostGameplay = true;
}
internal static void ClearHostGameplay()
{
_hasHostGameplay = false;
_hostGameplay = default(GameplayValues);
}
private IEnumerator VfxCleanupLoop()
{
WaitForSeconds wait = new WaitForSeconds(1f);
while (true)
{
yield return wait;
if (CleanupOrphanVfxConfig != null && CleanupOrphanVfxConfig.Value)
{
DynamiteUtil.CleanupOrphanVfx();
}
}
}
}
internal struct GameplayValues
{
public bool Enabled;
public float LightCastTime;
public bool AllowPocket;
public bool AllowPocketWhileLit;
public float FuseTime;
public bool HazardAutoLight;
public float HazardLightRadius;
public bool LightOnThrow;
public float LightOnThrowMinCharge;
public float InHandInjury;
public float DamageMultiplier;
public float RangeMultiplier;
public float KnockbackMultiplier;
public bool CooksItems;
public float FallTimeMultiplier;
public float VerticalKnockbackMultiplier;
public bool LaunchItems;
public float ItemKnockbackMultiplier;
public bool RequireLineOfSight;
public float ThrowForceMultiplier;
public int CarryWeight;
public bool ExtinguishOnPocket;
public bool ResetFuseOnPocket;
}
internal static class DynamiteUtil
{
private static bool _loggedWickError;
private static bool _loggedAwakeError;
private static bool _loggedLightError;
private static bool _loggedOwnedError;
private static bool _loggedTickError;
private static bool _loggedExplodeError;
private static readonly Dictionary<int, float> OrigFuse = new Dictionary<int, float>();
private static readonly Dictionary<int, float> OrigRadius = new Dictionary<int, float>();
private static readonly Dictionary<int, float> OrigThrow = new Dictionary<int, float>();
private static readonly Dictionary<int, int> OrigWeight = new Dictionary<int, int>();
private static readonly Dictionary<SFX_Instance, float> OrigSfxVolume = new Dictionary<SFX_Instance, float>();
private const DataEntryKey KeepRemainingKey = (DataEntryKey)15;
internal static bool LoggedWickError
{
get
{
return _loggedWickError;
}
set
{
_loggedWickError = value;
}
}
internal static bool LoggedAwakeError
{
get
{
return _loggedAwakeError;
}
set
{
_loggedAwakeError = value;
}
}
internal static bool LoggedTickError
{
get
{
return _loggedTickError;
}
set
{
_loggedTickError = value;
}
}
internal static bool IsDynamite(Item item)
{
return (Object)(object)item != (Object)null && (Object)(object)((Component)item).GetComponent<Dynamite>() != (Object)null;
}
internal static bool IsLit(Item item)
{
if ((Object)(object)item == (Object)null || item.data == null)
{
return false;
}
BoolItemData val = default(BoolItemData);
return item.data.TryGetDataEntry<BoolItemData>((DataEntryKey)3, ref val) && val != null && val.Value;
}
internal static bool IsWorldHazard(Dynamite dyn)
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Invalid comparison between Unknown and I4
if ((Object)(object)dyn == (Object)null)
{
return false;
}
Item item = ((ItemComponent)dyn).item;
if ((Object)(object)item == (Object)null)
{
return false;
}
if ((int)item.itemState > 0)
{
return false;
}
if ((Object)(object)item.holderCharacter != (Object)null)
{
return false;
}
if ((Object)(object)item.lastThrownCharacter != (Object)null)
{
return false;
}
if ((Object)(object)item.lastHolderCharacter != (Object)null)
{
return false;
}
return !HasPlayerOwnedFlag(item);
}
internal static bool HasPlayerOwnedFlag(Item item)
{
if ((Object)(object)item == (Object)null || item.data == null)
{
return false;
}
BoolItemData val = default(BoolItemData);
return item.data.TryGetDataEntry<BoolItemData>((DataEntryKey)8, ref val) && val != null && val.Value;
}
internal static void MarkPlayerOwned(Item item)
{
if ((Object)(object)item == (Object)null || item.data == null)
{
return;
}
try
{
MarkPlayerOwned(item.data);
}
catch (Exception ex)
{
LogOwnedError(ex);
}
}
internal static void MarkPlayerOwned(ItemInstanceData data)
{
if (data == null)
{
return;
}
try
{
BoolItemData val = default(BoolItemData);
if (!data.TryGetDataEntry<BoolItemData>((DataEntryKey)8, ref val) || val == null)
{
val = data.RegisterNewEntry<BoolItemData>((DataEntryKey)8);
}
val.Value = true;
}
catch (Exception ex)
{
LogOwnedError(ex);
}
}
internal static void MarkSpawnedDynamite(IEnumerable<PhotonView> views)
{
if (views == null)
{
return;
}
foreach (PhotonView view in views)
{
if (!((Object)(object)view == (Object)null))
{
Item component = ((Component)view).GetComponent<Item>();
if (IsDynamite(component))
{
MarkPlayerOwned(component);
}
}
}
}
internal static void RememberPrefabRadius(Dynamite dyn, bool assumeAlreadySquared)
{
if ((Object)(object)dyn == (Object)null)
{
return;
}
int instanceID = ((Object)dyn).GetInstanceID();
if (!OrigRadius.ContainsKey(instanceID))
{
float num = Mathf.Max(0f, dyn.lightFuseRadius);
if (assumeAlreadySquared)
{
OrigRadius[instanceID] = Mathf.Sqrt(num);
}
else
{
OrigRadius[instanceID] = num;
}
}
}
internal static void ApplyWickRadius(Dynamite dyn)
{
if (!((Object)(object)dyn == (Object)null))
{
RememberPrefabRadius(dyn, assumeAlreadySquared: true);
float value = UseableDynamitePlugin.Gameplay.HazardLightRadius;
if (value <= 0f)
{
OrigRadius.TryGetValue(((Object)dyn).GetInstanceID(), out value);
}
value = Mathf.Max(0f, value);
dyn.lightFuseRadius = value * value;
RefreshWickPosition(dyn);
}
}
internal static void RefreshWickPosition(Dynamite dyn)
{
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)dyn == (Object)null) && !((Object)(object)((Component)dyn).transform == (Object)null))
{
dyn.dynamitePosition = ((Component)dyn).transform.position;
}
}
internal static void RefreshAllSticks()
{
Dynamite[] array = Object.FindObjectsByType<Dynamite>((FindObjectsSortMode)0);
for (int i = 0; i < array.Length; i++)
{
ApplyStickSettings(array[i]);
}
}
internal static void ApplyStickSettings(Dynamite dyn)
{
if ((Object)(object)dyn == (Object)null || (Object)(object)((ItemComponent)dyn).item == (Object)null)
{
return;
}
int instanceID = ((Object)dyn).GetInstanceID();
Item item = ((ItemComponent)dyn).item;
if (!OrigFuse.ContainsKey(instanceID))
{
OrigFuse[instanceID] = ((dyn.startingFuseTime > 0f) ? dyn.startingFuseTime : 5f);
}
RememberPrefabRadius(dyn, assumeAlreadySquared: true);
if (!OrigThrow.ContainsKey(instanceID))
{
OrigThrow[instanceID] = item.throwForceMultiplier;
}
if (!OrigWeight.ContainsKey(instanceID))
{
OrigWeight[instanceID] = item.carryWeight;
}
dyn.startingFuseTime = GetConfiguredFuseTime(dyn);
ApplyWickRadius(dyn);
GameplayValues gameplay = UseableDynamitePlugin.Gameplay;
item.throwForceMultiplier = OrigThrow[instanceID] * Mathf.Max(0f, gameplay.ThrowForceMultiplier);
int carryWeight = gameplay.CarryWeight;
item.carryWeight = ((carryWeight >= 0) ? carryWeight : OrigWeight[instanceID]);
if (!IsLit(item) && item.data != null && !HasKeepRemaining(item.data))
{
FloatItemData data = ((ItemComponent)dyn).GetData<FloatItemData>((DataEntryKey)10, (Func<FloatItemData>)dyn.SetupDefaultFuel);
if (data != null)
{
data.Value = dyn.startingFuseTime;
dyn.fuseTime = dyn.startingFuseTime;
}
}
if (IsLit(item) && (Object)(object)dyn.hashGridObject != (Object)null)
{
dyn.hashGridObject.RemoveFromGrid();
}
ConfigureAsNormalItem(dyn);
}
internal static float GetConfiguredFuseTime(Dynamite dyn)
{
float fuseTime = UseableDynamitePlugin.Gameplay.FuseTime;
if (fuseTime > 0f)
{
return fuseTime;
}
if ((Object)(object)dyn != (Object)null && OrigFuse.TryGetValue(((Object)dyn).GetInstanceID(), out var value) && value > 0f)
{
return value;
}
if ((Object)(object)dyn != (Object)null && dyn.startingFuseTime > 0f)
{
return dyn.startingFuseTime;
}
return 5f;
}
internal static void ApplyConfiguredFuse(Dynamite dyn, bool forceFull)
{
if ((Object)(object)dyn == (Object)null)
{
return;
}
float num = (dyn.startingFuseTime = GetConfiguredFuseTime(dyn));
if (forceFull && !((Object)(object)((ItemComponent)dyn).item == (Object)null) && ((ItemComponent)dyn).item.data != null)
{
FloatItemData data = ((ItemComponent)dyn).GetData<FloatItemData>((DataEntryKey)10, (Func<FloatItemData>)dyn.SetupDefaultFuel);
if (data != null)
{
data.Value = num;
}
dyn.fuseTime = num;
}
}
internal static bool HasKeepRemaining(ItemInstanceData data)
{
if (data == null)
{
return false;
}
BoolItemData val = default(BoolItemData);
return data.TryGetDataEntry<BoolItemData>((DataEntryKey)15, ref val) && val != null && val.Value;
}
internal static void SetKeepRemaining(ItemInstanceData data, bool keep)
{
if (data != null)
{
BoolItemData val = default(BoolItemData);
if (!data.TryGetDataEntry<BoolItemData>((DataEntryKey)15, ref val) || val == null)
{
val = data.RegisterNewEntry<BoolItemData>((DataEntryKey)15);
}
val.Value = keep;
}
}
internal static void StampLightOnThrow(Item item, ItemInstanceData data, float throwCharge)
{
if (!UseableDynamitePlugin.Enabled || !UseableDynamitePlugin.Gameplay.LightOnThrow || (Object)(object)item == (Object)null || data == null || !IsDynamite(item) || IsLit(item))
{
return;
}
float lightOnThrowMinCharge = UseableDynamitePlugin.Gameplay.LightOnThrowMinCharge;
if (throwCharge < lightOnThrowMinCharge)
{
return;
}
MarkPlayerOwned(data);
BoolItemData val = default(BoolItemData);
if (!data.TryGetDataEntry<BoolItemData>((DataEntryKey)3, ref val) || val == null)
{
val = data.RegisterNewEntry<BoolItemData>((DataEntryKey)3);
}
val.Value = true;
if (!HasKeepRemaining(data))
{
Dynamite component = ((Component)item).GetComponent<Dynamite>();
float configuredFuseTime = GetConfiguredFuseTime(component);
FloatItemData val2 = default(FloatItemData);
if (!data.TryGetDataEntry<FloatItemData>((DataEntryKey)10, ref val2) || val2 == null)
{
val2 = data.RegisterNewEntry<FloatItemData>((DataEntryKey)10);
}
val2.Value = configuredFuseTime;
}
}
internal static void ConfigureAsNormalItem(Dynamite dyn)
{
if (!((Object)(object)dyn == (Object)null) && !((Object)(object)((ItemComponent)dyn).item == (Object)null) && ((ItemComponent)dyn).item.UIData != null)
{
Item item = ((ItemComponent)dyn).item;
GameplayValues gameplay = UseableDynamitePlugin.Gameplay;
bool flag = IsLit(item);
item.UIData.canPocket = gameplay.AllowPocket && (gameplay.AllowPocketWhileLit || !flag);
item.UIData.canBackpack = item.UIData.canPocket;
item.UIData.hasMainInteract = true;
if (string.IsNullOrEmpty(item.UIData.mainInteractPrompt))
{
item.UIData.mainInteractPrompt = "Light";
}
float usingTimePrimary = Mathf.Max(0f, gameplay.LightCastTime);
item.usingTimePrimary = usingTimePrimary;
}
}
internal static void TryLightFromPrimary(Item item)
{
try
{
if (!UseableDynamitePlugin.Enabled || (Object)(object)item == (Object)null)
{
return;
}
Dynamite component = ((Component)item).GetComponent<Dynamite>();
if (!((Object)(object)component == (Object)null))
{
Character holderCharacter = item.holderCharacter;
if (!((Object)(object)holderCharacter == (Object)null) && holderCharacter.IsLocal)
{
LightStick(component, item);
}
}
}
catch (Exception ex)
{
if (!_loggedLightError)
{
_loggedLightError = true;
UseableDynamitePlugin.Log.LogError((object)("Primary dynamite light failed: " + ex));
}
}
}
internal static void LightStick(Dynamite dyn, Item item)
{
if (!((Object)(object)dyn == (Object)null) && !((Object)(object)item == (Object)null) && !IsLit(item))
{
MarkPlayerOwned(item);
dyn.LightFlare();
}
}
internal static void TickDynamite(Dynamite dyn)
{
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Invalid comparison between Unknown and I4
//IL_02c4: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)dyn == (Object)null || (Object)(object)((ItemComponent)dyn).item == (Object)null)
{
return;
}
ConfigureAsNormalItem(dyn);
if (!IsLit(((ItemComponent)dyn).item))
{
RefreshWickPosition(dyn);
dyn.TestLightWick();
return;
}
if ((Object)(object)dyn.trackable != (Object)null && !dyn.trackable.hasTracker && (UseableDynamitePlugin.DisableFuseSmokeConfig == null || !UseableDynamitePlugin.DisableFuseSmokeConfig.Value))
{
dyn.EnableFlareVisuals();
}
bool flag = UseableDynamitePlugin.DisableFuseSparksConfig != null && UseableDynamitePlugin.DisableFuseSparksConfig.Value;
bool flag2 = dyn.setting != null && (int)((EnumSetting<OffOnMode>)(object)dyn.setting).Value == 1;
if ((Object)(object)dyn.sparks != (Object)null)
{
((Component)dyn.sparks).gameObject.SetActive(!flag && !flag2);
}
if ((Object)(object)dyn.sparksPhotosensitive != (Object)null)
{
((Component)dyn.sparksPhotosensitive).gameObject.SetActive(!flag && flag2);
}
FloatItemData data = ((ItemComponent)dyn).GetData<FloatItemData>((DataEntryKey)10, (Func<FloatItemData>)dyn.SetupDefaultFuel);
dyn.fuseTime = data?.Value ?? dyn.fuseTime;
float num = ((dyn.startingFuseTime > 0f) ? dyn.startingFuseTime : 1f);
((ItemComponent)dyn).item.SetUseRemainingPercentage(dyn.fuseTime / num);
if ((Object)(object)((MonoBehaviourPun)dyn).photonView == (Object)null || !((MonoBehaviourPun)dyn).photonView.IsMine)
{
return;
}
dyn.fuseTime -= Time.deltaTime;
if (dyn.fuseTime <= 0f)
{
if (dyn._hasExploded)
{
Debug.LogError((object)"Attempting to explode an already exploded object!");
}
Character localCharacter = Character.localCharacter;
if ((Object)(object)localCharacter != (Object)null && (Object)(object)localCharacter.data != (Object)null && (Object)(object)localCharacter.data.currentItem == (Object)(object)((ItemComponent)dyn).item)
{
float num2 = Mathf.Max(0f, UseableDynamitePlugin.Gameplay.InHandInjury);
if (num2 > 0f && localCharacter.refs != null && (Object)(object)localCharacter.refs.afflictions != (Object)null)
{
localCharacter.refs.afflictions.AddStatus((STATUSTYPE)0, num2, false, true, true, false);
}
if ((Object)(object)Player.localPlayer != (Object)null && localCharacter.refs != null && (Object)(object)localCharacter.refs.items != (Object)null)
{
Player.localPlayer.EmptySlot(localCharacter.refs.items.currentSelectedSlot, true);
}
if (localCharacter.refs != null && (Object)(object)localCharacter.refs.afflictions != (Object)null)
{
localCharacter.refs.afflictions.UpdateWeight();
}
}
CleanupSmoke(dyn);
((MonoBehaviourPun)dyn).photonView.RPC("RPC_Explode", (RpcTarget)0, Array.Empty<object>());
Debug.Log((object)"<color=Red>Exploded</color>");
PhotonNetwork.Destroy(((Component)dyn).gameObject);
((ItemComponent)dyn).item.ClearDataFromBackpack();
dyn.fuseTime = 0f;
}
if (data != null)
{
data.Value = dyn.fuseTime;
}
}
internal static void SpawnTunedExplosion(Dynamite dyn)
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)dyn == (Object)null)
{
return;
}
try
{
if (dyn.DEBUG_PauseOnExplode)
{
Debug.Break();
}
CleanupSmoke(dyn);
if ((Object)(object)dyn.explosionPrefab != (Object)null)
{
GameObject go = Object.Instantiate<GameObject>(dyn.explosionPrefab, ((Component)dyn).transform.position, ((Component)dyn).transform.rotation);
TuneExplosion(go);
}
((Component)dyn).gameObject.SetActive(false);
dyn._hasExploded = true;
}
catch (Exception ex)
{
if (_loggedExplodeError)
{
throw;
}
_loggedExplodeError = true;
UseableDynamitePlugin.Log.LogError((object)("Tuned dynamite explosion failed: " + ex));
throw;
}
}
internal static void TuneExplosion(GameObject go)
{
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)go == (Object)null)
{
return;
}
bool enabled = UseableDynamitePlugin.Enabled;
GameplayValues gameplay = UseableDynamitePlugin.Gameplay;
float num = (enabled ? Mathf.Max(0f, gameplay.RangeMultiplier) : 1f);
float num2 = ((UseableDynamitePlugin.ExplosionVisualScaleConfig != null) ? Mathf.Max(0.05f, UseableDynamitePlugin.ExplosionVisualScaleConfig.Value) : 1f);
bool mute = UseableDynamitePlugin.MuteExplosionAudioConfig != null && UseableDynamitePlugin.MuteExplosionAudioConfig.Value;
float volumeMul = ((UseableDynamitePlugin.ExplosionVolumeConfig != null) ? Mathf.Max(0f, UseableDynamitePlugin.ExplosionVolumeConfig.Value) : 1f);
float num3 = ((UseableDynamitePlugin.ExplosionSmokeLifetimeConfig != null) ? Mathf.Max(0f, UseableDynamitePlugin.ExplosionSmokeLifetimeConfig.Value) : 0f);
if (num2 != 1f)
{
Transform transform = go.transform;
transform.localScale *= num2;
}
if (enabled)
{
AOE[] componentsInChildren = go.GetComponentsInChildren<AOE>(true);
foreach (AOE val in componentsInChildren)
{
if (!((Object)(object)val == (Object)null))
{
val.range *= num;
val.knockback *= gameplay.KnockbackMultiplier;
val.additionalVerticalKnockback *= gameplay.VerticalKnockbackMultiplier;
val.fallTime *= Mathf.Max(0f, gameplay.FallTimeMultiplier);
val.statusAmount *= gameplay.DamageMultiplier;
val.cooksItems = gameplay.CooksItems;
val.canLaunchItems = gameplay.LaunchItems;
val.itemKnockbackMultiplier *= gameplay.ItemKnockbackMultiplier;
val.requireLineOfSigh = gameplay.RequireLineOfSight;
}
}
}
ExplosionEffect[] componentsInChildren2 = go.GetComponentsInChildren<ExplosionEffect>(true);
foreach (ExplosionEffect val2 in componentsInChildren2)
{
if (!((Object)(object)val2 == (Object)null))
{
if (enabled)
{
val2.explosionRadius *= num;
}
val2.baseScale *= num2;
if (UseableDynamitePlugin.ReduceExplosionOrbsConfig != null && UseableDynamitePlugin.ReduceExplosionOrbsConfig.Value)
{
val2.explosionPointCount = 0;
val2.subExplosionPointCount = 0;
}
}
}
if (num3 > 0f)
{
ScheduleSmokeDispersal(go, num3);
}
TuneExplosionAudio(go, mute, volumeMul);
}
private static void ScheduleSmokeDispersal(GameObject go, float delay)
{
if (!((Object)(object)go == (Object)null) && !(delay <= 0f) && !((Object)(object)UseableDynamitePlugin.Instance == (Object)null))
{
((MonoBehaviour)UseableDynamitePlugin.Instance).StartCoroutine(DisperseExplosionSmoke(go, delay));
}
}
private static IEnumerator DisperseExplosionSmoke(GameObject go, float delay)
{
yield return (object)new WaitForSeconds(delay);
if (!((Object)(object)go == (Object)null))
{
StopLingeringExplosionSmoke(go.GetComponentsInChildren<ParticleSystem>(true));
}
}
private static void StopLingeringExplosionSmoke(ParticleSystem[] particles)
{
if (particles == null)
{
return;
}
for (int i = 0; i < particles.Length; i++)
{
if (IsLingeringExplosionSmoke(particles[i]))
{
StopLingeringParticle(particles[i]);
}
}
}
private static void StopLingeringParticle(ParticleSystem ps)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)ps == (Object)null))
{
MainModule main = ps.main;
((MainModule)(ref main)).loop = false;
ps.Stop(true, (ParticleSystemStopBehavior)1);
}
}
private static bool IsLingeringExplosionSmoke(ParticleSystem ps)
{
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: 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)
if ((Object)(object)ps == (Object)null)
{
return false;
}
string name = (((Object)(object)((Component)ps).gameObject != (Object)null) ? ((Object)((Component)ps).gameObject).name : string.Empty);
string name2 = (((Object)(object)((Component)ps).transform != (Object)null && (Object)(object)((Component)ps).transform.parent != (Object)null) ? ((Object)((Component)ps).transform.parent).name : string.Empty);
if (LooksLikeFlashOrFire(name) || LooksLikeFlashOrFire(name2))
{
return false;
}
if (LooksLikeFuseTrail(name) || LooksLikeFuseTrail(name2))
{
return false;
}
if (LooksLikeExplosionCloud(name) || LooksLikeExplosionCloud(name2))
{
return true;
}
MainModule main = ps.main;
int result;
if (!((MainModule)(ref main)).loop)
{
MinMaxCurve startLifetime = ((MainModule)(ref main)).startLifetime;
if (!(((MinMaxCurve)(ref startLifetime)).constantMax > 2.5f))
{
startLifetime = ((MainModule)(ref main)).startLifetime;
result = ((((MinMaxCurve)(ref startLifetime)).constant > 2.5f) ? 1 : 0);
goto IL_0103;
}
}
result = 1;
goto IL_0103;
IL_0103:
return (byte)result != 0;
}
private static bool LooksLikeExplosionCloud(string name)
{
if (string.IsNullOrEmpty(name))
{
return false;
}
return name.IndexOf("smoke", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("dust", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("cloud", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("mist", StringComparison.OrdinalIgnoreCase) >= 0;
}
private static bool LooksLikeFuseTrail(string name)
{
if (string.IsNullOrEmpty(name))
{
return false;
}
return name.IndexOf("flare", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("wick", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("fuse", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("trail", StringComparison.OrdinalIgnoreCase) >= 0;
}
private static bool LooksLikeFlashOrFire(string name)
{
if (string.IsNullOrEmpty(name))
{
return false;
}
return name.IndexOf("flash", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("fire", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("flame", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("spark", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("orb", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("shock", StringComparison.OrdinalIgnoreCase) >= 0;
}
internal static void TuneExplosionAudio(GameObject go, bool mute, float volumeMul)
{
SFX_PlayOneShot[] componentsInChildren = go.GetComponentsInChildren<SFX_PlayOneShot>(true);
AudioSource[] componentsInChildren2 = go.GetComponentsInChildren<AudioSource>(true);
if (mute)
{
for (int i = 0; i < componentsInChildren.Length; i++)
{
if (!((Object)(object)componentsInChildren[i] == (Object)null))
{
componentsInChildren[i].playOnStart = false;
componentsInChildren[i].playOnEnable = false;
((Behaviour)componentsInChildren[i]).enabled = false;
if (componentsInChildren[i].handle != null)
{
SFX_Player.StopPlaying(componentsInChildren[i].handle, 0f);
}
}
}
for (int j = 0; j < componentsInChildren2.Length; j++)
{
if ((Object)(object)componentsInChildren2[j] != (Object)null)
{
componentsInChildren2[j].mute = true;
}
}
}
else
{
if (Mathf.Approximately(volumeMul, 1f))
{
return;
}
for (int k = 0; k < componentsInChildren2.Length; k++)
{
if ((Object)(object)componentsInChildren2[k] != (Object)null)
{
AudioSource obj = componentsInChildren2[k];
obj.volume *= volumeMul;
}
}
for (int l = 0; l < componentsInChildren.Length; l++)
{
WrapShotVolume(componentsInChildren[l], volumeMul);
}
}
}
private static void WrapShotVolume(SFX_PlayOneShot shot, float volumeMul)
{
if ((Object)(object)shot == (Object)null)
{
return;
}
Action before = shot.beforePlayAction;
Action after = shot.afterPlayAction;
shot.beforePlayAction = delegate
{
ScaleSfxVolumes(shot, volumeMul);
if (before != null)
{
before();
}
};
shot.afterPlayAction = delegate
{
if (after != null)
{
after();
}
RestoreSfxVolumes(shot);
};
}
private static void ScaleSfxVolumes(SFX_PlayOneShot shot, float mul)
{
if ((Object)(object)shot == (Object)null)
{
return;
}
PushSfxVolume(shot.sfx, mul);
if (shot.sfxs != null)
{
for (int i = 0; i < shot.sfxs.Length; i++)
{
PushSfxVolume(shot.sfxs[i], mul);
}
}
}
private static void PushSfxVolume(SFX_Instance sfx, float mul)
{
if (!((Object)(object)sfx == (Object)null) && sfx.settings != null)
{
if (!OrigSfxVolume.ContainsKey(sfx))
{
OrigSfxVolume[sfx] = sfx.settings.volume;
}
sfx.settings.volume = Mathf.Clamp01(OrigSfxVolume[sfx] * mul);
}
}
private static void RestoreSfxVolumes(SFX_PlayOneShot shot)
{
if ((Object)(object)shot == (Object)null)
{
return;
}
RestoreSfxVolume(shot.sfx);
if (shot.sfxs != null)
{
for (int i = 0; i < shot.sfxs.Length; i++)
{
RestoreSfxVolume(shot.sfxs[i]);
}
}
}
private static void RestoreSfxVolume(SFX_Instance sfx)
{
if (!((Object)(object)sfx == (Object)null) && sfx.settings != null && OrigSfxVolume.TryGetValue(sfx, out var value))
{
sfx.settings.volume = value;
OrigSfxVolume.Remove(sfx);
}
}
internal static void Extinguish(Item item)
{
if ((Object)(object)item == (Object)null || !IsDynamite(item) || !IsLit(item))
{
return;
}
try
{
bool resetFuseOnPocket = UseableDynamitePlugin.Gameplay.ResetFuseOnPocket;
Dynamite component = ((Component)item).GetComponent<Dynamite>();
float configuredFuseTime = GetConfiguredFuseTime(component);
ExtinguishData(item.data, resetFuseOnPocket, configuredFuseTime);
SetKeepRemaining(item.data, !resetFuseOnPocket);
if ((Object)(object)component != (Object)null)
{
if (resetFuseOnPocket)
{
component.fuseTime = configuredFuseTime;
}
if ((Object)(object)component.sparks != (Object)null)
{
((Component)component.sparks).gameObject.SetActive(false);
}
if ((Object)(object)component.sparksPhotosensitive != (Object)null)
{
((Component)component.sparksPhotosensitive).gameObject.SetActive(false);
}
CleanupSmoke(component);
}
Character val = (((Object)(object)item.holderCharacter != (Object)null) ? item.holderCharacter : Character.localCharacter);
if ((Object)(object)val != (Object)null && (Object)(object)val.player != (Object)null && val.refs != null && (Object)(object)val.refs.items != (Object)null && val.refs.items.currentSelectedSlot.IsSome)
{
ItemSlot itemSlot = val.player.GetItemSlot(val.refs.items.currentSelectedSlot.Value);
if (itemSlot != null)
{
ExtinguishData(itemSlot.data, resetFuseOnPocket, configuredFuseTime);
SetKeepRemaining(itemSlot.data, !resetFuseOnPocket);
}
}
}
catch (Exception ex)
{
if (UseableDynamitePlugin.Log != null)
{
UseableDynamitePlugin.Log.LogError((object)("Extinguish dynamite failed: " + ex));
}
}
}
internal static void ExtinguishData(ItemInstanceData data, bool resetFuse, float fullFuse)
{
if (data == null)
{
return;
}
BoolItemData val = default(BoolItemData);
if (!data.TryGetDataEntry<BoolItemData>((DataEntryKey)3, ref val) || val == null)
{
val = data.RegisterNewEntry<BoolItemData>((DataEntryKey)3);
}
val.Value = false;
if (resetFuse)
{
FloatItemData val2 = default(FloatItemData);
if (!data.TryGetDataEntry<FloatItemData>((DataEntryKey)10, ref val2) || val2 == null)
{
val2 = data.RegisterNewEntry<FloatItemData>((DataEntryKey)10);
}
val2.Value = fullFuse;
}
}
internal static void TryExtinguishOnPocket(Item item)
{
if (UseableDynamitePlugin.Enabled && UseableDynamitePlugin.Gameplay.ExtinguishOnPocket)
{
Extinguish(item);
}
}
internal static void CleanupSmoke(Dynamite dyn)
{
if ((Object)(object)dyn == (Object)null)
{
return;
}
try
{
if ((Object)(object)dyn.trackable != (Object)null && (Object)(object)dyn.trackable.currentTracker != (Object)null)
{
Object.Destroy((Object)(object)((Component)dyn.trackable.currentTracker).gameObject);
}
AudioSource[] componentsInChildren = ((Component)dyn).GetComponentsInChildren<AudioSource>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
if ((Object)(object)componentsInChildren[i] != (Object)null)
{
componentsInChildren[i].Stop();
}
}
}
catch
{
}
}
internal static void CleanupOrphanVfx()
{
try
{
TrackNetworkedObject[] array = Object.FindObjectsByType<TrackNetworkedObject>((FindObjectsSortMode)0);
foreach (TrackNetworkedObject val in array)
{
if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null) && !((Object)(object)val.trackedObject != (Object)null) && (LooksLikeDynamiteVfx(((Object)((Component)val).gameObject).name) || LooksLikeSmoke(((Object)((Component)val).gameObject).name)))
{
Object.Destroy((Object)(object)((Component)val).gameObject);
}
}
}
catch
{
}
}
internal static bool LooksLikeDynamiteVfx(string name)
{
return !string.IsNullOrEmpty(name) && name.IndexOf("Dynamite", StringComparison.OrdinalIgnoreCase) >= 0;
}
internal static bool LooksLikeSmoke(string name)
{
if (string.IsNullOrEmpty(name))
{
return false;
}
return name.IndexOf("smoke", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("flare", StringComparison.OrdinalIgnoreCase) >= 0;
}
private static void LogOwnedError(Exception ex)
{
if (!_loggedOwnedError)
{
_loggedOwnedError = true;
if (UseableDynamitePlugin.Log != null)
{
UseableDynamitePlugin.Log.LogError((object)("Marking player dynamite failed: " + ex));
}
}
}
}
[HarmonyPatch(typeof(Dynamite), "Awake")]
internal static class Patch_Dynamite_Awake
{
private static void Prefix(Dynamite __instance)
{
DynamiteUtil.RememberPrefabRadius(__instance, assumeAlreadySquared: false);
}
private static void Postfix(Dynamite __instance)
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Invalid comparison between Unknown and I4
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Invalid comparison between Unknown and I4
try
{
if (UseableDynamitePlugin.Enabled)
{
DynamiteUtil.ApplyStickSettings(__instance);
Item item = ((ItemComponent)__instance).item;
if ((Object)(object)item != (Object)null && ((int)item.itemState == 1 || (int)item.itemState == 2))
{
DynamiteUtil.MarkPlayerOwned(item);
}
}
}
catch (Exception ex)
{
if (!DynamiteUtil.LoggedAwakeError)
{
DynamiteUtil.LoggedAwakeError = true;
UseableDynamitePlugin.Log.LogError((object)("Dynamite.Awake postfix failed: " + ex));
}
}
}
}
[HarmonyPatch(typeof(Dynamite), "OnInstanceDataSet")]
internal static class Patch_Dynamite_OnInstanceDataSet
{
private static void Postfix(Dynamite __instance)
{
try
{
if (UseableDynamitePlugin.Enabled)
{
DynamiteUtil.ApplyStickSettings(__instance);
}
}
catch (Exception ex)
{
UseableDynamitePlugin.Log.LogError((object)("Dynamite.OnInstanceDataSet postfix failed: " + ex));
}
}
}
[HarmonyPatch(typeof(Dynamite), "Update")]
internal static class Patch_Dynamite_Update
{
private static bool Prefix(Dynamite __instance)
{
try
{
if (!UseableDynamitePlugin.Enabled)
{
return true;
}
DynamiteUtil.TickDynamite(__instance);
return false;
}
catch (Exception ex)
{
if (!DynamiteUtil.LoggedTickError)
{
DynamiteUtil.LoggedTickError = true;
UseableDynamitePlugin.Log.LogError((object)("Dynamite.Update prefix failed: " + ex));
}
return true;
}
}
}
[HarmonyPatch(typeof(Dynamite), "TestLightWick")]
internal static class Patch_Dynamite_TestLightWick
{
private static bool Prefix(Dynamite __instance)
{
try
{
if (!UseableDynamitePlugin.Enabled)
{
return true;
}
if (!UseableDynamitePlugin.Gameplay.HazardAutoLight)
{
return false;
}
if ((Object)(object)Character.localCharacter == (Object)null)
{
return false;
}
DynamiteUtil.RefreshWickPosition(__instance);
return DynamiteUtil.IsWorldHazard(__instance);
}
catch (Exception ex)
{
if (!DynamiteUtil.LoggedWickError)
{
DynamiteUtil.LoggedWickError = true;
UseableDynamitePlugin.Log.LogError((object)("Dynamite.TestLightWick prefix failed: " + ex));
}
return true;
}
}
}
[HarmonyPatch(typeof(Dynamite), "SetFlareLitRPC")]
internal static class Patch_Dynamite_SetFlareLitRPC
{
private static void Prefix(Dynamite __instance)
{
try
{
if (UseableDynamitePlugin.Enabled && !((Object)(object)__instance == (Object)null))
{
bool flag = (Object)(object)((ItemComponent)__instance).item != (Object)null && DynamiteUtil.HasKeepRemaining(((ItemComponent)__instance).item.data);
DynamiteUtil.ApplyConfiguredFuse(__instance, !flag);
}
}
catch (Exception ex)
{
if (UseableDynamitePlugin.Log != null)
{
UseableDynamitePlugin.Log.LogError((object)("SetFlareLitRPC fuse apply failed: " + ex));
}
}
}
}
[HarmonyPatch(typeof(Dynamite), "EnableFlareVisuals")]
internal static class Patch_Dynamite_EnableFlareVisuals
{
private static bool Prefix()
{
return UseableDynamitePlugin.DisableFuseSmokeConfig == null || !UseableDynamitePlugin.DisableFuseSmokeConfig.Value;
}
}
[HarmonyPatch(typeof(Dynamite), "RPC_Explode")]
internal static class Patch_Dynamite_RPC_Explode
{
private static bool Prefix(Dynamite __instance)
{
try
{
DynamiteUtil.SpawnTunedExplosion(__instance);
return false;
}
catch
{
return true;
}
}
}
[HarmonyPatch(typeof(Item), "FinishCastPrimary")]
internal static class Patch_Item_FinishCastPrimary
{
private static void Postfix(Item __instance)
{
DynamiteUtil.TryLightFromPrimary(__instance);
}
}
[HarmonyPatch(typeof(CharacterItems), "DropItemRpc")]
internal static class Patch_CharacterItems_DropItemRpc
{
private static void Prefix(CharacterItems __instance, float throwCharge, ItemInstanceData itemInstanceData)
{
try
{
if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.character == (Object)null) && !((Object)(object)__instance.character.data == (Object)null))
{
DynamiteUtil.StampLightOnThrow(__instance.character.data.currentItem, itemInstanceData, throwCharge);
}
}
catch (Exception ex)
{
if (UseableDynamitePlugin.Log != null)
{
UseableDynamitePlugin.Log.LogError((object)("DropItemRpc dynamite throw-light failed: " + ex));
}
}
}
}
[HarmonyPatch(typeof(Item), "CanUsePrimary")]
internal static class Patch_Item_CanUsePrimary
{
private static void Postfix(Item __instance, ref bool __result)
{
try
{
if (UseableDynamitePlugin.Enabled && DynamiteUtil.IsDynamite(__instance) && DynamiteUtil.IsLit(__instance))
{
__result = false;
}
}
catch
{
}
}
}
[HarmonyPatch(typeof(Item), "SetState")]
internal static class Patch_Item_SetState
{
private static void Postfix(Item __instance, ItemState setState)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Invalid comparison between Unknown and I4
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Invalid comparison between Unknown and I4
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Invalid comparison between Unknown and I4
try
{
if (UseableDynamitePlugin.Enabled && DynamiteUtil.IsDynamite(__instance))
{
if ((int)setState == 1 || (int)setState == 2)
{
DynamiteUtil.MarkPlayerOwned(__instance);
}
if ((int)setState == 2)
{
DynamiteUtil.TryExtinguishOnPocket(__instance);
}
}
}
catch (Exception ex)
{
UseableDynamitePlugin.Log.LogError((object)("Item.SetState dynamite postfix failed: " + ex));
}
}
}
[HarmonyPatch(typeof(Item), "OnStash")]
internal static class Patch_Item_OnStash
{
private static void Prefix(Item __instance)
{
try
{
DynamiteUtil.TryExtinguishOnPocket(__instance);
}
catch (Exception ex)
{
UseableDynamitePlugin.Log.LogError((object)("Item.OnStash dynamite prefix failed: " + ex));
}
}
}
[HarmonyPatch(typeof(Player), "AddItem")]
internal static class Patch_Player_AddItem
{
private static void Postfix(ushort itemID, ItemSlot slot, bool __result)
{
try
{
if (UseableDynamitePlugin.Enabled && __result && slot != null && !((Object)(object)slot.prefab == (Object)null) && !((Object)(object)((Component)slot.prefab).GetComponent<Dynamite>() == (Object)null))
{
DynamiteUtil.MarkPlayerOwned(slot.data);
}
}
catch (Exception ex)
{
if (UseableDynamitePlugin.Log != null)
{
UseableDynamitePlugin.Log.LogError((object)("Player.AddItem dynamite postfix failed: " + ex));
}
}
}
}
[HarmonyPatch(typeof(Spawner), "SpawnItems")]
internal static class Patch_Spawner_SpawnItems
{
private static void Postfix(Spawner __instance, List<PhotonView> __result)
{
try
{
if (UseableDynamitePlugin.Enabled && __instance is Luggage)
{
DynamiteUtil.MarkSpawnedDynamite(__result);
}
}
catch (Exception ex)
{
UseableDynamitePlugin.Log.LogError((object)("Luggage dynamite spawn postfix failed: " + ex));
}
}
}
[HarmonyPatch(typeof(SpawnedItemTracker), "SpawnAndTrackFromItemHistory")]
internal static class Patch_SpawnedItemTracker_History
{
private static void Postfix(SpawnedItemTracker __instance, List<PhotonView> __result)
{
try
{
if (UseableDynamitePlugin.Enabled && !((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponent<Luggage>() == (Object)null))
{
DynamiteUtil.MarkSpawnedDynamite(__result);
}
}
catch (Exception ex)
{
UseableDynamitePlugin.Log.LogError((object)("Luggage dynamite history postfix failed: " + ex));
}
}
}
internal sealed class DynamiteNet : MonoBehaviourPunCallbacks, IOnEventCallback
{
private const byte SubConfig = 1;
private const byte SubConfigRequest = 2;
private const float HostSyncTimeoutSeconds = 12f;
private const float HostSyncRetrySeconds = 2f;
internal static bool HostModConfirmed;
private Coroutine _debounce;
private Coroutine _hostSyncWatch;
private bool _syncingFromNet;
internal static DynamiteNet Instance { get; private set; }
internal static bool UseHostGameplay
{
get
{
try
{
return PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient && HostModConfirmed;
}
catch
{
return false;
}
}
}
internal static void Ensure()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Expected O, but got Unknown
if ((Object)(object)Instance != (Object)null)
{
return;
}
GameObject val = new GameObject("UseableDynamite_Net");
Object.DontDestroyOnLoad((Object)(object)val);
Instance = val.AddComponent<DynamiteNet>();
try
{
if (PhotonNetwork.InRoom)
{
Instance.HandleJoinedRoom();
}
}
catch
{
}
}
public override void OnEnable()
{
((MonoBehaviourPunCallbacks)this).OnEnable();
PhotonNetwork.AddCallbackTarget((object)this);
}
public override void OnDisable()
{
PhotonNetwork.RemoveCallbackTarget((object)this);
((MonoBehaviourPunCallbacks)this).OnDisable();
}
public override void OnJoinedRoom()
{
HandleJoinedRoom();
}
public override void OnLeftRoom()
{
StopHostSyncWatch();
HostModConfirmed = false;
UseableDynamitePlugin.ClearHostGameplay();
DynamiteUtil.RefreshAllSticks();
}
public override void OnMasterClientSwitched(Player newMasterClient)
{
if (PhotonNetwork.IsMasterClient)
{
HostModConfirmed = true;
UseableDynamitePlugin.ClearHostGameplay();
DynamiteUtil.RefreshAllSticks();
BroadcastNow();
StopHostSyncWatch();
}
else
{
HostModConfirmed = false;
UseableDynamitePlugin.ClearHostGameplay();
DynamiteUtil.RefreshAllSticks();
RequestHostSync();
RestartHostSyncWatch();
}
}
public override void OnPlayerEnteredRoom(Player newPlayer)
{
if (PhotonNetwork.IsMasterClient)
{
((MonoBehaviour)this).StartCoroutine(BroadcastAfterDelay(0.5f));
}
}
public void OnEvent(EventData photonEvent)
{
if (photonEvent == null || photonEvent.Code != 167 || !(photonEvent.CustomData is object[] array) || array.Length < 3 || !(array[0] is string text) || text != "tony4twentys.Useable_Dynamite" || ToInt(array[1]) != 1)
{
return;
}
byte b = ToByte(array[2]);
if (b == 2 && PhotonNetwork.IsMasterClient)
{
BroadcastNow();
}
else
{
if (b != 1 || PhotonNetwork.IsMasterClient)
{
return;
}
try
{
_syncingFromNet = true;
UseableDynamitePlugin.ApplyHostGameplay(array);
StopHostSyncWatch();
HostModConfirmed = true;
DynamiteUtil.RefreshAllSticks();
if (UseableDynamitePlugin.Log != null)
{
UseableDynamitePlugin.Log.LogInfo((object)"Host dynamite config applied.");
}
}
catch (Exception ex)
{
if (UseableDynamitePlugin.Log != null)
{
UseableDynamitePlugin.Log.LogError((object)("Host config sync failed: " + ex.Message));
}
}
finally
{
_syncingFromNet = false;
}
}
}
internal static void OnLocalSettingChanged()
{
if (!((Object)(object)Instance != (Object)null) || !Instance._syncingFromNet)
{
DynamiteUtil.RefreshAllSticks();
ScheduleBroadcast();
}
}
private void HandleJoinedRoom()
{
if (PhotonNetwork.IsMasterClient)
{
HostModConfirmed = true;
UseableDynamitePlugin.ClearHostGameplay();
DynamiteUtil.RefreshAllSticks();
BroadcastNow();
StopHostSyncWatch();
}
else
{
HostModConfirmed = false;
UseableDynamitePlugin.ClearHostGameplay();
DynamiteUtil.RefreshAllSticks();
RequestHostSync();
RestartHostSyncWatch();
}
}
private static void RequestHostSync()
{
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Expected O, but got Unknown
if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
{
PhotonNetwork.RaiseEvent((byte)167, (object)new object[3]
{
"tony4twentys.Useable_Dynamite",
1,
(byte)2
}, new RaiseEventOptions
{
Receivers = (ReceiverGroup)2
}, SendOptions.SendReliable);
}
}
private static void ScheduleBroadcast()
{
if (!((Object)(object)Instance == (Object)null) && PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient)
{
if (Instance._debounce != null)
{
((MonoBehaviour)Instance).StopCoroutine(Instance._debounce);
}
Instance._debounce = ((MonoBehaviour)Instance).StartCoroutine(Instance.DebounceBroadcast());
}
}
private void RestartHostSyncWatch()
{
StopHostSyncWatch();
if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient)
{
_hostSyncWatch = ((MonoBehaviour)this).StartCoroutine(WatchForHostSync());
}
}
private void StopHostSyncWatch()
{
if (_hostSyncWatch != null)
{
((MonoBehaviour)this).StopCoroutine(_hostSyncWatch);
_hostSyncWatch = null;
}
}
private IEnumerator WatchForHostSync()
{
float elapsed = 0f;
float nextRetry = 2f;
while (elapsed < 12f)
{
if (!PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient || HostModConfirmed)
{
yield break;
}
elapsed += Time.unscaledDeltaTime;
if (elapsed >= nextRetry)
{
RequestHostSync();
nextRetry += 2f;
}
yield return null;
}
if (PhotonNetwork.InRoom && !PhotonNetwork.IsMasterClient && !HostModConfirmed && UseableDynamitePlugin.Log != null)
{
UseableDynamitePlugin.Log.LogWarning((object)"Host does not appear to have Useable Dynamite — gameplay off, local VFX still on.");
}
_hostSyncWatch = null;
}
private IEnumerator DebounceBroadcast()
{
yield return (object)new WaitForSeconds(0.25f);
BroadcastNow();
_debounce = null;
}
private IEnumerator BroadcastAfterDelay(float seconds)
{
yield return (object)new WaitForSeconds(seconds);
BroadcastNow();
}
private static void BroadcastNow()
{
//IL_0023: 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)
//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)
//IL_0039: Expected O, but got Unknown
if (PhotonNetwork.InRoom && PhotonNetwork.IsMasterClient)
{
PhotonNetwork.RaiseEvent((byte)167, (object)UseableDynamitePlugin.BuildGameplayPayload(), new RaiseEventOptions
{
Receivers = (ReceiverGroup)0
}, SendOptions.SendReliable);
}
}
private static int ToInt(object value)
{
return Convert.ToInt32(value);
}
private static byte ToByte(object value)
{
return Convert.ToByte(value);
}
}
namespace System.Runtime.CompilerServices;
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}