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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.SceneManagement;
using Zorro.Core;
using Zorro.Core.Serizalization;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("Reloadable_Hand_Cannons")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Reloadable_Hand_Cannons")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("0f5e42e3-bb26-4c24-9f5b-39f5ae0867ad")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Hand_Cannon;
public enum HandCannonAmmoType
{
Empty,
Piton,
NormalRope,
AntiRope
}
[BepInPlugin("tony4twentys.Reloadable_Hand_Cannons", "Reloadable_Hand_Cannons", "1.0.0")]
public class HandCannonPlugin : BaseUnityPlugin
{
public const string PluginGuid = "tony4twentys.Reloadable_Hand_Cannons";
public const string PluginName = "Reloadable_Hand_Cannons";
public const string PluginVersion = "1.0.0";
internal static ConfigEntry<float> PitonSpawnChanceConfig;
internal static ConfigEntry<bool> AllowBackpackReloadConfig;
internal static ConfigEntry<KeyCode> ReloadKeyConfig;
private Harmony _harmony;
public static ManualLogSource Log { get; private set; }
internal static HandCannonPlugin Instance { get; private set; }
private void Awake()
{
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Expected O, but got Unknown
//IL_0107: Unknown result type (might be due to invalid IL or missing references)
Instance = this;
Log = ((BaseUnityPlugin)this).Logger;
PitonSpawnChanceConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "Piton Spawn Chance", 0.5f, "Chance (0.0 to 1.0) for a Hand Cannon (item 63) to spawn loaded with a piton instead of normal rope.");
AllowBackpackReloadConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Reload", "Allow Backpack Reload", true, "When true, pressing the reload key can consume ammo from a worn backpack.");
ReloadKeyConfig = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Reload", "Reload Key", (KeyCode)114, "Press this key while holding an empty Hand Cannon to reload from inventory.");
WarnIfConflictingModsLoaded();
_harmony = new Harmony("tony4twentys.Reloadable_Hand_Cannons");
try
{
_harmony.PatchAll();
}
catch (Exception ex)
{
((BaseUnityPlugin)this).Logger.LogError((object)("Reloadable Hand Cannons harmony patching failed: " + ex.Message));
}
HandCannonReloadPickerUI.EnsureCreated();
HandCannonNetworkSync.EnsureProxy();
SceneManager.sceneLoaded += OnSceneLoaded;
((BaseUnityPlugin)this).Logger.LogInfo((object)($"Reloadable Hand Cannons loaded. Piton spawn chance: {PitonSpawnChanceConfig.Value:P0}. " + string.Format("Reload key: {0}. Backpack reload: {1}.", ReloadKeyConfig.Value, AllowBackpackReloadConfig.Value ? "enabled" : "disabled")));
}
private void Update()
{
//IL_0058: 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)
if (HandCannonReloadPickerUI.IsOpen)
{
if (Input.GetKeyDown((KeyCode)27) || Input.GetKeyDown(ReloadKeyConfig.Value))
{
Log.LogInfo((object)"[Reload] picker cancelled.");
HandCannonReloadPickerUI.Close();
}
else
{
HandCannonReloadPickerUI.TryKeyboardSelect();
}
}
else
{
if (!Input.GetKeyDown(ReloadKeyConfig.Value))
{
return;
}
Character localCharacter = Character.localCharacter;
object obj;
if (localCharacter == null)
{
obj = null;
}
else
{
CharacterData data = localCharacter.data;
obj = ((data != null) ? data.currentItem : null);
}
if (!((Object)obj == (Object)null))
{
Item currentItem = localCharacter.data.currentItem;
RopeShooter component = ((Component)currentItem).GetComponent<RopeShooter>();
if (HandCannonHelper.IsHandCannon(currentItem) && !((Object)(object)component == (Object)null) && HandCannonHelper.IsEmptyForReload(currentItem, component) && !currentItem.isUsingPrimary)
{
HandCannonReloadExecutor.TryManualReload(localCharacter);
}
}
}
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
HandCannonReloadPickerUI.ForceClose();
}
private void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
Instance = null;
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
HandCannonReloadPickerUI.DestroyInstance();
Log = null;
}
private static void WarnIfConflictingModsLoaded()
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
string name = assembly.GetName().Name;
if (string.Equals(name, "Piton Launcher", StringComparison.Ordinal) || string.Equals(name, "Reloadable Rope Canons", StringComparison.Ordinal) || string.Equals(name, "Hand Cannon", StringComparison.Ordinal))
{
Log.LogWarning((object)("Detected '" + name + "' — disable it to avoid Harmony conflicts with Reloadable Hand Cannons."));
}
}
}
}
internal static class HandCannonDataEntryKey
{
public static readonly DataEntryKey LoadedAmmoType = (DataEntryKey)74;
}
internal static class GameItemIds
{
public const ushort RopeCannonItemId = 63;
public const ushort AntiRopeCannonItemId = 64;
public const ushort AntiRopeSpoolItemId = 1;
public const ushort RopeSpoolItemId = 65;
public const ushort ClimbingSpikeItemId = 18;
}
internal static class HandCannonHelper
{
public static Item GetItem(RopeShooter shooter)
{
if ((Object)(object)shooter == (Object)null)
{
return null;
}
return ((ItemComponent)shooter).item ?? ((Component)shooter).GetComponent<Item>();
}
public static bool IsHandCannon(Item item)
{
if ((Object)(object)item == (Object)null || (Object)(object)((Component)item).GetComponent<RopeShooter>() == (Object)null)
{
return false;
}
return item.itemID == 63 || item.itemID == 64;
}
public static bool CanTagItems()
{
return !PhotonNetwork.InRoom || PhotonNetwork.IsMasterClient;
}
public static Item GetActionItem(ItemActionBase action)
{
return (action != null) ? ((Component)action).GetComponent<Item>() : null;
}
public static bool IsEmptyForReload(Item item, RopeShooter shooter)
{
if ((Object)(object)item == (Object)null || (Object)(object)shooter == (Object)null)
{
return false;
}
if (!shooter.HasAmmo)
{
return true;
}
OptionableIntItemData data = item.GetData<OptionableIntItemData>((DataEntryKey)2);
if (data != null && data.HasData && data.Value <= 0)
{
return true;
}
return false;
}
}
internal static class HandCannonFireHelper
{
public static void ConsumeFiredShot(RopeShooter shooter, Item item)
{
//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)shooter == (Object)null || (Object)(object)item == (Object)null || !HandCannonHelper.IsHandCannon(item) || !shooter.HasAmmo)
{
return;
}
IntItemData data = ((ItemComponent)shooter).GetData<IntItemData>((DataEntryKey)12, (Func<IntItemData>)(() => ItemDataHelper.CreateIntItemData(0)));
data.Value = 0;
OptionableIntItemData data2 = item.GetData<OptionableIntItemData>((DataEntryKey)2);
if (data2 != null)
{
data2.Value = 0;
}
item.SetUseRemainingPercentage(0f);
shooter.cantReFire = false;
((ItemComponent)shooter).OnInstanceDataSet();
Optionable<byte> valueOrDefault = (item.holderCharacter?.refs?.items?.currentSelectedSlot).GetValueOrDefault();
object obj;
if (valueOrDefault.IsSome)
{
Character holderCharacter = item.holderCharacter;
if ((Object)(object)((holderCharacter != null) ? holderCharacter.player : null) != (Object)null)
{
obj = item.holderCharacter.player.GetItemSlot(valueOrDefault.Value);
goto IL_0135;
}
}
obj = null;
goto IL_0135;
IL_0135:
ItemSlot slot = (ItemSlot)obj;
HandCannonAmmoHelper.SetLoadedAmmo(item, slot, HandCannonAmmoType.Empty);
HandCannonStateSync.Sync(item, shooter);
HandCannonNetworkSync.PushAmmoState(item, slot, item.holderCharacter);
}
}
internal static class HandCannonStateSync
{
public static void Sync(Item item, RopeShooter shooter)
{
HandCannonAntigravSync.Sync(item, shooter);
HandCannonVisualSync.Sync(item, shooter);
}
}
internal static class HandCannonNetworkSync
{
public const byte EventCode = 191;
public const int ProtocolVersion = 100;
private const byte SubAmmoSync = 0;
private static HandCannonNetProxy _proxy;
public static void EnsureProxy()
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
if (!((Object)(object)_proxy != (Object)null))
{
GameObject val = new GameObject("ReloadableHandCannonsNet");
Object.DontDestroyOnLoad((Object)(object)val);
_proxy = val.AddComponent<HandCannonNetProxy>();
}
}
public static void PushAmmoState(Item item, ItemSlot slot, Character holder)
{
if ((Object)(object)item != (Object)null && slot != null)
{
HandCannonAmmoHelper.CopyAmmoToSlot(item, slot);
}
PushItemInstanceData(item);
BroadcastAmmo(item);
SyncHolderInventory(holder);
}
public static void PushItemInstanceData(Item item)
{
if (item?.data == null || !PhotonNetwork.InRoom)
{
return;
}
PhotonView val = ((MonoBehaviourPun)item).photonView ?? item.view;
if ((Object)(object)val == (Object)null || (!val.IsMine && !PhotonNetwork.IsMasterClient))
{
return;
}
try
{
val.RPC("SetItemInstanceDataRPC", (RpcTarget)1, new object[1] { item.data });
}
catch (Exception ex)
{
ManualLogSource log = HandCannonPlugin.Log;
if (log != null)
{
log.LogWarning((object)("[Sync] SetItemInstanceDataRPC failed: " + ex.Message));
}
}
BroadcastAmmo(item);
}
public static void BroadcastAmmo(Item item)
{
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: 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_00b0: Expected O, but got Unknown
if ((Object)(object)item == (Object)null || !PhotonNetwork.InRoom)
{
return;
}
PhotonView val = ((MonoBehaviourPun)item).photonView ?? item.view;
if ((Object)(object)val == (Object)null || (!val.IsMine && !PhotonNetwork.IsMasterClient))
{
return;
}
HandCannonAmmoType loadedAmmo = HandCannonAmmoHelper.GetLoadedAmmo(item);
try
{
PhotonNetwork.RaiseEvent((byte)191, (object)new object[4]
{
100,
(byte)0,
val.ViewID,
(int)loadedAmmo
}, new RaiseEventOptions
{
Receivers = (ReceiverGroup)0
}, SendOptions.SendReliable);
}
catch (Exception ex)
{
ManualLogSource log = HandCannonPlugin.Log;
if (log != null)
{
log.LogWarning((object)("[Sync] RaiseEvent ammo failed: " + ex.Message));
}
}
}
public static void ApplyRemoteAmmo(int itemViewId, HandCannonAmmoType ammo)
{
PhotonView val = PhotonView.Find(itemViewId);
if (!((Object)(object)val == (Object)null))
{
Item component = ((Component)val).GetComponent<Item>();
if (HandCannonHelper.IsHandCannon(component))
{
HandCannonAmmoHelper.SetLoadedAmmo(component, null, ammo);
RopeShooter component2 = ((Component)component).GetComponent<RopeShooter>();
HandCannonStateSync.Sync(component, component2);
}
}
}
public static void BroadcastAllHandCannons()
{
//IL_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
if (!PhotonNetwork.IsMasterClient)
{
return;
}
Item[] array = Resources.FindObjectsOfTypeAll<Item>();
foreach (Item val in array)
{
if (HandCannonHelper.IsHandCannon(val) && !((Object)(object)((Component)val).gameObject == (Object)null))
{
Scene scene = ((Component)val).gameObject.scene;
if (((Scene)(ref scene)).IsValid())
{
BroadcastAmmo(val);
PushItemInstanceData(val);
}
}
}
}
public static void SyncHolderInventory(Character character)
{
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)((character != null) ? character.player : null) == (Object)null || !PhotonNetwork.InRoom || !character.IsLocal)
{
return;
}
PhotonView component = ((Component)character.player).GetComponent<PhotonView>();
if ((Object)(object)component == (Object)null)
{
return;
}
try
{
InventorySyncData val = default(InventorySyncData);
((InventorySyncData)(ref val))..ctor(character.player.itemSlots, character.player.backpackSlot, character.player.tempFullSlot);
component.RPC("SyncInventoryRPC", (RpcTarget)1, new object[2]
{
IBinarySerializable.ToManagedArray<InventorySyncData>(val),
false
});
}
catch (Exception ex)
{
ManualLogSource log = HandCannonPlugin.Log;
if (log != null)
{
log.LogWarning((object)("[Sync] SyncInventoryRPC failed: " + ex.Message));
}
}
}
public static void PreserveAmmoOnStash(Item item)
{
//IL_0060: 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_0073: Unknown result type (might be due to invalid IL or missing references)
if (!HandCannonHelper.IsHandCannon(item))
{
return;
}
Character holderCharacter = item.holderCharacter;
if ((Object)(object)((holderCharacter != null) ? holderCharacter.player : null) == (Object)null)
{
return;
}
Character holderCharacter2 = item.holderCharacter;
Optionable<byte> valueOrDefault = (holderCharacter2.refs?.items?.currentSelectedSlot).GetValueOrDefault();
if (valueOrDefault.IsSome)
{
ItemSlot itemSlot = holderCharacter2.player.GetItemSlot(valueOrDefault.Value);
if (itemSlot != null && !itemSlot.IsEmpty())
{
HandCannonAmmoHelper.CopyAmmoToSlot(item, itemSlot);
SyncHolderInventory(holderCharacter2);
}
}
}
public static void ScheduleSpawnResync(Item item)
{
EnsureProxy();
if ((Object)(object)_proxy != (Object)null && (Object)(object)item != (Object)null)
{
((MonoBehaviour)_proxy).StartCoroutine(SpawnResyncRoutine(item));
}
}
private static IEnumerator SpawnResyncRoutine(Item item)
{
yield return null;
if ((Object)(object)item != (Object)null)
{
PushItemInstanceData(item);
}
yield return (object)new WaitForSeconds(0.35f);
if ((Object)(object)item != (Object)null)
{
PushItemInstanceData(item);
}
}
internal static void HandleEvent(EventData eventData)
{
if (eventData != null && eventData.Code == 191 && eventData.CustomData is object[] array && array.Length >= 4 && Convert.ToInt32(array[0]) == 100 && Convert.ToByte(array[1]) == 0)
{
int itemViewId = Convert.ToInt32(array[2]);
HandCannonAmmoType ammo = (HandCannonAmmoType)Convert.ToInt32(array[3]);
ApplyRemoteAmmo(itemViewId, ammo);
}
}
}
internal sealed class HandCannonNetProxy : MonoBehaviourPunCallbacks, IOnEventCallback
{
public override void OnEnable()
{
((MonoBehaviourPunCallbacks)this).OnEnable();
PhotonNetwork.AddCallbackTarget((object)this);
}
public override void OnDisable()
{
PhotonNetwork.RemoveCallbackTarget((object)this);
((MonoBehaviourPunCallbacks)this).OnDisable();
}
public void OnPlayerEnteredRoom(Player _)
{
if (PhotonNetwork.IsMasterClient)
{
((MonoBehaviour)this).StartCoroutine(BroadcastAfterJoin());
}
}
public void OnEvent(EventData photonEvent)
{
HandCannonNetworkSync.HandleEvent(photonEvent);
}
private IEnumerator BroadcastAfterJoin()
{
yield return (object)new WaitForSeconds(0.5f);
HandCannonNetworkSync.BroadcastAllHandCannons();
}
}
internal static class HandCannonAmmoHelper
{
public static HandCannonAmmoType GetLoadedAmmo(Item item)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)item == (Object)null)
{
return HandCannonAmmoType.Empty;
}
if (item.HasData(HandCannonDataEntryKey.LoadedAmmoType))
{
return (HandCannonAmmoType)item.GetData<IntItemData>(HandCannonDataEntryKey.LoadedAmmoType).Value;
}
Character holderCharacter = item.holderCharacter;
Optionable<byte> valueOrDefault = (holderCharacter?.refs?.items?.currentSelectedSlot).GetValueOrDefault();
if (valueOrDefault.IsSome && (Object)(object)((holderCharacter != null) ? holderCharacter.player : null) != (Object)null)
{
ItemSlot itemSlot = holderCharacter.player.GetItemSlot(valueOrDefault.Value);
if (itemSlot == null || itemSlot.IsEmpty() || itemSlot.data == null)
{
return HandCannonAmmoType.Empty;
}
return GetLoadedAmmo(itemSlot.data);
}
return HandCannonAmmoType.Empty;
}
public static HandCannonAmmoType GetLoadedAmmo(ItemInstanceData data)
{
//IL_0005: 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)
if (data == null || !data.HasData(HandCannonDataEntryKey.LoadedAmmoType))
{
return HandCannonAmmoType.Empty;
}
IntItemData val = default(IntItemData);
if (data.TryGetDataEntry<IntItemData>(HandCannonDataEntryKey.LoadedAmmoType, ref val))
{
return (HandCannonAmmoType)val.Value;
}
return HandCannonAmmoType.Empty;
}
public static void SetLoadedAmmo(Item item, ItemSlot slot, HandCannonAmmoType ammoType)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Expected O, but got Unknown
if ((Object)(object)item != (Object)null)
{
IntItemData data = item.GetData<IntItemData>(HandCannonDataEntryKey.LoadedAmmoType);
data.Value = (int)ammoType;
}
if (slot != null)
{
if (slot.data == null)
{
slot.data = new ItemInstanceData(Guid.NewGuid());
}
ItemDataHelper.SetIntEntry(slot.data, HandCannonDataEntryKey.LoadedAmmoType, (int)ammoType);
}
}
public static void CopyAmmoToSlot(Item item, ItemSlot slot)
{
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)item == (Object)null) && slot != null)
{
HandCannonAmmoType loadedAmmo = GetLoadedAmmo(item);
if (slot.data == null)
{
slot.data = (ItemInstanceData)(((object)item.data) ?? ((object)new ItemInstanceData(Guid.NewGuid())));
}
ItemDataHelper.SetIntEntry(slot.data, HandCannonDataEntryKey.LoadedAmmoType, (int)loadedAmmo);
}
}
public static string GetAmmoLabel(HandCannonAmmoType ammoType)
{
return ammoType switch
{
HandCannonAmmoType.Piton => "piton",
HandCannonAmmoType.NormalRope => "rope",
HandCannonAmmoType.AntiRope => "anti-grav rope",
_ => "empty",
};
}
public static string GetDisplayName(HandCannonAmmoType ammoType)
{
return ammoType switch
{
HandCannonAmmoType.Piton => "Piton Cannon",
HandCannonAmmoType.NormalRope => "Rope Cannon",
HandCannonAmmoType.AntiRope => "Anti-Rope Cannon",
_ => "Hand Cannon",
};
}
public static HandCannonAmmoType ResolveLoadedAmmoForName(Item item, ItemInstanceData data)
{
HandCannonAmmoType loadedAmmo = GetLoadedAmmo(data);
if (loadedAmmo != HandCannonAmmoType.Empty)
{
return loadedAmmo;
}
return GetLoadedAmmo(item);
}
}
internal static class ItemDataHelper
{
public static void SetIntEntry(ItemInstanceData data, DataEntryKey key, int value)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
IntItemData val = default(IntItemData);
if (data.TryGetDataEntry<IntItemData>(key, ref val))
{
val.Value = value;
return;
}
IntItemData val2 = new IntItemData();
((DataEntryValue)val2).Init();
val2.Value = value;
data.RegisterEntry<IntItemData>(key, val2);
}
public static void SetOptionableIntEntry(ItemInstanceData data, DataEntryKey key, int value)
{
//IL_0002: 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_0025: Expected O, but got Unknown
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
OptionableIntItemData val = default(OptionableIntItemData);
if (data.TryGetDataEntry<OptionableIntItemData>(key, ref val))
{
val.HasData = true;
val.Value = value;
return;
}
OptionableIntItemData val2 = new OptionableIntItemData();
((DataEntryValue)val2).Init();
val2.HasData = true;
val2.Value = value;
data.RegisterEntry<OptionableIntItemData>(key, val2);
}
public static void SetFloatEntry(ItemInstanceData data, DataEntryKey key, float value)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
FloatItemData val = default(FloatItemData);
if (data.TryGetDataEntry<FloatItemData>(key, ref val))
{
val.Value = value;
return;
}
FloatItemData val2 = new FloatItemData();
((DataEntryValue)val2).Init();
val2.Value = value;
data.RegisterEntry<FloatItemData>(key, val2);
}
public static IntItemData CreateIntItemData(int value)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Expected O, but got Unknown
IntItemData val = new IntItemData();
((DataEntryValue)val).Init();
val.Value = value;
return val;
}
}
internal static class HandCannonAntigravSync
{
private static float? _cachedIntensity;
public static void Sync(Item item, RopeShooter shooter)
{
if ((Object)(object)item == (Object)null)
{
return;
}
bool flag = (Object)(object)shooter != (Object)null && shooter.HasAmmo && HandCannonAmmoHelper.GetLoadedAmmo(item) == HandCannonAmmoType.AntiRope;
Antigrav val = ((Component)item).GetComponent<Antigrav>();
if (flag)
{
if ((Object)(object)val == (Object)null)
{
val = ((Component)item).gameObject.AddComponent<Antigrav>();
}
val.intensity = GetAntigravIntensity();
}
else if ((Object)(object)val != (Object)null)
{
Object.Destroy((Object)(object)val);
}
}
private static float GetAntigravIntensity()
{
if (_cachedIntensity.HasValue)
{
return _cachedIntensity.Value;
}
Item[] array = Resources.FindObjectsOfTypeAll<Item>();
Item[] array2 = array;
foreach (Item val in array2)
{
if (!((Object)(object)val == (Object)null) && val.itemID == 64)
{
Antigrav component = ((Component)val).GetComponent<Antigrav>();
if ((Object)(object)component != (Object)null)
{
_cachedIntensity = component.intensity;
return _cachedIntensity.Value;
}
}
}
_cachedIntensity = 1f;
return _cachedIntensity.Value;
}
}
internal static class HandCannonVisualSync
{
private const string PitonVisualObjectName = "HandCannonPitonVisual";
private const string SwappedRopeVisualObjectName = "HandCannonSwappedRopeVisual";
private const string PitonClimbingSpikeChildName = "ClimbingSpike";
private static readonly Vector3 PitonClimbingSpikeLocalPosition = new Vector3(-0.0304f, -27.3382f, -4.3815f);
private static readonly Vector3 PitonClimbingSpikeLocalEuler = new Vector3(270f, 180f, 0f);
private static readonly Vector3 PitonClimbingSpikeLocalScale = Vector3.one;
private static readonly Dictionary<int, bool> SwappedRopeIsAntiVisual = new Dictionary<int, bool>();
public static void Sync(Item item, RopeShooter shooter)
{
if ((Object)(object)shooter?.hideOnFire == (Object)null || !HandCannonHelper.IsHandCannon(item))
{
return;
}
Transform transform = shooter.hideOnFire.transform;
HandCannonAmmoType handCannonAmmoType = HandCannonAmmoHelper.GetLoadedAmmo(item);
if (handCannonAmmoType == HandCannonAmmoType.Empty && shooter.HasAmmo)
{
handCannonAmmoType = ((item.itemID == 64) ? HandCannonAmmoType.AntiRope : HandCannonAmmoType.NormalRope);
}
if (!shooter.HasAmmo || handCannonAmmoType == HandCannonAmmoType.Empty || !shooter.hideOnFire.activeSelf)
{
ClearRuntimeVisuals(shooter, transform);
return;
}
Transform val = FindDirectChild(transform, "Harpoon");
Transform val2 = FindDirectChild(transform, "Rope");
Transform val3 = EnsurePitonVisual(transform, val);
bool flag = handCannonAmmoType == HandCannonAmmoType.Piton;
bool flag2 = handCannonAmmoType == HandCannonAmmoType.NormalRope || handCannonAmmoType == HandCannonAmmoType.AntiRope;
SetActiveIfPresent(val, flag2);
SetActiveIfPresent(val3, flag);
if (flag2)
{
ApplyRopeVisual(item, shooter, transform, val2, handCannonAmmoType);
}
else
{
HideSwappedRopeVisual(shooter, transform);
SetActiveIfPresent(val2, active: false);
}
HideUnmanagedLoadedChildren(transform, val, val2, val3, flag, flag2);
}
private static void ApplyRopeVisual(Item item, RopeShooter shooter, Transform hideOnFire, Transform nativeRope, HandCannonAmmoType ammo)
{
bool flag = item.itemID == 64;
bool flag2 = ammo == HandCannonAmmoType.AntiRope;
if ((!flag || flag2) && !(!flag && flag2))
{
HideSwappedRopeVisual(shooter, hideOnFire);
SetActiveIfPresent(nativeRope, active: true);
return;
}
Transform referenceRopeTransform = GetReferenceRopeTransform(flag2);
if ((Object)(object)referenceRopeTransform == (Object)null)
{
HideSwappedRopeVisual(shooter, hideOnFire);
SetActiveIfPresent(nativeRope, active: true);
}
else
{
Transform transform = EnsureSwappedRopeVisual(shooter, hideOnFire, nativeRope, referenceRopeTransform, flag2);
SetActiveIfPresent(nativeRope, active: false);
SetActiveIfPresent(transform, active: true);
}
}
private static Transform GetReferenceRopeTransform(bool wantsAntiVisual)
{
RopeShooter shooter;
if (wantsAntiVisual)
{
AntiRopeCannonReference.TryGetShooter(out shooter);
}
else
{
NormalRopeCannonReference.TryGetShooter(out shooter);
}
if ((Object)(object)shooter?.hideOnFire == (Object)null)
{
return null;
}
return FindDirectChild(shooter.hideOnFire.transform, "Rope");
}
private static Transform EnsureSwappedRopeVisual(RopeShooter shooter, Transform hideOnFire, Transform nativeRope, Transform referenceRope, bool wantsAntiVisual)
{
int instanceID = ((Object)shooter).GetInstanceID();
Transform val = hideOnFire.Find("HandCannonSwappedRopeVisual");
if ((Object)(object)val != (Object)null && SwappedRopeIsAntiVisual.TryGetValue(instanceID, out var value) && value == wantsAntiVisual)
{
return val;
}
if ((Object)(object)val != (Object)null)
{
Object.Destroy((Object)(object)((Component)val).gameObject);
SwappedRopeIsAntiVisual.Remove(instanceID);
}
GameObject val2 = Object.Instantiate<GameObject>(((Component)referenceRope).gameObject, hideOnFire);
((Object)val2).name = "HandCannonSwappedRopeVisual";
ApplyAnchorTransform(val2.transform, nativeRope ?? referenceRope);
StripGameplayComponents(val2);
SwappedRopeIsAntiVisual[instanceID] = wantsAntiVisual;
return val2.transform;
}
private static Transform EnsurePitonVisual(Transform hideOnFire, Transform harpoonAnchor)
{
Transform val = FindDirectChild(hideOnFire, "Piton");
val = val ?? hideOnFire.Find("HandCannonPitonVisual");
if ((Object)(object)val != (Object)null)
{
ApplyPitonClimbingSpikeTransform(val);
return val;
}
GameObject val2 = Resources.Load<GameObject>("0_Items/Piton");
if ((Object)(object)val2 == (Object)null && PitonPrefabCache.EnsureInitialized(HandCannonPlugin.Log))
{
val2 = Resources.Load<GameObject>(PitonPrefabCache.PrefabPath);
}
if ((Object)(object)val2 == (Object)null)
{
return null;
}
GameObject val3 = Object.Instantiate<GameObject>(val2, hideOnFire);
((Object)val3).name = "HandCannonPitonVisual";
ApplyAnchorTransform(val3.transform, harpoonAnchor);
StripGameplayComponents(val3);
ApplyPitonClimbingSpikeTransform(val3.transform);
return val3.transform;
}
private static void ApplyPitonClimbingSpikeTransform(Transform pitonVisualRoot)
{
//IL_0082: 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_009f: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)pitonVisualRoot == (Object)null)
{
return;
}
Transform val = pitonVisualRoot.Find("ClimbingSpike");
if ((Object)(object)val == (Object)null)
{
for (int i = 0; i < pitonVisualRoot.childCount; i++)
{
Transform child = pitonVisualRoot.GetChild(i);
if (((Object)child).name.IndexOf("ClimbingSpike", StringComparison.OrdinalIgnoreCase) >= 0)
{
val = child;
break;
}
}
}
if (!((Object)(object)val == (Object)null))
{
val.localPosition = PitonClimbingSpikeLocalPosition;
val.localRotation = Quaternion.Euler(PitonClimbingSpikeLocalEuler);
val.localScale = PitonClimbingSpikeLocalScale;
}
}
private static void ApplyAnchorTransform(Transform visual, Transform anchor)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: 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_0034: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)visual == (Object)null))
{
if ((Object)(object)anchor == (Object)null)
{
visual.localPosition = Vector3.zero;
visual.localRotation = Quaternion.identity;
visual.localScale = Vector3.one;
}
else
{
visual.localPosition = anchor.localPosition;
visual.localRotation = anchor.localRotation;
visual.localScale = anchor.localScale;
}
}
}
private static void HideSwappedRopeVisual(RopeShooter shooter, Transform hideOnFire)
{
Transform transform = hideOnFire.Find("HandCannonSwappedRopeVisual");
SetActiveIfPresent(transform, active: false);
SwappedRopeIsAntiVisual.Remove(((Object)shooter).GetInstanceID());
}
private static void ClearRuntimeVisuals(RopeShooter shooter, Transform hideOnFire)
{
HideSwappedRopeVisual(shooter, hideOnFire);
Transform transform = hideOnFire.Find("HandCannonPitonVisual");
SetActiveIfPresent(transform, active: false);
Transform transform2 = FindDirectChild(hideOnFire, "Piton");
SetActiveIfPresent(transform2, active: false);
}
private static void HideUnmanagedLoadedChildren(Transform hideOnFire, Transform harpoon, Transform nativeRope, Transform pitonVisual, bool showPiton, bool showRopeShot)
{
for (int i = 0; i < hideOnFire.childCount; i++)
{
Transform child = hideOnFire.GetChild(i);
if (!((Object)(object)child == (Object)(object)harpoon) && !((Object)(object)child == (Object)(object)nativeRope) && !((Object)(object)child == (Object)(object)pitonVisual) && !(((Object)child).name == "HandCannonSwappedRopeVisual") && !(((Object)child).name == "SpawnPoint"))
{
bool active = (showPiton && ((Object)child).name == "Piton") || (showRopeShot && (((Object)child).name == "Harpoon" || ((Object)child).name == "Rope"));
((Component)child).gameObject.SetActive(active);
}
}
}
private static Transform FindDirectChild(Transform parent, string childName)
{
if ((Object)(object)parent == (Object)null)
{
return null;
}
return parent.Find(childName);
}
private static void SetActiveIfPresent(Transform transform, bool active)
{
if (transform != null)
{
((Component)transform).gameObject.SetActive(active);
}
}
private static void StripGameplayComponents(GameObject root)
{
if ((Object)(object)root == (Object)null)
{
return;
}
Component[] componentsInChildren = root.GetComponentsInChildren<Component>(true);
foreach (Component val in componentsInChildren)
{
if (!((Object)(object)val == (Object)null) && !(val is Transform) && !(val is MeshFilter) && !(val is MeshRenderer) && !(val is SkinnedMeshRenderer) && !(val is ParticleSystem) && !(val is ParticleSystemRenderer) && !(val is LineRenderer) && !(val is TrailRenderer))
{
Object.Destroy((Object)(object)val);
}
}
}
}
internal static class AntiRopeCannonReference
{
private static RopeShooter _cachedShooter;
private static bool _loggedFailure;
public static bool IsAvailable()
{
RopeShooter shooter;
return TryGetShooter(out shooter);
}
public static bool TryGetShooter(out RopeShooter shooter)
{
if ((Object)(object)_cachedShooter != (Object)null)
{
shooter = _cachedShooter;
return true;
}
if (TryResolveFromLoadedItems(out shooter) || TryResolveFromResources(out shooter) || TryResolveFromLoadedAssets(out shooter))
{
_cachedShooter = shooter;
ManualLogSource log = HandCannonPlugin.Log;
if (log != null)
{
log.LogInfo((object)$"Resolved anti-rope reference from '{((Object)((Component)shooter).gameObject).name}' (length={shooter.length} segments).");
}
return true;
}
if (!_loggedFailure)
{
_loggedFailure = true;
ManualLogSource log2 = HandCannonPlugin.Log;
if (log2 != null)
{
log2.LogWarning((object)"Could not resolve anti-rope cannon reference. Anti-grav spool reloads disabled until available.");
}
}
shooter = null;
return false;
}
private static bool TryResolveFromLoadedItems(out RopeShooter shooter)
{
shooter = null;
Item[] array = Resources.FindObjectsOfTypeAll<Item>();
foreach (Item val in array)
{
if (!((Object)(object)val == (Object)null) && val.itemID == 64)
{
RopeShooter component = ((Component)val).GetComponent<RopeShooter>();
if ((Object)(object)component?.ropeAnchorWithRopePref != (Object)null)
{
shooter = component;
return true;
}
}
}
return false;
}
private static bool TryResolveFromResources(out RopeShooter shooter)
{
shooter = null;
string[] array = new string[3] { "0_Items/Anti-Rope Cannon", "0_Items/RopeShooterAnti", "0_Items/AntiRope Cannon" };
string[] array2 = array;
foreach (string text in array2)
{
GameObject val = Resources.Load<GameObject>(text);
shooter = ((val != null) ? val.GetComponent<RopeShooter>() : null);
if ((Object)(object)shooter != (Object)null)
{
return true;
}
}
GameObject[] array3 = Resources.LoadAll<GameObject>("0_Items/");
if (array3 == null)
{
return false;
}
GameObject[] array4 = array3;
foreach (GameObject val2 in array4)
{
if ((Object)(object)val2 == (Object)null)
{
continue;
}
Item component = val2.GetComponent<Item>();
if (!((Object)(object)component == (Object)null) && component.itemID == 64)
{
shooter = val2.GetComponent<RopeShooter>();
if ((Object)(object)shooter != (Object)null)
{
return true;
}
}
}
return false;
}
private static bool TryResolveFromLoadedAssets(out RopeShooter shooter)
{
//IL_0034: 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)
shooter = null;
RopeShooter[] array = Resources.FindObjectsOfTypeAll<RopeShooter>();
foreach (RopeShooter val in array)
{
if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null))
{
Scene scene = ((Component)val).gameObject.scene;
if (!((Scene)(ref scene)).IsValid() && ((Component)val).GetComponent<Item>()?.itemID == 64)
{
shooter = val;
return true;
}
}
}
return false;
}
public static float GetShotSegments()
{
if (TryGetShooter(out var shooter) && shooter.length > 0f)
{
return shooter.length;
}
return 30f;
}
public static GameObject GetAnchorPrefab()
{
RopeShooter shooter;
return TryGetShooter(out shooter) ? shooter.ropeAnchorWithRopePref : null;
}
}
internal static class NormalRopeCannonReference
{
private static RopeShooter _cachedShooter;
private static bool _loggedFailure;
public static bool IsAvailable()
{
RopeShooter shooter;
return TryGetShooter(out shooter);
}
public static bool TryGetShooter(out RopeShooter shooter)
{
if ((Object)(object)_cachedShooter != (Object)null)
{
shooter = _cachedShooter;
return true;
}
if (TryResolveFromLoadedItems(out shooter) || TryResolveFromResources(out shooter) || TryResolveFromLoadedAssets(out shooter))
{
_cachedShooter = shooter;
ManualLogSource log = HandCannonPlugin.Log;
if (log != null)
{
log.LogInfo((object)$"Resolved normal rope reference from '{((Object)((Component)shooter).gameObject).name}' (length={shooter.length} segments).");
}
return true;
}
if (!_loggedFailure)
{
_loggedFailure = true;
ManualLogSource log2 = HandCannonPlugin.Log;
if (log2 != null)
{
log2.LogWarning((object)"Could not resolve normal rope cannon reference. Anti-grav Hand Cannon normal reloads may fire anti rope.");
}
}
shooter = null;
return false;
}
private static bool TryResolveFromLoadedItems(out RopeShooter shooter)
{
shooter = null;
Item[] array = Resources.FindObjectsOfTypeAll<Item>();
foreach (Item val in array)
{
if (!((Object)(object)val == (Object)null) && val.itemID == 63)
{
RopeShooter component = ((Component)val).GetComponent<RopeShooter>();
if ((Object)(object)component?.ropeAnchorWithRopePref != (Object)null)
{
shooter = component;
return true;
}
}
}
return false;
}
private static bool TryResolveFromResources(out RopeShooter shooter)
{
shooter = null;
string[] array = new string[3] { "0_Items/Rope Cannon", "0_Items/RopeShooter", "0_Items/Rope CannonItem" };
string[] array2 = array;
foreach (string text in array2)
{
GameObject val = Resources.Load<GameObject>(text);
shooter = ((val != null) ? val.GetComponent<RopeShooter>() : null);
if ((Object)(object)shooter?.ropeAnchorWithRopePref != (Object)null)
{
return true;
}
}
GameObject[] array3 = Resources.LoadAll<GameObject>("0_Items/");
if (array3 == null)
{
return false;
}
GameObject[] array4 = array3;
foreach (GameObject val2 in array4)
{
if ((Object)(object)val2 == (Object)null)
{
continue;
}
Item component = val2.GetComponent<Item>();
if (!((Object)(object)component == (Object)null) && component.itemID == 63)
{
shooter = val2.GetComponent<RopeShooter>();
if ((Object)(object)shooter?.ropeAnchorWithRopePref != (Object)null)
{
return true;
}
}
}
return false;
}
private static bool TryResolveFromLoadedAssets(out RopeShooter shooter)
{
//IL_0034: 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)
shooter = null;
RopeShooter[] array = Resources.FindObjectsOfTypeAll<RopeShooter>();
foreach (RopeShooter val in array)
{
if (!((Object)(object)val == (Object)null) && !((Object)(object)((Component)val).gameObject == (Object)null))
{
Scene scene = ((Component)val).gameObject.scene;
if (!((Scene)(ref scene)).IsValid() && ((Component)val).GetComponent<Item>()?.itemID == 63)
{
shooter = val;
return true;
}
}
}
return false;
}
public static float GetShotSegments()
{
if (TryGetShooter(out var shooter) && shooter.length > 0f)
{
return shooter.length;
}
return 30f;
}
public static GameObject GetAnchorPrefab()
{
RopeShooter shooter;
return TryGetShooter(out shooter) ? shooter.ropeAnchorWithRopePref : null;
}
}
internal static class RopeSpoolLengthHelper
{
public const float MetersPerSegment = 0.25f;
public const float DefaultCannonShotSegments = 30f;
public const float OutOfRopeSegmentThreshold = 2f;
public const float DefaultSpoolStartFuel = 60f;
private const float SegmentComparisonEpsilon = 0.01f;
internal const float SegmentEpsilon = 0.01f;
public static float SegmentsToMeters(float segments)
{
return segments * 0.25f;
}
public static float GetCannonShotSegments(RopeShooter shooter)
{
if ((Object)(object)shooter == (Object)null || shooter.length <= 0f)
{
return 30f;
}
return shooter.length;
}
public static float GetCannonShotMeters(RopeShooter shooter)
{
return SegmentsToMeters(GetCannonShotSegments(shooter));
}
public static float GetSpoolStartFuel(ItemSlot slot)
{
if ((Object)(object)slot?.prefab == (Object)null)
{
return 60f;
}
RopeSpool component = ((Component)slot.prefab).GetComponent<RopeSpool>();
return ((Object)(object)component != (Object)null) ? component.ropeStartFuel : 60f;
}
public static float GetRemainingSegments(ItemSlot slot)
{
if (slot == null || slot.IsEmpty())
{
return 0f;
}
float spoolStartFuel = GetSpoolStartFuel(slot);
ItemInstanceData data = slot.data;
if (data == null)
{
return spoolStartFuel;
}
FloatItemData val = default(FloatItemData);
if (data.TryGetDataEntry<FloatItemData>((DataEntryKey)10, ref val))
{
return Mathf.Max(0f, val.Value);
}
FloatItemData val2 = default(FloatItemData);
if (data.TryGetDataEntry<FloatItemData>((DataEntryKey)11, ref val2))
{
return Mathf.Max(0f, val2.Value * spoolStartFuel);
}
return spoolStartFuel;
}
public static int CountFullReloadsAvailable(float remainingSegments, float requiredSegments)
{
if (requiredSegments <= 0.01f)
{
return 0;
}
return Mathf.FloorToInt(remainingSegments / requiredSegments);
}
public static bool HasReloadableLength(float segments)
{
return segments > 2.01f;
}
public static bool CanFullyReload(float segments, float requiredSegments)
{
return segments + 0.01f >= requiredSegments;
}
}
internal readonly struct RopeReloadPlan
{
public ItemSlot PartialSlot { get; }
public float SegmentsToDeduct { get; }
public IReadOnlyList<ItemSlot> SlotsToConsumeEntirely { get; }
public bool IsAntiRopeAmmo { get; }
public bool UsesPartialSlot => PartialSlot != null;
public bool IsValid => UsesPartialSlot || SlotsToConsumeEntirely.Count > 0;
public RopeReloadPlan(ItemSlot partialSlot, float segmentsToDeduct, IReadOnlyList<ItemSlot> slotsToConsumeEntirely, bool isAntiRopeAmmo)
{
PartialSlot = partialSlot;
SegmentsToDeduct = segmentsToDeduct;
SlotsToConsumeEntirely = slotsToConsumeEntirely ?? Array.Empty<ItemSlot>();
IsAntiRopeAmmo = isAntiRopeAmmo;
}
}
internal sealed class HandCannonReloadPlan
{
public HandCannonAmmoType AmmoType { get; private set; }
public ItemSlot PitonSlot { get; private set; }
public RopeReloadPlan RopePlan { get; private set; }
public string DisplayLabel { get; private set; }
public bool IsPiton => AmmoType == HandCannonAmmoType.Piton;
public bool IsValid => IsPiton ? (PitonSlot != null) : RopePlan.IsValid;
public static HandCannonReloadPlan ForPiton(ItemSlot slot)
{
return new HandCannonReloadPlan
{
AmmoType = HandCannonAmmoType.Piton,
PitonSlot = slot,
DisplayLabel = $"Piton — slot {slot.itemSlotID}"
};
}
public static HandCannonReloadPlan ForRope(RopeReloadPlan ropePlan, HandCannonAmmoType ammoType, string displayLabel)
{
return new HandCannonReloadPlan
{
AmmoType = ammoType,
RopePlan = ropePlan,
DisplayLabel = displayLabel
};
}
}
internal static class HandCannonInventoryHelper
{
private const byte TempInventorySlotId = 250;
public static bool IsHandheldPitonPrefab(Item prefab, ItemInstanceData slotData = null)
{
if ((Object)(object)prefab == (Object)null || (Object)(object)((Component)prefab).GetComponent<RopeShooter>() != (Object)null)
{
return false;
}
if (prefab.itemID == 18 || (Object)(object)((Component)prefab).GetComponent<ClimbingSpikeComponent>() != (Object)null)
{
IntItemData val = default(IntItemData);
if (slotData != null && slotData.TryGetDataEntry<IntItemData>((DataEntryKey)1, ref val) && val.Value > 0)
{
return false;
}
return true;
}
string text = ((Object)((Component)prefab).gameObject).name ?? string.Empty;
return text.IndexOf("ClimbingSpike", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("Piton", StringComparison.OrdinalIgnoreCase) >= 0;
}
public static bool IsRopeSpoolPrefab(Item prefab)
{
if ((Object)(object)prefab == (Object)null || (Object)(object)((Component)prefab).GetComponent<RopeShooter>() != (Object)null)
{
return false;
}
if ((Object)(object)((Component)prefab).GetComponent<RopeSpool>() != (Object)null)
{
return true;
}
if (prefab.itemID == 65 || prefab.itemID == 1)
{
return true;
}
string text = ((Object)((Component)prefab).gameObject).name ?? string.Empty;
return text.IndexOf("Rope Spool", StringComparison.OrdinalIgnoreCase) >= 0;
}
public static bool IsAntiRopeSpoolPrefab(Item prefab)
{
if ((Object)(object)prefab == (Object)null)
{
return false;
}
RopeSpool component = ((Component)prefab).GetComponent<RopeSpool>();
if (component != null && component.isAntiRope)
{
return true;
}
if (prefab.itemID == 1)
{
return true;
}
string text = ((Object)((Component)prefab).gameObject).name ?? string.Empty;
return text.IndexOf("Anti-Rope Spool", StringComparison.OrdinalIgnoreCase) >= 0;
}
public static void RefreshPitonTracking(Character character)
{
if ((Object)(object)character?.refs?.items != (Object)null && character.player?.itemSlots != null)
{
character.refs.items.UpdateClimbingSpikeCount(character.player.itemSlots);
}
}
public static List<ItemSlot> GetPitonSlotsInOrder(Character character)
{
List<ItemSlot> list = new List<ItemSlot>();
if ((Object)(object)character == (Object)null)
{
return list;
}
RefreshPitonTracking(character);
AppendPitonSlots(character.player?.itemSlots, list);
if (character.player?.tempFullSlot != null && !character.player.tempFullSlot.IsEmpty() && IsHandheldPitonPrefab(character.player.tempFullSlot.prefab, character.player.tempFullSlot.data))
{
list.Add(character.player.tempFullSlot);
}
if (HandCannonPlugin.AllowBackpackReloadConfig.Value)
{
AppendBackpackPitonSlots(character, list);
}
return list;
}
private static void AppendPitonSlots(ItemSlot[] slots, List<ItemSlot> pitonSlots)
{
if (slots == null)
{
return;
}
foreach (ItemSlot val in slots)
{
if (val != null && !val.IsEmpty() && IsHandheldPitonPrefab(val.prefab, val.data))
{
pitonSlots.Add(val);
}
}
}
private static void AppendBackpackPitonSlots(Character character, List<ItemSlot> pitonSlots)
{
if (!((Object)(object)((character != null) ? character.player : null) == (Object)null) && character.player.backpackSlot.hasBackpack)
{
ItemInstanceData data = ((ItemSlot)character.player.backpackSlot).data;
BackpackData val = default(BackpackData);
if (data != null && data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref val))
{
AppendPitonSlots(val.itemSlots, pitonSlots);
}
}
}
public static List<ItemSlot> GetRopeSpoolSlotsInOrder(Character character)
{
List<ItemSlot> list = new List<ItemSlot>();
if ((Object)(object)character == (Object)null)
{
return list;
}
AppendRopeSlots(character.player?.itemSlots, list);
if (character.player?.tempFullSlot != null && !character.player.tempFullSlot.IsEmpty() && IsRopeSpoolPrefab(character.player.tempFullSlot.prefab))
{
list.Add(character.player.tempFullSlot);
}
if (HandCannonPlugin.AllowBackpackReloadConfig.Value)
{
AppendBackpackRopeSlots(character, list);
}
return list;
}
private static void AppendRopeSlots(ItemSlot[] slots, List<ItemSlot> ropeSlots)
{
if (slots == null)
{
return;
}
foreach (ItemSlot val in slots)
{
if (val != null && !val.IsEmpty() && IsRopeSpoolPrefab(val.prefab))
{
ropeSlots.Add(val);
}
}
}
private static void AppendBackpackRopeSlots(Character character, List<ItemSlot> ropeSlots)
{
if (!((Object)(object)((character != null) ? character.player : null) == (Object)null) && character.player.backpackSlot.hasBackpack)
{
ItemInstanceData data = ((ItemSlot)character.player.backpackSlot).data;
BackpackData val = default(BackpackData);
if (data != null && data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref val))
{
AppendRopeSlots(val.itemSlots, ropeSlots);
}
}
}
public static bool TryBuildBestRopePlan(List<ItemSlot> ropeSlots, float requiredSegments, bool isAntiRopeAmmo, out RopeReloadPlan plan)
{
if (HasPartialSpoolsForAmmoType(ropeSlots, requiredSegments, isAntiRopeAmmo) && TryBuildCombinedReloadPlan(ropeSlots, requiredSegments, isAntiRopeAmmo, out plan))
{
return true;
}
if (TryBuildSingleSpoolPlan(ropeSlots, requiredSegments, isAntiRopeAmmo, out plan))
{
return true;
}
return TryBuildCombinedReloadPlan(ropeSlots, requiredSegments, isAntiRopeAmmo, out plan);
}
private static bool HasPartialSpoolsForAmmoType(List<ItemSlot> ropeSlots, float requiredSegments, bool isAntiRopeAmmo)
{
foreach (ItemSlot ropeSlot in ropeSlots)
{
if (IsAntiRopeSpoolPrefab(ropeSlot.prefab) == isAntiRopeAmmo)
{
float remainingSegments = RopeSpoolLengthHelper.GetRemainingSegments(ropeSlot);
if (RopeSpoolLengthHelper.HasReloadableLength(remainingSegments) && !RopeSpoolLengthHelper.CanFullyReload(remainingSegments, requiredSegments))
{
return true;
}
}
}
return false;
}
private static bool TryBuildSingleSpoolPlan(List<ItemSlot> ropeSlots, float requiredSegments, bool isAntiRopeAmmo, out RopeReloadPlan plan)
{
plan = default(RopeReloadPlan);
foreach (ItemSlot ropeSlot in ropeSlots)
{
if (IsAntiRopeSpoolPrefab(ropeSlot.prefab) == isAntiRopeAmmo)
{
float remainingSegments = RopeSpoolLengthHelper.GetRemainingSegments(ropeSlot);
if (RopeSpoolLengthHelper.CanFullyReload(remainingSegments, requiredSegments))
{
plan = new RopeReloadPlan(ropeSlot, requiredSegments, Array.Empty<ItemSlot>(), isAntiRopeAmmo);
return true;
}
}
}
return false;
}
private static bool TryBuildCombinedReloadPlan(List<ItemSlot> ropeSlots, float requiredSegments, bool isAntiRopeAmmo, out RopeReloadPlan plan)
{
plan = default(RopeReloadPlan);
float num = 0f;
List<ItemSlot> list = new List<ItemSlot>();
foreach (ItemSlot ropeSlot in ropeSlots)
{
if (IsAntiRopeSpoolPrefab(ropeSlot.prefab) != isAntiRopeAmmo)
{
continue;
}
float remainingSegments = RopeSpoolLengthHelper.GetRemainingSegments(ropeSlot);
if (RopeSpoolLengthHelper.HasReloadableLength(remainingSegments))
{
list.Add(ropeSlot);
num += remainingSegments;
if (RopeSpoolLengthHelper.CanFullyReload(num, requiredSegments))
{
plan = BuildCombinedReloadPlan(list, requiredSegments, isAntiRopeAmmo);
return plan.IsValid;
}
}
}
return false;
}
private static RopeReloadPlan BuildCombinedReloadPlan(List<ItemSlot> spoolsInOrder, float requiredSegments, bool isAntiRopeAmmo)
{
float num = requiredSegments;
List<ItemSlot> list = new List<ItemSlot>();
ItemSlot val = null;
float segmentsToDeduct = 0f;
foreach (ItemSlot item in spoolsInOrder)
{
float remainingSegments = RopeSpoolLengthHelper.GetRemainingSegments(item);
if (!(remainingSegments <= 2f))
{
if (!(num + 0.01f >= remainingSegments))
{
val = item;
segmentsToDeduct = num;
num = 0f;
break;
}
list.Add(item);
num -= remainingSegments;
}
}
if (num > 0.01f)
{
return default(RopeReloadPlan);
}
if (val != null)
{
return new RopeReloadPlan(val, segmentsToDeduct, list, isAntiRopeAmmo);
}
return new RopeReloadPlan(null, 0f, list, isAntiRopeAmmo);
}
public static string BuildRopePlanLabel(RopeReloadPlan plan, float requiredSegments, HandCannonAmmoType ammoType)
{
string text = ((ammoType == HandCannonAmmoType.AntiRope) ? "Anti-grav rope" : "Rope");
float num = RopeSpoolLengthHelper.SegmentsToMeters(requiredSegments);
if (plan.SlotsToConsumeEntirely.Count == 0 && plan.UsesPartialSlot)
{
float segments = RopeSpoolLengthHelper.GetRemainingSegments(plan.PartialSlot) - plan.SegmentsToDeduct;
return $"{text} — {num:0.##}m from slot {plan.PartialSlot.itemSlotID} ({RopeSpoolLengthHelper.SegmentsToMeters(segments):0.##}m left after)";
}
if (plan.SlotsToConsumeEntirely.Count > 0 && !plan.UsesPartialSlot)
{
return $"{text} — combine {plan.SlotsToConsumeEntirely.Count} spool(s) for {num:0.##}m";
}
if (plan.SlotsToConsumeEntirely.Count > 0 && plan.UsesPartialSlot)
{
return $"{text} — combine {plan.SlotsToConsumeEntirely.Count + 1} spool(s) for {num:0.##}m";
}
return $"{text} — {num:0.##}m shot";
}
public static bool TryApplyRopePlan(Character character, RopeReloadPlan plan)
{
if ((Object)(object)character == (Object)null || !plan.IsValid)
{
return false;
}
bool flag = false;
if (plan.UsesPartialSlot)
{
if (!TryDeductSegmentsFromSlot(character, plan.PartialSlot, plan.SegmentsToDeduct))
{
return false;
}
flag = IsBackpackSlot(character, plan.PartialSlot);
}
foreach (ItemSlot item in plan.SlotsToConsumeEntirely)
{
if (!TryConsumeInventorySlot(character, item, syncBackpack: false))
{
return false;
}
flag = flag || IsBackpackSlot(character, item);
}
if (flag)
{
SyncPlayerInventory(character);
}
return true;
}
public static bool TryConsumePitonSlot(Character character, ItemSlot slot)
{
if ((Object)(object)character == (Object)null || slot == null)
{
return false;
}
bool result = TryConsumeInventorySlot(character, slot, syncBackpack: true);
RefreshPitonTracking(character);
return result;
}
private static bool TryDeductSegmentsFromSlot(Character character, ItemSlot slot, float segmentsToDeduct)
{
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Expected O, but got Unknown
if ((Object)(object)character == (Object)null || slot == null || slot.IsEmpty() || segmentsToDeduct <= 0f)
{
return false;
}
float spoolStartFuel = RopeSpoolLengthHelper.GetSpoolStartFuel(slot);
float num = RopeSpoolLengthHelper.GetRemainingSegments(slot) - segmentsToDeduct;
if (num <= 2f)
{
return TryConsumeInventorySlot(character, slot, syncBackpack: false);
}
if (slot.data == null)
{
slot.data = new ItemInstanceData(Guid.NewGuid());
}
ItemDataHelper.SetFloatEntry(slot.data, (DataEntryKey)10, num);
float value = ((spoolStartFuel > 0f) ? Mathf.Clamp01(num / spoolStartFuel) : 0f);
ItemDataHelper.SetFloatEntry(slot.data, (DataEntryKey)11, value);
return true;
}
private static bool TryConsumeInventorySlot(Character character, ItemSlot slot, bool syncBackpack)
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
if (slot.itemSlotID == 250)
{
character.player.EmptySlot(Optionable<byte>.Some((byte)250));
}
else if (IsBackpackSlot(character, slot))
{
slot.EmptyOut();
if (syncBackpack)
{
SyncPlayerInventory(character);
}
}
else
{
character.player.EmptySlot(Optionable<byte>.Some(slot.itemSlotID));
}
return true;
}
private static void SyncPlayerInventory(Character character)
{
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
object obj;
if (character == null)
{
obj = null;
}
else
{
Player player = character.player;
obj = ((player != null) ? ((Component)player).GetComponent<PhotonView>() : null);
}
PhotonView val = (PhotonView)obj;
if (!PhotonNetwork.IsMasterClient || (Object)(object)val == (Object)null)
{
return;
}
try
{
InventorySyncData val2 = default(InventorySyncData);
((InventorySyncData)(ref val2))..ctor(character.player.itemSlots, character.player.backpackSlot, character.player.tempFullSlot);
val.RPC("SyncInventoryRPC", (RpcTarget)1, new object[2]
{
IBinarySerializable.ToManagedArray<InventorySyncData>(val2),
false
});
}
catch (Exception ex)
{
HandCannonPlugin.Log.LogWarning((object)("[Reload] inventory sync skipped: " + ex.Message));
}
}
public static bool IsBackpackSlot(Character character, ItemSlot slot)
{
if ((Object)(object)((character != null) ? character.player : null) == (Object)null || slot == null || !character.player.backpackSlot.hasBackpack)
{
return false;
}
ItemInstanceData data = ((ItemSlot)character.player.backpackSlot).data;
BackpackData val = default(BackpackData);
if (data == null || !data.TryGetDataEntry<BackpackData>((DataEntryKey)7, ref val))
{
return false;
}
ItemSlot[] itemSlots = val.itemSlots;
foreach (ItemSlot val2 in itemSlots)
{
if (val2 == slot)
{
return true;
}
}
return false;
}
}
internal static class HandCannonReloadPlanner
{
public static List<HandCannonReloadPlan> BuildAllValidPlans(Character character, RopeShooter shooter)
{
List<HandCannonReloadPlan> list = new List<HandCannonReloadPlan>();
if ((Object)(object)character == (Object)null || (Object)(object)shooter == (Object)null)
{
return list;
}
foreach (ItemSlot item in HandCannonInventoryHelper.GetPitonSlotsInOrder(character))
{
list.Add(HandCannonReloadPlan.ForPiton(item));
}
List<ItemSlot> ropeSpoolSlotsInOrder = HandCannonInventoryHelper.GetRopeSpoolSlotsInOrder(character);
float cannonShotSegments = RopeSpoolLengthHelper.GetCannonShotSegments(shooter);
if (HandCannonInventoryHelper.TryBuildBestRopePlan(ropeSpoolSlotsInOrder, cannonShotSegments, isAntiRopeAmmo: false, out var plan))
{
string displayLabel = HandCannonInventoryHelper.BuildRopePlanLabel(plan, cannonShotSegments, HandCannonAmmoType.NormalRope);
list.Add(HandCannonReloadPlan.ForRope(plan, HandCannonAmmoType.NormalRope, displayLabel));
}
if (CanUseAntiRopeAmmo(shooter) && HandCannonInventoryHelper.TryBuildBestRopePlan(ropeSpoolSlotsInOrder, AntiRopeCannonReference.GetShotSegments(), isAntiRopeAmmo: true, out var plan2))
{
float shotSegments = AntiRopeCannonReference.GetShotSegments();
string displayLabel2 = HandCannonInventoryHelper.BuildRopePlanLabel(plan2, shotSegments, HandCannonAmmoType.AntiRope);
list.Add(HandCannonReloadPlan.ForRope(plan2, HandCannonAmmoType.AntiRope, displayLabel2));
}
return CollapseDistinctAmmoTypes(list);
}
private static List<HandCannonReloadPlan> CollapseDistinctAmmoTypes(List<HandCannonReloadPlan> plans)
{
List<HandCannonReloadPlan> list = new List<HandCannonReloadPlan>();
HashSet<HandCannonAmmoType> hashSet = new HashSet<HandCannonAmmoType>();
foreach (HandCannonReloadPlan plan in plans)
{
if (hashSet.Add(plan.AmmoType))
{
list.Add(plan);
}
}
return list;
}
private static bool CanUseAntiRopeAmmo(RopeShooter shooter)
{
if (HandCannonHelper.GetItem(shooter)?.itemID == 64)
{
return true;
}
return AntiRopeCannonReference.IsAvailable();
}
}
internal static class HandCannonReloadExecutor
{
public static bool TryManualReload(Character holder)
{
Character obj = holder;
object obj2;
if (obj == null)
{
obj2 = null;
}
else
{
CharacterData data = obj.data;
obj2 = ((data != null) ? data.currentItem : null);
}
if ((Object)obj2 == (Object)null)
{
return false;
}
Item cannonItem = holder.data.currentItem;
RopeShooter shooter = ((Component)cannonItem).GetComponent<RopeShooter>();
if (!HandCannonHelper.IsHandCannon(cannonItem) || (Object)(object)shooter == (Object)null || !HandCannonHelper.IsEmptyForReload(cannonItem, shooter))
{
return false;
}
HandCannonPlugin.Log.LogInfo((object)"[Reload] manual reload requested.");
List<HandCannonReloadPlan> list = HandCannonReloadPlanner.BuildAllValidPlans(holder, shooter);
if (list.Count == 0)
{
HandCannonPlugin.Log.LogInfo((object)"[Reload] no ammo available for Hand Cannon reload.");
return false;
}
HandCannonPlugin.Log.LogInfo((object)$"[Reload] {list.Count} reload option(s) available.");
if (list.Count == 1)
{
return ExecutePlan(holder, cannonItem, shooter, list[0]);
}
HandCannonReloadPickerUI.Show(list, delegate(HandCannonReloadPlan plan)
{
ExecutePlan(holder, cannonItem, shooter, plan);
});
return true;
}
public static bool ExecutePlan(Character holder, Item cannonItem, RopeShooter shooter, HandCannonReloadPlan plan)
{
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)holder == (Object)null || (Object)(object)cannonItem == (Object)null || (Object)(object)shooter == (Object)null || plan == null || !plan.IsValid)
{
return false;
}
HandCannonPlugin.Log.LogInfo((object)("[Reload] executing plan: " + plan.DisplayLabel));
Optionable<byte> currentSelectedSlot = holder.refs.items.currentSelectedSlot;
ItemSlot val = (currentSelectedSlot.IsSome ? holder.player.GetItemSlot(currentSelectedSlot.Value) : null);
if (!ApplySlotDataReload(cannonItem, shooter, plan.AmmoType, val))
{
return false;
}
if (!shooter.HasAmmo)
{
HandCannonPlugin.Log.LogWarning((object)"[Reload] slot-data reload left Hand Cannon empty.");
return false;
}
if (val != null && !val.IsEmpty())
{
ResetCannonSlotForFreshShot(val, shooter, plan.AmmoType);
}
if (plan.IsPiton)
{
if (!HandCannonInventoryHelper.TryConsumePitonSlot(holder, plan.PitonSlot))
{
HandCannonPlugin.Log.LogWarning((object)"[Reload] piton reload succeeded but piton could not be consumed.");
return false;
}
}
else if (!HandCannonInventoryHelper.TryApplyRopePlan(holder, plan.RopePlan))
{
HandCannonPlugin.Log.LogWarning((object)"[Reload] reload succeeded but rope could not be consumed.");
return false;
}
HandCannonStateSync.Sync(cannonItem, shooter);
HandCannonNetworkSync.PushAmmoState(cannonItem, val, holder);
HandCannonPlugin.Log.LogInfo((object)$"[Reload] ok: loaded {HandCannonAmmoHelper.GetAmmoLabel(plan.AmmoType)}, hasAmmo={shooter.HasAmmo}");
return true;
}
private static bool ApplySlotDataReload(Item cannonItem, RopeShooter shooter, HandCannonAmmoType ammoType, ItemSlot cannonSlot)
{
if (ammoType == HandCannonAmmoType.AntiRope && cannonItem.itemID != 64 && !AntiRopeCannonReference.IsAvailable())
{
HandCannonPlugin.Log.LogWarning((object)"[Reload] anti-grav reload failed: anti reference unavailable.");
return false;
}
int ammo = Mathf.Max(1, shooter.startAmmo);
try
{
IntItemData data = ((ItemComponent)shooter).GetData<IntItemData>((DataEntryKey)12, (Func<IntItemData>)(() => ItemDataHelper.CreateIntItemData(ammo)));
data.Value = ammo;
OptionableIntItemData data2 = cannonItem.GetData<OptionableIntItemData>((DataEntryKey)2);
if (data2 != null)
{
data2.Value = ammo;
}
HandCannonAmmoHelper.SetLoadedAmmo(cannonItem, cannonSlot, ammoType);
cannonItem.SetUseRemainingPercentage(1f);
shooter.cantReFire = false;
((ItemComponent)shooter).OnInstanceDataSet();
cannonItem.finishedCast = false;
cannonItem.CancelUsePrimary();
HandCannonPlugin.Log.LogInfo((object)$"[Reload] slot-data applied (ammo={HandCannonAmmoHelper.GetAmmoLabel(ammoType)}, hasAmmo={shooter.HasAmmo})");
return shooter.HasAmmo;
}
catch (Exception ex)
{
HandCannonPlugin.Log.LogError((object)("[Reload] slot-data failed: " + ex.GetType().Name + ": " + ex.Message));
return false;
}
}
private static void ResetCannonSlotForFreshShot(ItemSlot slot, RopeShooter shooter, HandCannonAmmoType ammoType)
{
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Expected O, but got Unknown
int value = ((!((Object)(object)shooter != (Object)null)) ? 1 : Mathf.Max(1, shooter.startAmmo));
if (slot.data == null)
{
slot.data = new ItemInstanceData(Guid.NewGuid());
}
ItemDataHelper.SetIntEntry(slot.data, (DataEntryKey)12, value);
ItemDataHelper.SetOptionableIntEntry(slot.data, (DataEntryKey)2, value);
ItemDataHelper.SetIntEntry(slot.data, HandCannonDataEntryKey.LoadedAmmoType, (int)ammoType);
}
}
internal sealed class HandCannonReloadPickerUI : MonoBehaviour
{
private const int WindowId = 63818;
private static HandCannonReloadPickerUI _instance;
private bool _visible;
private List<HandCannonReloadPlan> _openPlans;
private Action<HandCannonReloadPlan> _onSelected;
private Rect _windowRect = new Rect(0f, 0f, 560f, 320f);
private float _openedAt;
public static bool IsOpen => (Object)(object)_instance != (Object)null && _instance._visible;
public static void TryKeyboardSelect()
{
//IL_002f: 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_0040: Unknown result type (might be due to invalid IL or missing references)
if (!IsOpen || _instance?._openPlans == null)
{
return;
}
for (int i = 0; i < _instance._openPlans.Count && i < 9; i++)
{
KeyCode val = (KeyCode)(49 + i);
KeyCode val2 = (KeyCode)(257 + i);
if (Input.GetKeyDown(val) || Input.GetKeyDown(val2))
{
_instance.OnPlanSelected(_instance._openPlans[i]);
break;
}
}
}
public static void EnsureCreated()
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
if (!((Object)(object)_instance != (Object)null))
{
GameObject val = new GameObject("HandCannonReloadPickerUI");
Object.DontDestroyOnLoad((Object)(object)val);
_instance = val.AddComponent<HandCannonReloadPickerUI>();
}
}
public static void DestroyInstance()
{
if (!((Object)(object)_instance == (Object)null))
{
Object.Destroy((Object)(object)((Component)_instance).gameObject);
_instance = null;
}
}
public static void Show(List<HandCannonReloadPlan> plans, Action<HandCannonReloadPlan> onSelected)
{
EnsureCreated();
_instance.Open(plans, onSelected);
}
public static void Close()
{
ForceClose();
}
public static void ForceClose()
{
if (!((Object)(object)_instance == (Object)null))
{
_instance.CloseInternal();
}
}
private void Update()
{
if (_visible && Time.unscaledTime - _openedAt > 120f)
{
HandCannonPlugin.Log.LogWarning((object)"[Reload] picker timed out, closing.");
CloseInternal();
}
}
private void OnGUI()
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Expected O, but got Unknown
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
if (_visible && _openPlans != null)
{
Cursor.lockState = (CursorLockMode)0;
Cursor.visible = true;
_windowRect = GUI.Window(63818, _windowRect, new WindowFunction(DrawWindow), "Choose Hand Cannon Ammo");
}
}
private void DrawWindow(int windowId)
{
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
List<HandCannonReloadPlan> openPlans = _openPlans;
if (openPlans == null)
{
return;
}
float num = 28f;
float num2 = ((Rect)(ref _windowRect)).width - 40f;
for (int i = 0; i < openPlans.Count; i++)
{
HandCannonReloadPlan handCannonReloadPlan = openPlans[i];
if (handCannonReloadPlan != null)
{
string text = $"{i + 1}. {handCannonReloadPlan.DisplayLabel}";
if (GUI.Button(new Rect(20f, num, num2, 40f), text))
{
OnPlanSelected(handCannonReloadPlan);
return;
}
num += 48f;
}
}
if (GUI.Button(new Rect(20f, ((Rect)(ref _windowRect)).height - 42f, num2, 30f), "Cancel (Esc)"))
{
CloseInternal();
}
else
{
GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _windowRect)).width, 24f));
}
}
private void Open(List<HandCannonReloadPlan> plans, Action<HandCannonReloadPlan> onSelected)
{
//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
_onSelected = onSelected;
_openPlans = plans;
_openedAt = Time.unscaledTime;
float height = 90f + (float)plans.Count * 48f + 50f;
((Rect)(ref _windowRect)).width = 560f;
((Rect)(ref _windowRect)).height = height;
((Rect)(ref _windowRect)).x = ((float)Screen.width - ((Rect)(ref _windowRect)).width) * 0.5f;
((Rect)(ref _windowRect)).y = ((float)Screen.height - ((Rect)(ref _windowRect)).height) * 0.5f;
_visible = true;
HandCannonPlugin.Log.LogInfo((object)$"[Reload] picker opened with {plans.Count} option(s). Press 1-{plans.Count} to choose, click a button, or press {HandCannonPlugin.ReloadKeyConfig.Value}/Esc to cancel.");
for (int i = 0; i < plans.Count; i++)
{
HandCannonPlugin.Log.LogInfo((object)$"[Reload] {i + 1}: {plans[i].DisplayLabel}");
}
}
private void OnPlanSelected(HandCannonReloadPlan plan)
{
Action<HandCannonReloadPlan> onSelected = _onSelected;
CloseInternal();
onSelected?.Invoke(plan);
}
private void CloseInternal()
{
_visible = false;
_onSelected = null;
_openPlans = null;
Cursor.lockState = (CursorLockMode)1;
Cursor.visible = false;
}
}
internal static class HandCannonSpawnHelper
{
public static void InitializeSpawnedHandCannon(Item item)
{
if (!HandCannonHelper.IsHandCannon(item))
{
return;
}
RopeShooter component = ((Component)item).GetComponent<RopeShooter>();
if ((Object)(object)component == (Object)null)
{
return;
}
if (HandCannonAmmoHelper.GetLoadedAmmo(item) != HandCannonAmmoType.Empty)
{
HandCannonStateSync.Sync(item, component);
return;
}
if (!component.HasAmmo)
{
HandCannonStateSync.Sync(item, component);
return;
}
if (!HandCannonHelper.CanTagItems())
{
HandCannonStateSync.Sync(item, component);
return;
}
HandCannonAmmoType ammoType;
if (item.itemID == 64)
{
ammoType = HandCannonAmmoType.AntiRope;
}
else
{
float num = Random.Range(0f, 1f);
ammoType = ((num < HandCannonPlugin.PitonSpawnChanceConfig.Value) ? HandCannonAmmoType.Piton : HandCannonAmmoType.NormalRope);
}
int ammo = Mathf.Max(1, component.startAmmo);
HandCannonAmmoHelper.SetLoadedAmmo(item, null, ammoType);
IntItemData data = ((ItemComponent)component).GetData<IntItemData>((DataEntryKey)12, (Func<IntItemData>)(() => ItemDataHelper.CreateIntItemData(ammo)));
data.Value = ammo;
OptionableIntItemData data2 = item.GetData<OptionableIntItemData>((DataEntryKey)2);
if (data2 != null)
{
data2.Value = ammo;
}
item.SetUseRemainingPercentage(1f);
((ItemComponent)component).OnInstanceDataSet();
HandCannonStateSync.Sync(item, component);
HandCannonNetworkSync.PushItemInstanceData(item);
HandCannonNetworkSync.ScheduleSpawnResync(item);
HandCannonPlugin.Log.LogInfo((object)("Hand Cannon " + ((Object)item).name + ": spawned loaded with " + HandCannonAmmoHelper.GetAmmoLabel(ammoType) + "."));
}
}
internal static class PitonShotRegistry
{
private static readonly HashSet<int> PitonAnchorViewIds = new HashSet<int>();
private static readonly HashSet<int> KnownAnchorViewIds = new HashSet<int>();
public static bool MarkNextAnchorAsPiton { get; set; }
public static void Register(int photonViewId)
{
PitonAnchorViewIds.Add(photonViewId);
}
public static bool TryConsume(int photonViewId)
{
return PitonAnchorViewIds.Remove(photonViewId);
}
public static void SnapshotKnownAnchors()
{
KnownAnchorViewIds.Clear();
RopeAnchorProjectile[] array = Resources.FindObjectsOfTypeAll<RopeAnchorProjectile>();
foreach (RopeAnchorProjectile val in array)
{
if ((Object)(object)val?.photonView != (Object)null)
{
KnownAnchorViewIds.Add(val.photonView.ViewID);
}
}
}
public static bool RegisterNewAnchors()
{
bool result = false;
RopeAnchorProjectile[] array = Resources.FindObjectsOfTypeAll<RopeAnchorProjectile>();
foreach (RopeAnchorProjectile val in array)
{
if (!((Object)(object)val?.photonView == (Object)null))
{
int viewID = val.photonView.ViewID;
if (KnownAnchorViewIds.Add(viewID))
{
Register(viewID);
result = true;
}
}
}
return result;
}
public static void ClearPendingMark()
{
MarkNextAnchorAsPiton = false;
}
}
internal static class PitonPrefabCache
{
public static string PrefabPath { get; private set; }
public static bool EnsureInitialized(ManualLogSource logger)
{
if (!string.IsNullOrEmpty(PrefabPath))
{
return true;
}
GameObject obj = Resources.Load<GameObject>("0_Items/Piton");
if (TryFromClimbingSpikeComponent((obj != null) ? obj.GetComponent<ClimbingSpikeComponent>() : null, logger))
{
return true;
}
GameObject[] array = Resources.LoadAll<GameObject>("0_Items/");
if (array != null)
{
GameObject[] array2 = array;
foreach (GameObject val in array2)
{
if (TryFromClimbingSpikeComponent(val.GetComponent<ClimbingSpikeComponent>(), logger))
{
return true;
}
}
}
ClimbingSpikeComponent[] array3 = Resources.FindObjectsOfTypeAll<ClimbingSpikeComponent>();
foreach (ClimbingSpikeComponent component in array3)
{
if (TryFromClimbingSpikeComponent(component, logger))
{
return true;
}
}
logger.LogWarning((object)"Could not resolve piton prefab yet.");
return false;
}
private static bool TryFromClimbingSpikeComponent(ClimbingSpikeComponent component, ManualLogSource logger)
{
if ((Object)(object)component?.hammeredVersionPrefab == (Object)null)
{
return false;
}
PrefabPath = "0_Items/" + ((Object)component.hammeredVersionPrefab).name;
logger.LogInfo((object)("Resolved piton prefab: " + PrefabPath));
return true;
}
}
internal static class PitonPlacementHelper
{
public static void GetPlacement(RopeAnchorWithRope anchor, out Vector3 point, out Vector3 normal)
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: 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: 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_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: 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_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: 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_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_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00f8: 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_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: 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_0118: 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_013a: 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)
point = ((Component)anchor).transform.position;
normal = -((Component)anchor).transform.up;
int num = LayerMask.op_Implicit(HelperExtensions.ToLayerMask((LayerType)1));
Vector3[] array = (Vector3[])(object)new Vector3[8]
{
-((Component)anchor).transform.forward,
((Component)anchor).transform.forward,
-((Component)anchor).transform.up,
((Component)anchor).transform.up,
-((Component)anchor).transform.right,
((Component)anchor).transform.right,
Vector3.down,
Vector3.up
};
Vector3[] array2 = array;
RaycastHit val2 = default(RaycastHit);
for (int i = 0; i < array2.Length; i++)
{
Vector3 val = array2[i];
if (!(((Vector3)(ref val)).sqrMagnitude < 0.0001f))
{
Vector3 normalized = ((Vector3)(ref val)).normalized;
if (Physics.Raycast(point + normalized * 0.15f, -normalized, ref val2, 0.75f, num, (QueryTriggerInteraction)0))
{
point = ((RaycastHit)(ref val2)).point;
normal = ((RaycastHit)(ref val2)).normal;
break;
}
}
}
}
}
internal static class HandCannonAntiFireContext
{
private static readonly Dictionary<int, HandCannonFireSwapState> ActiveFireSwaps = new Dictionary<int, HandCannonFireSwapState>();
public static void Begin(RopeShooter shooter, HandCannonFireSwapState swapState)
{
if ((Object)(object)shooter != (Object)null)
{
ActiveFireSwaps[((Object)shooter).GetInstanceID()] = swapState;
}
}
public static bool TryEnd(RopeShooter shooter, out HandCannonFireSwapState swapState)
{
swapState = default(HandCannonFireSwapState);
if ((Object)(object)shooter == (Object)null)
{
return false;
}
int instanceID = ((Object)shooter).GetInstanceID();
if (!ActiveFireSwaps.TryGetValue(instanceID, out swapState))
{
return false;
}
ActiveFireSwaps.Remove(instanceID);
return true;
}
public static bool ShouldApplyAntiGravFallback(RopeShooter shooter)
{
HandCannonFireSwapState value;
return (Object)(object)shooter != (Object)null && ActiveFireSwaps.TryGetValue(((Object)shooter).GetInstanceID(), out value) && value.PendingAntiGravFallback;
}
}
internal struct HandCannonFireSwapState
{
public bool SwappedAntiRopePrefab;
public bool PendingAntiGravFallback;
public GameObject OriginalAnchorPrefab;
public float OriginalLength;
}
internal struct HandCannonFireState
{
public bool IsHandCannon;
public HandCannonAmmoType AmmoType;
}
[HarmonyPatch(typeof(RopeShooter), "OnInstanceDataSet")]
internal static class RopeShooter_OnInstanceDataSet_HandCannonVisual_Patch
{
private static void Postfix(RopeShooter __instance)
{
Item item = HandCannonHelper.GetItem(__instance);
if (HandCannonHelper.IsHandCannon(item))
{
HandCannonStateSync.Sync(item, __instance);
}
}
}
[HarmonyPatch(typeof(RopeShooter), "Sync_Rpc")]
internal static class RopeShooter_Sync_Rpc_HandCannonVisual_Patch
{
private static void Postfix(RopeShooter __instance)
{
Item item = HandCannonHelper.GetItem(__instance);
if (HandCannonHelper.IsHandCannon(item))
{
HandCannonStateSync.Sync(item, __instance);
}
}
}
[HarmonyPatch(typeof(Item), "SetItemInstanceDataRPC")]
internal static class Item_SetItemInstanceDataRPC_HandCannon_Patch
{
private static void Postfix(Item __instance)
{
if (HandCannonHelper.IsHandCannon(__instance))
{
RopeShooter component = ((Component)__instance).GetComponent<RopeShooter>();
if (!((Object)(object)component == (Object)null))
{
HandCannonStateSync.Sync(__instance, component);
}
}
}
}
[HarmonyPatch(typeof(Item), "OnStash")]
internal static class Item_OnStash_HandCannon_Patch
{
private static void Prefix(Item __instance)
{
HandCannonNetworkSync.PreserveAmmoOnStash(__instance);
}
}
[HarmonyPatch(typeof(RunManager), "StartRun")]
internal static class RunManager_StartRun_Patch
{
private static void Postfix()
{
PitonPrefabCache.EnsureInitialized(HandCannonPlugin.Log);
}
}
[HarmonyPatch(typeof(Item), "Start")]
internal static class Item_Start_HandCannon_Patch
{
private static void Postfix(Item __instance)
{
HandCannonSpawnHelper.InitializeSpawnedHandCannon(__instance);
}
}
[HarmonyPatch(typeof(Item), "GetItemName")]
internal static class Item_GetItemName_HandCannon_Patch
{
private static void Postfix(Item __instance, ItemInstanceData data, ref string __result)
{
if (HandCannonHelper.IsHandCannon(__instance))
{
HandCannonAmmoType ammoType = HandCannonAmmoHelper.ResolveLoadedAmmoForName(__instance, data);
__result = HandCannonAmmoHelper.GetDisplayName(ammoType);
}
}
}
[HarmonyPatch(typeof(RopeShooter), "OnPrimaryFinishedCast")]
internal static class RopeShooter_OnPrimaryFinishedCast_HandCannon_Patch
{
private static void CompleteFireAfterCast(RopeShooter shooter, HandCannonFireState state, string stage)
{
//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_00b2: Unknown result type (might be due to invalid IL or missing references)
Item item = HandCannonHelper.GetItem(shooter);
if ((Object)(object)item == (Object)null || !state.IsHandCannon)
{
return;
}
if (state.AmmoType == HandCannonAmmoType.Piton && !PitonShotRegistry.RegisterNewAnchors())
{
HandCannonPlugin.Log.LogWarning((object)("[Fire] piton shot fired but no anchor registered (" + stage + ")."));
}
object obj;
if (!shooter.HasAmmo)
{
Optionable<byte> valueOrDefault = (item.holderCharacter?.refs?.items?.currentSelectedSlot).GetValueOrDefault();
if (valueOrDefault.IsSome)
{
Character holderCharacter = item.holderCharacter;
if ((Object)(object)((holderCharacter != null) ? holderCharacter.player : null) != (Object)null)
{
obj = item.holderCharacter.player.GetItemSlot(valueOrDefault.Value);
goto IL_0104;
}
}
obj = null;
goto IL_0104;
}
goto IL_0128;
IL_0104:
ItemSlot slot = (ItemSlot)obj;
HandCannonAmmoHelper.SetLoadedAmmo(item, slot, HandCannonAmmoType.Empty);
HandCannonStateSync.Sync(item, shooter);
HandCannonNetworkSync.PushAmmoState(item, slot, item.holderCharacter);
goto IL_0128;
IL_0128:
PitonShotRegistry.ClearPendingMark();
}
private static void Prefix(RopeShooter __instance, ref HandCannonFireState __state)
{
__state = default(HandCannonFireState);
Item item = HandCannonHelper.GetItem(__instance);
if (!HandCannonHelper.IsHandCannon(item))
{
return;
}
__state.IsHandCannon = true;
__state.AmmoType = HandCannonAmmoHelper.GetLoadedAmmo(item);
PitonShotRegistry.SnapshotKnownAnchors();
PitonShotRegistry.MarkNextAnchorAsPiton = __state.AmmoType == HandCannonAmmoType.Piton;
if (__state.AmmoType == HandCannonAmmoType.Piton)
{
return;
}
HandCannonFireSwapState swapState = new HandCannonFireSwapState
{
OriginalAnchorPrefab = __instance.ropeAnchorWithRopePref,
OriginalLength = __instance.length
};
if (__state.AmmoType == HandCannonAmmoType.NormalRope)
{
if (item.itemID == 64)
{
if (!NormalRopeCannonReference.TryGetShooter(out var shooter) || (Object)(object)shooter.ropeAnchorWithRopePref == (Object)null)
{
HandCannonPlugin.Log.LogWarning((object)"[Fire] normal rope anchor unavailable on anti-grav Hand Cannon; shot may still be anti-grav.");
return;
}
swapState.SwappedAntiRopePrefab = true;
__instance.ropeAnchorWithRopePref = shooter.ropeAnchorWithRopePref;
__instance.length = shooter.length;
HandCannonAntiFireContext.Begin(__instance, swapState);
HandCannonPlugin.Log.LogInfo((object)"[Fire] normal rope shot via swapped anchor on anti-grav Hand Cannon.");
}
}
else
{
if (__state.AmmoType != HandCannonAmmoType.AntiRope)
{
return;
}
if (item.itemID == 64)
{
swapState.PendingAntiGravFallback = true;
HandCannonAntiFireContext.Begin(__instance, swapState);
return;
}
GameObject anchorPrefab = AntiRopeCannonReference.GetAnchorPrefab();
if ((Object)(object)anchorPrefab == (Object)null || !AntiRopeCannonReference.TryGetShooter(out var shooter2))
{
swapState.PendingAntiGravFallback = true;
HandCannonAntiFireContext.Begin(__instance, swapState);
HandCannonPlugin.Log.LogWarning((object)"[Fire] anti anchor unavailable; using antigrav rope fallback.");
}
else
{
swapState.SwappedAntiRopePrefab = true;
__instance.ropeAnchorWithRopePref = anchorPrefab;
__instance.length = shooter2.length;
HandCannonAntiFireContext.Begin(__instance, swapState);
HandCannonPlugin.Log.LogInfo((object)"[Fire] anti-grav rope shot via swapped anchor prefab.");
}
}
}
private static void Postfix(RopeShooter __instance, HandCannonFireState __state)
{
if (__state.IsHandCannon)
{
Item item = HandCannonHelper.GetItem(__instance);
RestoreAntiSwap(__instance, clearLoadedState: false);
HandCannonFireHelper.ConsumeFiredShot(__instance, item);
CompleteFireAfterCast(__instance, __state, "Postfix");
}
}
[HarmonyFinalizer]
private static Exception Finalizer(Exception __exception, RopeShooter __instance, ref HandCannonFireState __state)
{
if (__exception != null)
{
HandCannonPlugin.Log.LogWarning((object)("[Fire] OnPrimaryFinishedCast threw: " + __exception.GetType().Name + ": " + __exception.Message));
RestoreAntiSwap(__instance, clearLoadedState: false);
}
if (__state.IsHandCannon)
{
Item item = HandCannonHelper.GetItem(__instance);
HandCannonFireHelper.ConsumeFiredShot(__instance, item);
}
CompleteFireAfterCast(__instance, __state, "Finalizer");
return null;
}
private static void RestoreAntiSwap(RopeShooter shooter, bool clearLoadedState)
{
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
if (!HandCannonAntiFireContext.TryEnd(shooter, out var swapState))
{
return;
}
if (swapState.SwappedAntiRopePrefab)
{
shooter.ropeAnchorWithRopePref = swapState.OriginalAnchorPrefab;
shooter.length = swapState.OriginalLength;
}
if (!clearLoadedState)
{
return;
}
Item item = HandCannonHelper.GetItem(shooter);
Optionable<byte> valueOrDefault = ((item == null) ? ((Optionable<byte>?)null) : item.holderCharacter?.refs?.items?.currentSelectedSlot).GetValueOrDefault();
object obj2;
if (valueOrDefault.IsSome)
{
object obj;
if (item == null)
{
obj = null;
}
else
{
Character holderCharacter = item.holderCharacter;
obj = ((holderCharacter != null) ? holderCharacter.player : null);
}
if ((Object)obj != (Object)null)
{
obj2 = item.holderCharacter.player.GetItemSlot(valueOrDefault.Value);
goto IL_00fb;
}
}
obj2 = null;
goto IL_00fb;
IL_00fb:
ItemSlot slot = (ItemSlot)obj2;
HandCannonAmmoHelper.SetLoadedAmmo(item, slot, HandCannonAmmoType.Empty);
HandCannonStateSync.Sync(item, shooter);
}
}
[HarmonyPatch(typeof(RopeAnchorProjectile), "GetShot")]
internal static class RopeAnchorProjectile_GetShot_HandCannon_Patch
{
private static void Prefix(RopeAnchorProjectile __instance)
{
if (PitonShotRegistry.MarkNextAnchorAsPiton && (Object)(object)__instance?.photonView != (Object)null)
{
PitonShotRegistry.Register(__instance.photonView.ViewID);
}
}
private static void Postfix(RopeAnchorProjectile __instance)
{
RopeShooter val = FindSourceShooter();
if (!((Object)(object)val == (Object)null) && HandCannonAntiFireContext.ShouldApplyAntiGravFallback(val))
{
Rope componentInChildren = ((Component)__instance).GetComponentInChildren<Rope>(true);
if ((Object)(object)componentInChildren == (Object)null)
{
HandCannonPlugin.Log.LogWarning((object)"[Fire] anti-grav fallback failed: rope not found on anchor.");
}
else
{
componentInChildren.antigrav = true;
}
}
}
private static RopeShooter FindSourceShooter()
{
Character localCharacter = Character.localCharacter;
object obj;
if (localCharacter == null)
{
obj = null;
}
else
{
CharacterData data = localCharacter.data;
obj = ((data != null) ? data.currentItem : null);
}
Item val = (Item)obj;
if ((Object)(object)val == (Object)null || !HandCannonHelper.IsHandCannon(val))
{
return null;
}
return ((Component)val).GetComponent<RopeShooter>();
}
}
[HarmonyPatch(typeof(RopeAnchorWithRope), "SpawnRope")]
internal static class RopeAnchorWithRope_SpawnRope_HandCannon_Patch
{
private static bool Prefix(RopeAnchorWithRope __instance, ref Rope __result)
{
//IL_0071: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
if (!((MonoBehaviourPun)__instance).photonView.IsMine || !PitonShotRegistry.TryConsume(((MonoBehaviourPun)__instance).photonView.ViewID))
{
return true;
}
ManualLogSource log = HandCannonPlugin.Log;
if (log == null || !PitonPrefabCache.EnsureInitialized(log))
{
if (log != null)
{
log.LogWarning((object)"[Fire] piton prefab unavailable; falling back to rope.");
}
return true;
}
try
{
PitonPlacementHelper.GetPlacement(__instance, out var point, out var normal);
PhotonNetwork.Instantiate(PitonPrefabCache.PrefabPath, point, Quaternion.LookRotation(-normal, Vector3.up), (byte)0, (object[])null);
PhotonNetwork.Destroy(((Component)__instance).gameObject);
log.LogInfo((object)$"[Fire] placed piton at {point}");
}
catch (Exception ex)
{
log.LogError((object)("[Fire] piton placement failed: " + ex.Message));
return true;
}
__result = null;
return false;
}
}
[HarmonyPatch(typeof(Action_ReduceUses), "RunAction")]
internal static class Action_ReduceUses_RunAction_HandCannon_Patch
{
private static bool Prefix(Action_ReduceUses __instance)
{
Item actionItem = HandCannonHelper.GetActionItem((ItemActionBase)(object)__instance);
if (!HandCannonHelper.IsHandCannon(actionItem))
{
return true;
}
return false;
}
}
[HarmonyPatch(typeof(Item), "ConsumeDelayed")]
internal static class Item_ConsumeDelayed_HandCannon_Patch
{
private static bool Prefix(Item __instance)
{
if (!HandCannonHelper.IsHandCannon(__instance))
{
return true;
}
HandCannonPlugin.Log.LogInfo((object)("Blocked ConsumeDelayed for Hand Cannon " + ((Object)__instance).name));
return false;
}
}