using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using TMPro;
using TerminalLoadouts.Core;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.UI;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("TerminalLoadouts")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.4.0")]
[assembly: AssemblyInformationalVersion("1.1.4")]
[assembly: AssemblyProduct("TerminalLoadouts")]
[assembly: AssemblyTitle("TerminalLoadouts")]
[assembly: AssemblyVersion("1.1.4.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace TerminalLoadouts
{
internal static class BrutalV1Compatibility
{
internal const string PluginId = "com.potpot.brutalv1";
private static Action<NewMovement> original;
private static MethodInfo update;
private static HarmonyMethod originalPatch;
private static string owner;
internal static void Install(Harmony harmony)
{
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_0124: Unknown result type (might be due to invalid IL or missing references)
//IL_0130: Unknown result type (might be due to invalid IL or missing references)
//IL_013c: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: Expected O, but got Unknown
//IL_0180: Unknown result type (might be due to invalid IL or missing references)
//IL_0185: Unknown result type (might be due to invalid IL or missing references)
//IL_0191: Unknown result type (might be due to invalid IL or missing references)
//IL_019d: Unknown result type (might be due to invalid IL or missing references)
//IL_01b1: Expected O, but got Unknown
if (!Chainloader.PluginInfos.TryGetValue("com.potpot.brutalv1", out var value))
{
return;
}
try
{
Type type = ((object)value.Instance).GetType().Assembly.GetType("NewMovementUpdatePatch");
MethodInfo method = ((type == null) ? null : AccessTools.DeclaredMethod(type, "Postfix", new Type[1] { typeof(NewMovement) }, (Type[])null));
if (method == null || !method.IsStatic || method.ReturnType != typeof(void))
{
throw new InvalidOperationException("Unsupported BrutalV1 movement patch signature.");
}
update = AccessTools.DeclaredMethod(typeof(NewMovement), "Update", (Type[])null, (Type[])null);
Patch val = ((IEnumerable<Patch>)Harmony.GetPatchInfo((MethodBase)update)?.Postfixes).SingleOrDefault((Func<Patch, bool>)((Patch p) => p.PatchMethod == method));
if (val == null)
{
throw new InvalidOperationException("BrutalV1 movement callback is not registered.");
}
original = (Action<NewMovement>)Delegate.CreateDelegate(typeof(Action<NewMovement>), method);
originalPatch = new HarmonyMethod(method)
{
priority = val.priority,
before = val.before,
after = val.after
};
owner = val.owner;
harmony.Unpatch((MethodBase)update, method);
try
{
harmony.Patch((MethodBase)update, (HarmonyMethod)null, new HarmonyMethod(typeof(BrutalV1Compatibility), "MovementPostfix", (Type[])null)
{
priority = val.priority,
before = val.before,
after = val.after
}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
}
catch
{
Restore();
throw;
}
Plugin.Log.LogInfo((object)"BrutalV1 movement guard enabled for loadout dialogs.");
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Could not guard BrutalV1 during loadout dialogs: " + ex));
}
}
private static void MovementPostfix(NewMovement __instance)
{
if (!LoadoutDialog.IsOpen)
{
original?.Invoke(__instance);
}
}
internal static void Restore()
{
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
if (originalPatch != null)
{
new Harmony(owner).Patch((MethodBase)update, (HarmonyMethod)null, originalPatch, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
originalPatch = null;
}
}
}
internal sealed class EquipmentIcons
{
private readonly ShopZone shop;
private readonly Dictionary<int, Sprite> sprites = new Dictionary<int, Sprite>();
private readonly HashSet<int> warned = new HashSet<int>();
internal EquipmentIcons(ShopZone shop)
{
this.shop = shop;
}
internal Sprite Get(int index, int selection)
{
int num = index * 3 + selection;
if (sprites.TryGetValue(num, out var value) && Object.op_Implicit((Object)(object)value))
{
return value;
}
try
{
Sprite val = null;
if (index < 15)
{
GunSetter instance = MonoSingleton<GunSetter>.Instance;
if (!Object.op_Implicit((Object)(object)instance))
{
return null;
}
AssetReference[] array = (new AssetReference[15][]
{
instance.revolverPierce, instance.revolverTwirl, instance.revolverRicochet, instance.shotgunGrenade, instance.shotgunPump, instance.shotgunRed, instance.nailMagnet, instance.nailOverheat, instance.nailRed, instance.railCannon,
instance.railHarpoon, instance.railMalicious, instance.rocketBlue, instance.rocketGreen, instance.rocketRed
})[index];
int num2 = selection - 1;
if (array != null && num2 >= 0 && num2 < array.Length)
{
GameObject val2 = AddressablesExtensions.ToAsset(array[num2]);
WeaponIcon val3 = (Object.op_Implicit((Object)(object)val2) ? val2.GetComponent<WeaponIcon>() : null);
if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)val3.weaponDescriptor))
{
val = val3.weaponDescriptor.icon;
}
}
}
else
{
VariationInfo val4 = ((IEnumerable<VariationInfo>)((Component)shop).GetComponentsInChildren<VariationInfo>(true)).FirstOrDefault((Func<VariationInfo, bool>)((VariationInfo item) => item.weaponName == Catalog.Keys[index]));
if (Object.op_Implicit((Object)(object)val4) && Object.op_Implicit((Object)(object)val4.icon))
{
val = val4.icon.sprite;
}
}
if (Object.op_Implicit((Object)(object)val))
{
sprites[num] = val;
}
return val;
}
catch (Exception ex)
{
if (warned.Add(num))
{
Plugin.Log.LogWarning((object)("Icon unavailable for " + Catalog.Keys[index] + ": " + ex.Message));
}
return null;
}
}
internal static Color ColorFor(int index)
{
//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)
int num = ((index < 15) ? (index % 3) : (index - 15));
switch (index)
{
case 1:
num = 2;
break;
case 2:
num = 1;
break;
case 16:
num = 2;
break;
case 17:
num = 1;
break;
}
ColorBlindSettings instance = MonoSingleton<ColorBlindSettings>.Instance;
if (!Object.op_Implicit((Object)(object)instance) || instance.variationColors == null || num >= instance.variationColors.Length)
{
return Color.white;
}
return instance.variationColors[num];
}
}
internal sealed class GameEquipment : IEquipmentRuntime
{
private readonly PrefsManager prefs;
private readonly GunSetter setter;
private readonly FistControl fists;
private readonly GunControl guns;
private string selectedName;
private int selectedSlot;
private bool wasActivated;
private readonly GrenadeLauncherCompatibility grenades;
public bool Restricted
{
get
{
if (setter.forcedLoadout == null)
{
return fists.forcedLoadout != null;
}
return true;
}
}
public GameEquipment()
{
prefs = MonoSingleton<PrefsManager>.Instance;
setter = MonoSingleton<GunSetter>.Instance;
fists = MonoSingleton<FistControl>.Instance;
guns = MonoSingleton<GunControl>.Instance;
if (!Object.op_Implicit((Object)(object)prefs) || !Object.op_Implicit((Object)(object)setter) || !Object.op_Implicit((Object)(object)fists) || !Object.op_Implicit((Object)(object)guns) || guns.slots.Count < 5)
{
throw new InvalidOperationException("Player equipment is not ready yet.");
}
grenades = new GrenadeLauncherCompatibility();
}
public int GetInt(string key, int fallback)
{
return prefs.GetInt(key, fallback);
}
public string GetString(string key, string fallback)
{
return prefs.GetString(key, fallback);
}
public bool HasKey(string key)
{
return prefs.HasKey(key);
}
public void SetInt(string key, int value)
{
prefs.SetInt(key, value);
}
public void SetString(string key, string value)
{
prefs.SetString(key, value);
}
public void DeleteKey(string key)
{
prefs.DeleteKey(key);
}
public int Gear(string id)
{
return GameProgressSaver.CheckGear(id);
}
public bool[] CaptureGrenadeModes()
{
return grenades.Capture();
}
public void SetGrenadeModes(bool[] modes)
{
grenades.Apply(modes);
}
public void RememberSelection()
{
selectedName = (Object.op_Implicit((Object)(object)guns.currentWeapon) ? ((Object)guns.currentWeapon).name : null);
selectedSlot = guns.currentSlotIndex - 1;
wasActivated = guns.activated;
}
public void ResetWeapons()
{
setter.ResetWeapons(false);
}
public void ResetFists()
{
fists.ResetFists();
}
public void RestoreSelection()
{
GameObject target = guns.slots.SelectMany((List<GameObject> s) => s).FirstOrDefault((Func<GameObject, bool>)((GameObject w) => Object.op_Implicit((Object)(object)w) && ((Object)w).name == selectedName));
if (!Object.op_Implicit((Object)(object)target) && selectedSlot >= 0 && selectedSlot < guns.slots.Count)
{
target = ((IEnumerable<GameObject>)guns.slots[selectedSlot]).FirstOrDefault((Func<GameObject, bool>)((GameObject w) => Object.op_Implicit((Object)(object)w)));
}
if (!Object.op_Implicit((Object)(object)target))
{
target = guns.slots.SelectMany((List<GameObject> s) => s).FirstOrDefault((Func<GameObject, bool>)((GameObject w) => Object.op_Implicit((Object)(object)w)));
}
if (Object.op_Implicit((Object)(object)guns.currentWeapon))
{
guns.currentWeapon.SetActive(false);
}
guns.currentWeapon = null;
foreach (GameObject item in guns.slots.SelectMany((List<GameObject> s) => s))
{
if (Object.op_Implicit((Object)(object)item))
{
item.SetActive(false);
}
}
if (Object.op_Implicit((Object)(object)target))
{
int num = guns.slots.FindIndex((List<GameObject> s) => s.Contains(target));
guns.SwitchWeapon(num + 1, (int?)guns.slots[num].IndexOf(target), false, false, false);
if (!wasActivated)
{
guns.NoWeapon();
}
}
else
{
guns.currentSlotIndex = 1;
guns.currentVariationIndex = 0;
guns.noWeapons = true;
}
guns.activated = wasActivated;
}
}
internal sealed class GrenadeLauncherCompatibility
{
internal const string PluginId = "docvalentyne.ultrakill.grenadelauncher";
private readonly BaseUnityPlugin instance;
private readonly MethodInfo get;
private readonly MethodInfo set;
internal static bool IsLoaded
{
get
{
if (Chainloader.PluginInfos.TryGetValue("docvalentyne.ultrakill.grenadelauncher", out var value) && Object.op_Implicit((Object)(object)value.Instance))
{
return ((Behaviour)value.Instance).isActiveAndEnabled;
}
return false;
}
}
internal GrenadeLauncherCompatibility()
{
if (Chainloader.PluginInfos.TryGetValue("docvalentyne.ultrakill.grenadelauncher", out var value) && Object.op_Implicit((Object)(object)value.Instance) && ((Behaviour)value.Instance).isActiveAndEnabled)
{
instance = value.Instance;
Type type = ((object)instance).GetType();
get = type.GetMethod("IsGrenadeModeEnabled", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(int) }, null);
set = type.GetMethod("SetGrenadeModeEnabled", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2]
{
typeof(int),
typeof(bool)
}, null);
if (get == null || get.ReturnType != typeof(bool) || set == null || set.ReturnType != typeof(void))
{
throw new InvalidOperationException("This Grenade Launcher version is unsupported. Loadouts were not changed; compatibility was verified with 2.0.2.");
}
}
}
internal bool[] Capture()
{
if (!Object.op_Implicit((Object)(object)instance))
{
return null;
}
bool[] array = new bool[3];
for (int i = 0; i < array.Length; i++)
{
array[i] = (bool)Invoke(get, i);
}
return array;
}
internal void Apply(bool[] modes)
{
if (!Object.op_Implicit((Object)(object)instance))
{
throw new InvalidOperationException("Grenade Launcher is no longer available.");
}
if (modes == null || modes.Length != 3)
{
throw new ArgumentException("Expected three grenade modes.");
}
for (int i = 0; i < modes.Length; i++)
{
Invoke(set, i, modes[i]);
}
for (int j = 0; j < modes.Length; j++)
{
if ((bool)Invoke(get, j) != modes[j])
{
throw new InvalidOperationException("Grenade Launcher did not accept the saved selection.");
}
}
}
private object Invoke(MethodInfo method, params object[] args)
{
try
{
return method.Invoke(instance, args);
}
catch (TargetInvocationException ex)
{
throw new InvalidOperationException("Grenade Launcher selection failed: " + (ex.InnerException ?? ex).Message, ex.InnerException ?? ex);
}
}
}
internal sealed class LoadoutDialog : MonoBehaviour
{
private static LoadoutDialog current;
private const string StateKey = "local.terminal-loadouts.dialog";
private readonly List<EventSystem> suspendedSystems = new List<EventSystem>();
private EventSystem previousSystem;
private EventSystem modalSystem;
private GameObject previousSelection;
private CursorLockMode previousLock;
private bool previousVisible;
private bool closed;
private TMP_Text template;
private TMP_Text notice;
private TMP_InputField input;
private RectTransform panel;
private Action<string> accept;
private bool colorMode;
private Image sample;
private Slider[] channels;
private TMP_Text[] channelLabels;
private Button save;
private int openedFrame;
private ActionSuspension<InputAction> gameplayInput;
internal static bool IsOpen => (Object)(object)current != (Object)null;
private static LoadoutDialog Create(TMP_Text template, string title, int height, Action<string> accept)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Expected O, but got Unknown
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Unknown result type (might be due to invalid IL or missing references)
//IL_014e: Unknown result type (might be due to invalid IL or missing references)
//IL_0153: Unknown result type (might be due to invalid IL or missing references)
//IL_0154: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_015d: Unknown result type (might be due to invalid IL or missing references)
//IL_015e: Unknown result type (might be due to invalid IL or missing references)
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
//IL_017a: Unknown result type (might be due to invalid IL or missing references)
//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
//IL_01fb: Expected O, but got Unknown
//IL_022f: Unknown result type (might be due to invalid IL or missing references)
//IL_0234: Unknown result type (might be due to invalid IL or missing references)
//IL_0236: Unknown result type (might be due to invalid IL or missing references)
//IL_023b: Unknown result type (might be due to invalid IL or missing references)
//IL_023d: Unknown result type (might be due to invalid IL or missing references)
//IL_0242: Unknown result type (might be due to invalid IL or missing references)
//IL_0244: Unknown result type (might be due to invalid IL or missing references)
//IL_0249: Unknown result type (might be due to invalid IL or missing references)
//IL_0256: Expected O, but got Unknown
if (IsOpen)
{
throw new InvalidOperationException("A loadout dialog is already open.");
}
GameObject val = new GameObject("TerminalLoadouts Dialog", new Type[1] { typeof(RectTransform) });
val.SetActive(false);
LoadoutDialog loadoutDialog = val.AddComponent<LoadoutDialog>();
try
{
current = loadoutDialog;
loadoutDialog.template = template;
loadoutDialog.accept = accept;
loadoutDialog.openedFrame = Time.frameCount;
loadoutDialog.previousSystem = EventSystem.current;
loadoutDialog.previousSelection = (Object.op_Implicit((Object)(object)EventSystem.current) ? EventSystem.current.currentSelectedGameObject : null);
loadoutDialog.previousLock = Cursor.lockState;
loadoutDialog.previousVisible = Cursor.visible;
Canvas obj = val.AddComponent<Canvas>();
obj.renderMode = (RenderMode)0;
obj.sortingOrder = 30000;
CanvasScaler obj2 = val.AddComponent<CanvasScaler>();
obj2.uiScaleMode = (ScaleMode)1;
obj2.referenceResolution = new Vector2(960f, 540f);
obj2.matchWidthOrHeight = 0.5f;
val.AddComponent<GraphicRaycaster>();
((Graphic)val.AddComponent<Image>()).color = new Color(0f, 0f, 0f, 0.85f);
loadoutDialog.panel = TerminalUi.Rect("Dialog", val.transform, 0f, 0f, 540f, height);
RectTransform obj3 = loadoutDialog.panel;
RectTransform obj4 = loadoutDialog.panel;
Vector2 val2 = (loadoutDialog.panel.pivot = new Vector2(0.5f, 0.5f));
Vector2 anchorMin = (obj4.anchorMax = val2);
obj3.anchorMin = anchorMin;
((Graphic)((Component)loadoutDialog.panel).gameObject.AddComponent<Image>()).color = LoadoutTheme.Panel;
((Graphic)loadoutDialog.Text((Transform)(object)loadoutDialog.panel, title, 20f, 12f, 500f, 35f, 26)).color = LoadoutTheme.Accent;
EventSystem[] array = Object.FindObjectsOfType<EventSystem>();
foreach (EventSystem val5 in array)
{
if (((Behaviour)val5).enabled)
{
loadoutDialog.suspendedSystems.Add(val5);
((Behaviour)val5).enabled = false;
}
}
GameObject val6 = new GameObject("Dialog Input");
val6.transform.SetParent(val.transform, false);
loadoutDialog.modalSystem = val6.AddComponent<EventSystem>();
val6.AddComponent<InputSystemUIInputModule>().AssignDefaultActions();
GameStateManager.Instance.RegisterState(new GameState("local.terminal-loadouts.dialog", val)
{
playerInputLock = (LockMode)1,
cameraInputLock = (LockMode)1,
cursorLock = (LockMode)2,
priority = 100
});
return loadoutDialog;
}
catch
{
loadoutDialog.Close();
throw;
}
}
internal static LoadoutDialog ShowRename(TMP_Text template, string value, Action<string> accept)
{
LoadoutDialog dialog = Create(template, "RENAME LOADOUT", 230, accept);
try
{
dialog.Text((Transform)(object)dialog.panel, "Up to 32 characters. Enter saves; Escape cancels.", 20f, 52f, 500f, 25f, 16);
dialog.input = dialog.Field("Name", 20f, 92f, 500f, 32, value);
((UnityEvent<string>)(object)dialog.input.onSubmit).AddListener((UnityAction<string>)delegate
{
dialog.Submit();
});
dialog.AddButtons(168);
dialog.Activate(focusText: true);
return dialog;
}
catch
{
dialog.Close();
throw;
}
}
internal static LoadoutDialog ShowColor(TMP_Text template, string value, Action<string> accept)
{
//IL_00e6: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_0109: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: 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_011a: Unknown result type (might be due to invalid IL or missing references)
//IL_011b: Unknown result type (might be due to invalid IL or missing references)
//IL_0125: Unknown result type (might be due to invalid IL or missing references)
//IL_012f: Unknown result type (might be due to invalid IL or missing references)
LoadoutDialog dialog = Create(template, "LOADOUT SLOT COLOR", 430, accept);
try
{
dialog.colorMode = true;
dialog.Text((Transform)(object)dialog.panel, "Choose a palette color, adjust RGB, or enter #RRGGBB.", 20f, 50f, 500f, 25f, 16);
Color val = default(Color);
for (int i = 0; i < Catalog.Palette.Length; i++)
{
string hex = Catalog.Palette[i];
ColorUtility.TryParseHtmlString("#" + hex, ref val);
Button obj = dialog.Button((Transform)(object)dialog.panel, "", 20 + i % 10 * 50, 82 + i / 10 * 43, 42f, 35f, delegate
{
dialog.SetColor(hex);
});
ColorBlock colors = ((Selectable)obj).colors;
((ColorBlock)(ref colors)).normalColor = val;
Color highlightedColor = (((ColorBlock)(ref colors)).selectedColor = Color.Lerp(val, Color.white, 0.25f));
((ColorBlock)(ref colors)).highlightedColor = highlightedColor;
((ColorBlock)(ref colors)).pressedColor = Color.Lerp(val, Color.black, 0.25f);
((Selectable)obj).colors = colors;
}
dialog.sample = ((Component)TerminalUi.Rect("Preview", (Transform)(object)dialog.panel, 20f, 181f, 95f, 114f)).gameObject.AddComponent<Image>();
dialog.Text((Transform)(object)dialog.panel, "PREVIEW", 20f, 296f, 95f, 20f, 12).alignment = (TextAlignmentOptions)514;
dialog.channels = (Slider[])(object)new Slider[3];
dialog.channelLabels = (TMP_Text[])(object)new TMP_Text[3];
for (int num = 0; num < 3; num++)
{
dialog.Text((Transform)(object)dialog.panel, (new string[3] { "R", "G", "B" })[num], 135f, 179 + num * 39, 20f, 25f, 18);
dialog.channelLabels[num] = dialog.Text((Transform)(object)dialog.panel, "", 477f, 179 + num * 39, 42f, 25f, 16);
dialog.channels[num] = dialog.Channel(160f, 182 + num * 39);
((UnityEvent<float>)(object)dialog.channels[num].onValueChanged).AddListener((UnityAction<float>)delegate
{
dialog.ReadChannels();
});
}
dialog.Text((Transform)(object)dialog.panel, "HEX", 135f, 306f, 45f, 35f, 18);
dialog.input = dialog.Field("Hex", 182f, 304f, 180f, 7, "#" + value);
((UnityEvent<string>)(object)dialog.input.onValueChanged).AddListener((UnityAction<string>)dialog.ReadHex);
dialog.notice = dialog.Text((Transform)(object)dialog.panel, "", 20f, 346f, 500f, 22f, 14);
dialog.AddButtons(380);
dialog.SetColor(value);
dialog.Activate(focusText: false);
return dialog;
}
catch
{
dialog.Close();
throw;
}
}
private void Activate(bool focusText)
{
InputManager manager = MonoSingleton<InputManager>.Instance;
if (!Object.op_Implicit((Object)(object)manager) || manager.InputSource == null)
{
throw new InvalidOperationException("Gameplay input is not ready for a dialog.");
}
PlayerInput source = manager.InputSource;
gameplayInput = ActionSuspension<InputAction>.Suspend((IEnumerable<InputAction>)source.Actions.asset, (InputAction action) => action.enabled, delegate(InputAction action)
{
action.Disable();
}, delegate(InputAction action)
{
if (Object.op_Implicit((Object)(object)manager) && manager.InputSource == source)
{
action.Enable();
}
});
((Component)this).gameObject.SetActive(true);
EventSystem.current = modalSystem;
Cursor.lockState = (CursorLockMode)0;
Cursor.visible = true;
if (focusText)
{
((MonoBehaviour)this).StartCoroutine(FocusAfterOpeningClick());
}
else
{
modalSystem.SetSelectedGameObject(((Component)save).gameObject);
}
}
private IEnumerator FocusAfterOpeningClick()
{
yield return null;
while (Mouse.current != null && Mouse.current.leftButton.isPressed)
{
yield return null;
}
yield return null;
if (!closed && Object.op_Implicit((Object)(object)input))
{
modalSystem.SetSelectedGameObject(((Component)input).gameObject);
((Selectable)input).Select();
input.ActivateInputField();
}
}
private TMP_InputField Field(string name, float x, float y, float width, int limit, string value)
{
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
RectTransform val = TerminalUi.Rect(name, (Transform)(object)panel, x, y, width, 40f);
Image val2 = ((Component)val).gameObject.AddComponent<Image>();
((Graphic)val2).color = new Color(0.1f, 0.19f, 0.21f);
RectTransform val3 = TerminalUi.Rect("Viewport", (Transform)(object)val, 8f, 3f, width - 16f, 34f);
((Component)val3).gameObject.AddComponent<RectMask2D>();
TMP_Text val4 = Text((Transform)(object)val3, "", 0f, 0f, width - 16f, 34f, 22);
val4.enableWordWrapping = false;
TMP_InputField obj = ((Component)val).gameObject.AddComponent<TMP_InputField>();
obj.textViewport = val3;
obj.textComponent = val4;
((Selectable)obj).targetGraphic = (Graphic)(object)val2;
obj.characterLimit = limit;
obj.lineType = (LineType)0;
obj.richText = false;
obj.customCaretColor = true;
obj.caretColor = LoadoutTheme.Accent;
obj.caretWidth = 2;
obj.text = value;
return obj;
}
private TMP_Text Text(Transform parent, string value, float x, float y, float width, float height, int size)
{
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
TextMeshProUGUI obj = ((Component)TerminalUi.Rect("Text", parent, x, y, width, height)).gameObject.AddComponent<TextMeshProUGUI>();
((TMP_Text)obj).font = template.font;
((TMP_Text)obj).fontSharedMaterial = template.fontSharedMaterial;
((TMP_Text)obj).fontSize = size;
((TMP_Text)obj).text = value;
((Graphic)obj).color = Color.white;
((TMP_Text)obj).richText = false;
((Graphic)obj).raycastTarget = false;
((TMP_Text)obj).alignment = (TextAlignmentOptions)4097;
return (TMP_Text)(object)obj;
}
private Button Button(Transform parent, string value, float x, float y, float width, float height, Action action)
{
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Expected O, but got Unknown
RectTransform val = TerminalUi.Rect(value, parent, x, y, width, height);
Image image = ((Component)val).gameObject.AddComponent<Image>();
Button obj = ((Component)val).gameObject.AddComponent<Button>();
LoadoutTheme.Style(obj, image);
((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
{
if (Time.frameCount > openedFrame + 1)
{
action();
}
});
if (value.Length > 0)
{
Text((Transform)(object)val, value, 4f, 0f, width - 8f, height, 21).alignment = (TextAlignmentOptions)514;
}
return obj;
}
private void AddButtons(int y)
{
save = Button((Transform)(object)panel, "SAVE", 20f, y, 240f, 35f, Submit);
Button((Transform)(object)panel, "CANCEL", 280f, y, 240f, 35f, Close);
}
private Slider Channel(float x, float y)
{
//IL_0037: 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)
RectTransform val = TerminalUi.Rect("Channel", (Transform)(object)panel, x, y, 300f, 24f);
((Graphic)((Component)val).gameObject.AddComponent<Image>()).color = new Color(0.12f, 0.22f, 0.24f);
RectTransform val2 = TerminalUi.Rect("Handle", (Transform)(object)val, 0f, 0f, 14f, 24f);
Image val3 = ((Component)val2).gameObject.AddComponent<Image>();
((Graphic)val3).color = LoadoutTheme.Accent;
Slider obj = ((Component)val).gameObject.AddComponent<Slider>();
obj.handleRect = val2;
((Selectable)obj).targetGraphic = (Graphic)(object)val3;
obj.minValue = 0f;
obj.maxValue = 255f;
obj.wholeNumbers = true;
return obj;
}
private void ReadChannels()
{
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
SetColor(ColorUtility.ToHtmlStringRGB(new Color(channels[0].value / 255f, channels[1].value / 255f, channels[2].value / 255f)));
}
private void ReadHex(string raw)
{
string text = raw.Trim().TrimStart('#');
bool flag = Catalog.ValidColor(text);
((Selectable)save).interactable = flag;
notice.text = (flag ? "Color changes are saved only when you press SAVE." : "Use six hex digits, for example #28D9E8.");
if (flag)
{
UpdateColor(text);
}
}
private void SetColor(string hex)
{
input.SetTextWithoutNotify("#" + hex);
ReadHex(hex);
}
private void UpdateColor(string hex)
{
//IL_0019: 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_0030: 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)
Color val = default(Color);
ColorUtility.TryParseHtmlString("#" + hex, ref val);
((Graphic)sample).color = val;
float[] array = new float[3] { val.r, val.g, val.b };
for (int i = 0; i < 3; i++)
{
int num = Mathf.RoundToInt(array[i] * 255f);
channels[i].SetValueWithoutNotify((float)num);
channelLabels[i].text = num.ToString();
}
}
private void Update()
{
if (Time.frameCount > openedFrame + 1)
{
if (Keyboard.current != null && ((ButtonControl)Keyboard.current.escapeKey).wasPressedThisFrame)
{
Close();
}
else if (Gamepad.current != null && Gamepad.current.buttonEast.wasPressedThisFrame)
{
Close();
}
else if (Object.op_Implicit((Object)(object)MonoSingleton<OptionsManager>.Instance) && MonoSingleton<OptionsManager>.Instance.paused)
{
Close();
}
}
}
private void Submit()
{
if (!closed && Time.frameCount > openedFrame + 1)
{
string text = (colorMode ? input.text.Trim().TrimStart('#').ToUpperInvariant() : input.text);
if (colorMode && !Catalog.ValidColor(text))
{
ReadHex(input.text);
return;
}
Action<string> action = accept;
Close();
action(text);
}
}
internal void Close()
{
if (!closed)
{
closed = true;
Release();
((Component)this).gameObject.SetActive(false);
Object.Destroy((Object)(object)((Component)this).gameObject);
}
}
private void Release()
{
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)current != (Object)(object)this)
{
return;
}
current = null;
try
{
gameplayInput?.Release();
}
catch (Exception ex)
{
Plugin.Log.LogError((object)ex);
}
gameplayInput = null;
if (Object.op_Implicit((Object)(object)modalSystem))
{
((Component)modalSystem).gameObject.SetActive(false);
}
foreach (EventSystem suspendedSystem in suspendedSystems)
{
if (Object.op_Implicit((Object)(object)suspendedSystem))
{
((Behaviour)suspendedSystem).enabled = true;
}
}
if (Object.op_Implicit((Object)(object)previousSystem) && ((Behaviour)previousSystem).isActiveAndEnabled)
{
EventSystem.current = previousSystem;
previousSystem.SetSelectedGameObject(previousSelection);
}
if (Object.op_Implicit((Object)(object)GameStateManager.Instance))
{
GameStateManager.Instance.PopState("local.terminal-loadouts.dialog");
}
if (!Object.op_Implicit((Object)(object)MonoSingleton<OptionsManager>.Instance) || !MonoSingleton<OptionsManager>.Instance.paused)
{
Cursor.lockState = previousLock;
Cursor.visible = previousVisible;
}
}
private void OnDisable()
{
Release();
}
private void OnDestroy()
{
Release();
}
}
internal static class LoadoutTheme
{
internal static readonly Color Accent = new Color(0.2f, 0.95f, 1f);
internal static readonly Color Panel = new Color(0.015f, 0.08f, 0.095f);
internal static void SlotColor(Button button, Color tint, bool selected)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: 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_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: 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_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
ColorBlock colors = ((Selectable)button).colors;
((ColorBlock)(ref colors)).normalColor = Shade(tint, selected ? 0.6f : 0.38f);
Color highlightedColor = (((ColorBlock)(ref colors)).selectedColor = Shade(tint, 0.7f));
((ColorBlock)(ref colors)).highlightedColor = highlightedColor;
((ColorBlock)(ref colors)).pressedColor = Shade(tint, 0.25f);
((Selectable)button).colors = colors;
((Shadow)((Component)button).GetComponent<Outline>()).effectColor = (selected ? Color.white : tint);
}
private static Color Shade(Color tint, float factor)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
return new Color(tint.r * factor, tint.g * factor, tint.b * factor, 1f);
}
internal static void Style(Button button, Image image)
{
//IL_0008: 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_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: 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_00a6: 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_00ee: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
image.sprite = null;
((Graphic)image).color = Color.white;
((Selectable)button).targetGraphic = (Graphic)(object)image;
((Selectable)button).transition = (Transition)1;
ColorBlock colors = default(ColorBlock);
((ColorBlock)(ref colors)).normalColor = new Color(0.035f, 0.43f, 0.49f);
((ColorBlock)(ref colors)).highlightedColor = new Color(0.06f, 0.62f, 0.69f);
((ColorBlock)(ref colors)).selectedColor = new Color(0.06f, 0.62f, 0.69f);
((ColorBlock)(ref colors)).pressedColor = new Color(0.02f, 0.27f, 0.32f);
((ColorBlock)(ref colors)).disabledColor = new Color(0.025f, 0.2f, 0.23f);
((ColorBlock)(ref colors)).colorMultiplier = 1f;
((ColorBlock)(ref colors)).fadeDuration = 0.08f;
((Selectable)button).colors = colors;
Outline obj = ((Component)image).gameObject.AddComponent<Outline>();
((Shadow)obj).effectColor = new Color(0.12f, 0.8f, 0.85f, 0.7f);
((Shadow)obj).effectDistance = new Vector2(0.7f, -0.7f);
}
}
[BepInPlugin("local.terminal-loadouts", "Terminal Loadouts", "1.1.4")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public sealed class Plugin : BaseUnityPlugin
{
[HarmonyPatch(typeof(ShopZone), "Start")]
private static class AttachPatch
{
private static void Postfix(ShopZone __instance)
{
Attach(__instance);
}
}
[HarmonyPatch(typeof(ShopZone), "TurnOn")]
private static class RetryAttachPatch
{
private static void Postfix(ShopZone __instance)
{
Attach(__instance);
}
}
[HarmonyPatch]
private static class TypingPointerPatch
{
private static MethodBase TargetMethod()
{
return AccessTools.Method(typeof(ShopZone).Assembly.GetType("ControllerPointer"), "Update", (Type[])null, (Type[])null);
}
private static bool Prefix()
{
return !LoadoutDialog.IsOpen;
}
}
[HarmonyPatch(typeof(GamepadObjectSelector), "Update")]
private static class ModalSelectionPatch
{
private static bool Prefix()
{
return !LoadoutDialog.IsOpen;
}
}
public const string Id = "local.terminal-loadouts";
internal static PresetStore Store;
internal static ManualLogSource Log;
private Harmony harmony;
private void Awake()
{
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Store = new PresetStore(Path.Combine(Paths.ConfigPath, "TerminalLoadouts", "loadouts.json"));
if (Store.Notice != null)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)(Store.Notice + " " + Store.ErrorDetail));
}
harmony = new Harmony("local.terminal-loadouts");
harmony.PatchAll(typeof(Plugin).Assembly);
BrutalV1Compatibility.Install(harmony);
((BaseUnityPlugin)this).Logger.LogInfo((object)"Terminal Loadouts 1.1.4 ready. LOADOUTS appears below ARMS in start-room terminals.");
}
private void OnDestroy()
{
TerminalUi[] array = Resources.FindObjectsOfTypeAll<TerminalUi>();
foreach (TerminalUi terminalUi in array)
{
if (Object.op_Implicit((Object)(object)terminalUi))
{
terminalUi.Remove();
}
}
Harmony obj = harmony;
if (obj != null)
{
obj.UnpatchSelf();
}
BrutalV1Compatibility.Restore();
}
private static void Attach(ShopZone shop)
{
if (!Object.op_Implicit((Object)(object)shop) || !Object.op_Implicit((Object)(object)((Component)shop).GetComponentInParent<FirstRoomPrefab>()) || Object.op_Implicit((Object)(object)((Component)shop).GetComponent<TerminalMarker>()))
{
return;
}
try
{
TerminalUi.Attach(shop);
}
catch (Exception ex)
{
Log.LogError((object)("Could not attach loadout UI; the vanilla terminal was left available. " + ex));
}
}
}
internal sealed class TerminalMarker : MonoBehaviour
{
}
internal sealed class TerminalUi : MonoBehaviour
{
private sealed class UiButton
{
public readonly Button Button;
public readonly ShopButton Shop;
public readonly TMP_Text Label;
public UiButton(Button button, ShopButton shop, TMP_Text label)
{
Button = button;
Shop = shop;
Label = label;
}
public void Enable(bool value)
{
((Selectable)Button).interactable = value;
Shop.deactivated = !value;
}
}
private ShopZone shop;
private Transform weapons;
private ShopButton arms;
private TMP_Text fontSource;
private UiButton entry;
private UiButton apply;
private UiButton save;
private UiButton rename;
private UiButton delete;
private UiButton color;
private UiButton moveUp;
private UiButton moveDown;
private UiButton previous;
private UiButton next;
private readonly List<UiButton> rows = new List<UiButton>();
private readonly List<ShopButton> nativeButtons = new List<ShopButton>();
private readonly Dictionary<RectTransform, Vector2> originalPositions = new Dictionary<RectTransform, Vector2>();
private TMP_Text details;
private TMP_Text status;
private TMP_Text pageLabel;
private TMP_Text availability;
private GameObject content;
private GameObject confirmation;
private GameObject preview;
private EquipmentIcons icons;
private LoadoutDialog dialog;
private int selected;
private int page;
private bool ready;
private float nextSaveCheck;
internal static void Attach(ShopZone shop)
{
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_0143: Unknown result type (might be due to invalid IL or missing references)
ShopButton val = ((IEnumerable<ShopButton>)((Component)shop).GetComponentsInChildren<ShopButton>(true)).FirstOrDefault((Func<ShopButton, bool>)((ShopButton b) => ((Object)b).name == "ArmButton"));
if (!Object.op_Implicit((Object)(object)val))
{
throw new InvalidOperationException("ArmButton was not found in this terminal.");
}
Transform parent = ((Component)val).transform.parent.parent.parent;
if (((Object)parent).name != "Weapons")
{
throw new InvalidOperationException("Unexpected Weapons panel hierarchy.");
}
GameObject val2 = new GameObject("TerminalLoadouts", new Type[1] { typeof(RectTransform) });
val2.SetActive(false);
val2.transform.SetParent(parent, false);
val2.layer = ((Component)val).gameObject.layer;
RectTransform val3 = (RectTransform)val2.transform;
val3.anchorMin = Vector2.zero;
val3.anchorMax = Vector2.one;
val3.offsetMin = new Vector2(212.5f, 0f);
val3.offsetMax = Vector2.zero;
TerminalUi terminalUi = val2.AddComponent<TerminalUi>();
try
{
terminalUi.shop = shop;
terminalUi.weapons = parent;
terminalUi.arms = val;
terminalUi.fontSource = ((Component)val).GetComponentInChildren<TMP_Text>(true);
terminalUi.Build();
((Component)shop).gameObject.AddComponent<TerminalMarker>();
ManualLogSource log = Plugin.Log;
Scene scene = ((Component)shop).gameObject.scene;
log.LogInfo((object)("Attached LOADOUTS below ARMS: " + ((Scene)(ref scene)).name));
}
catch
{
terminalUi.Remove();
throw;
}
}
private void Build()
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_041b: Unknown result type (might be due to invalid IL or missing references)
//IL_04e2: Unknown result type (might be due to invalid IL or missing references)
//IL_04e8: Expected O, but got Unknown
//IL_04f8: Unknown result type (might be due to invalid IL or missing references)
//IL_04fe: Expected O, but got Unknown
//IL_0500: Unknown result type (might be due to invalid IL or missing references)
//IL_050c: Unknown result type (might be due to invalid IL or missing references)
//IL_0518: Unknown result type (might be due to invalid IL or missing references)
//IL_0524: Unknown result type (might be due to invalid IL or missing references)
//IL_05e0: Unknown result type (might be due to invalid IL or missing references)
//IL_05ef: Unknown result type (might be due to invalid IL or missing references)
//IL_05f4: Unknown result type (might be due to invalid IL or missing references)
//IL_0599: Unknown result type (might be due to invalid IL or missing references)
//IL_05a7: Unknown result type (might be due to invalid IL or missing references)
//IL_05b3: Unknown result type (might be due to invalid IL or missing references)
//IL_05c3: Unknown result type (might be due to invalid IL or missing references)
Image obj = ((Component)this).gameObject.AddComponent<Image>();
((Graphic)obj).color = LoadoutTheme.Panel;
((Graphic)obj).raycastTarget = true;
((Graphic)Label(((Component)this).transform, "LOADOUTS", 10f, 5f, 327f, 30f, 23f)).color = LoadoutTheme.Accent;
icons = new EquipmentIcons(shop);
content = ((Component)Rect("Content", ((Component)this).transform, 0f, 36f, 347f, 270f)).gameObject;
for (int i = 0; i < 5; i++)
{
int localRow = i;
rows.Add(MakeButton(content.transform, "Slot", 10f, i * 34 + 4, 122f, 30f, delegate
{
selected = page * 5 + localRow;
Refresh();
}));
}
Label(content.transform, "REORDER SELECTED SLOT", 10f, 174f, 122f, 13f, 9f);
moveUp = MakeButton(content.transform, "UP", 10f, 188f, 55f, 24f, delegate
{
Move(-1);
});
moveDown = MakeButton(content.transform, "DOWN", 77f, 188f, 55f, 24f, delegate
{
Move(1);
});
previous = MakeButton(content.transform, "<", 10f, 219f, 55f, 24f, delegate
{
page--;
selected = page * 5 + selected % 5;
Refresh();
});
next = MakeButton(content.transform, ">", 77f, 219f, 55f, 24f, delegate
{
page++;
selected = page * 5 + selected % 5;
Refresh();
});
pageLabel = Label(content.transform, "", 10f, 245f, 122f, 18f, 12f);
pageLabel.alignment = (TextAlignmentOptions)514;
details = Label(content.transform, "", 143f, 4f, 194f, 156f, 13f);
details.enableAutoSizing = true;
details.fontSizeMin = 10f;
details.fontSizeMax = 13f;
apply = MakeButton(content.transform, "APPLY", 143f, 191f, 194f, 28f, Apply);
save = MakeButton(content.transform, "SAVE CURRENT", 143f, 225f, 194f, 28f, Save);
rename = MakeButton(((Component)this).transform, "RENAME", 143f, 295f, 94f, 28f, Rename);
delete = MakeButton(((Component)this).transform, "DELETE", 243f, 295f, 94f, 28f, Delete);
color = MakeButton(((Component)this).transform, "SLOT COLOR", 10f, 305f, 122f, 24f, ChooseColor);
availability = Label(((Component)this).transform, "", 10f, 331f, 327f, 16f, 10f);
((Graphic)availability).color = new Color(1f, 0.75f, 0.25f);
status = Label(((Component)this).transform, "", 10f, 349f, 327f, 26f, 12f);
status.enableAutoSizing = true;
status.fontSizeMin = 9f;
status.fontSizeMax = 12f;
entry = MakeButton(((Component)arms).transform.parent, "LOADOUTS", 0f, 0f, 0f, 30f, Open);
((Object)entry.Button).name = "LoadoutsButton";
RectTransform val = (RectTransform)((Component)arms).transform;
RectTransform val2 = (RectTransform)((Component)entry.Button).transform;
val2.anchorMin = val.anchorMin;
val2.anchorMax = val.anchorMax;
val2.pivot = val.pivot;
val2.sizeDelta = val.sizeDelta;
ShopCategory[] componentsInChildren = ((Component)((Component)arms).transform.parent).GetComponentsInChildren<ShopCategory>(true);
foreach (ShopCategory val3 in componentsInChildren)
{
Transform transform = ((Component)val3).transform;
RectTransform val4 = (RectTransform)(object)((transform is RectTransform) ? transform : null);
if (Object.op_Implicit((Object)(object)val4) && !((Object)(object)((Component)val3).transform.parent != (Object)(object)((Component)arms).transform.parent))
{
originalPositions[val4] = val4.anchoredPosition;
val4.anchoredPosition = new Vector2(val4.anchoredPosition.x, val4.anchoredPosition.y * (13f / 14f));
}
}
val2.anchoredPosition = val.anchoredPosition + new Vector2(0f, -32.5f);
((Transform)val2).SetSiblingIndex(((Component)arms).transform.GetSiblingIndex() + 1);
entry.Label.fontSize = fontSource.fontSize;
ShopButton[] componentsInChildren2 = ((Component)((Component)arms).transform.parent).GetComponentsInChildren<ShopButton>(true);
foreach (ShopButton val5 in componentsInChildren2)
{
if (!((Object)(object)val5 == (Object)(object)entry.Shop))
{
nativeButtons.Add(val5);
val5.toDeactivate = (val5.toDeactivate ?? Array.Empty<GameObject>()).Concat((IEnumerable<GameObject>)(object)new GameObject[1] { ((Component)this).gameObject }).ToArray();
}
}
ready = true;
}
private void Open()
{
if (LoadoutDialog.IsOpen || !Object.op_Implicit((Object)(object)shop) || shop.forcedOff)
{
return;
}
foreach (GameObject item in arms.toActivate.Concat(arms.toDeactivate).Distinct())
{
if (Object.op_Implicit((Object)(object)item) && (Object)(object)item != (Object)(object)((Component)weapons).gameObject && (Object)(object)item != (Object)(object)((Component)this).gameObject && !((Component)this).transform.IsChildOf(item.transform))
{
item.SetActive(false);
}
}
ShopButtonListController[] componentsInChildren = ((Component)((Component)arms).transform.parent).GetComponentsInChildren<ShopButtonListController>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
componentsInChildren[i].ResetButtons();
}
ShopButtonListController componentInParent = ((Component)arms).GetComponentInParent<ShopButtonListController>();
if (Object.op_Implicit((Object)(object)componentInParent))
{
componentInParent.ResetButtons();
}
((Component)this).gameObject.SetActive(true);
entry.Enable(value: false);
SetStatus(Plugin.Store.Notice ?? "SAVE CURRENT fills empty slots. OVERWRITE replaces changed setups. SAVED means they match.");
}
private void OnEnable()
{
if (ready)
{
Refresh();
}
}
private void Update()
{
if (ready && !LoadoutDialog.IsOpen && !Object.op_Implicit((Object)(object)confirmation) && !(Time.unscaledTime < nextSaveCheck))
{
nextSaveCheck = Time.unscaledTime + 0.3f;
RefreshSaveAction(Plugin.Store.Get(selected));
}
}
private void OnDisable()
{
if (Object.op_Implicit((Object)(object)dialog))
{
dialog.Close();
dialog = null;
}
if (Object.op_Implicit((Object)(object)confirmation))
{
Object.Destroy((Object)(object)confirmation);
}
if (Object.op_Implicit((Object)(object)content))
{
content.SetActive(true);
}
if (rename != null)
{
((Component)rename.Button).gameObject.SetActive(true);
}
if (delete != null)
{
((Component)delete.Button).gameObject.SetActive(true);
}
if (color != null)
{
((Component)color.Button).gameObject.SetActive(true);
}
if (entry != null && Object.op_Implicit((Object)(object)entry.Button))
{
entry.Enable(value: true);
}
if (ready && ((Component)this).gameObject.activeSelf)
{
((Component)this).gameObject.SetActive(false);
}
}
private void Refresh()
{
//IL_008e: 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_0204: Unknown result type (might be due to invalid IL or missing references)
//IL_0228: Unknown result type (might be due to invalid IL or missing references)
//IL_025e: Unknown result type (might be due to invalid IL or missing references)
PresetStore store = Plugin.Store;
Color tint = default(Color);
for (int i = 0; i < 5; i++)
{
int num = page * 5 + i;
Loadout loadout = store.Get(num);
rows[i].Label.text = ((num == selected) ? "> " : "") + (num + 1) + ". " + (loadout?.Name ?? "Empty");
((Graphic)rows[i].Label).color = Color.white;
ColorUtility.TryParseHtmlString("#" + store.GetColor(num), ref tint);
LoadoutTheme.SlotColor(rows[i].Button, tint, num == selected);
}
pageLabel.text = "SLOTS " + (page * 5 + 1) + "–" + (page * 5 + 5) + " / 20";
previous.Enable(page > 0);
next.Enable(page < 3);
moveUp.Enable(store.Writable && selected > 0);
moveDown.Enable(store.Writable && selected < 19);
color.Enable(store.Writable);
Loadout loadout2 = store.Get(selected);
bool flag = EquipmentService.HasUnavailableGrenades(loadout2, GrenadeLauncherCompatibility.IsLoaded);
availability.text = (flag ? "GL missing: uses standard rockets. Saved GL choices kept." : "");
status.rectTransform.anchoredPosition = new Vector2(10f, (float)(flag ? (-349) : (-331)));
status.rectTransform.sizeDelta = new Vector2(327f, (float)(flag ? 26 : 44));
details.enableWordWrapping = loadout2 == null;
details.rectTransform.sizeDelta = new Vector2(194f, (float)((loadout2 == null) ? 156 : 20));
details.text = ((loadout2 == null) ? "EMPTY SLOT\n\nConfigure weapons, variant order and arms normally, then choose SAVE CURRENT." : loadout2.Name);
RefreshPreview(loadout2);
apply.Enable(loadout2 != null);
RefreshSaveAction(loadout2);
rename.Enable(loadout2 != null && store.Writable);
delete.Enable(loadout2 != null && store.Writable);
}
private void RefreshSaveAction(Loadout saved)
{
try
{
Loadout current = EquipmentService.Capture(new GameEquipment(), "Current");
bool flag = saved?.SameEquipment(EquipmentService.PrepareSave(current, saved)) ?? false;
save.Label.text = ((saved == null) ? "SAVE CURRENT" : (flag ? "SAVED" : "OVERWRITE"));
save.Enable(Plugin.Store.Writable && !flag);
}
catch
{
save.Label.text = "UNAVAILABLE";
save.Enable(value: false);
}
}
private void RefreshPreview(Loadout current)
{
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_0310: Unknown result type (might be due to invalid IL or missing references)
//IL_029d: Unknown result type (might be due to invalid IL or missing references)
//IL_0296: Unknown result type (might be due to invalid IL or missing references)
//IL_037c: Unknown result type (might be due to invalid IL or missing references)
//IL_036f: Unknown result type (might be due to invalid IL or missing references)
if (Object.op_Implicit((Object)(object)preview))
{
preview.SetActive(false);
Object.Destroy((Object)(object)preview);
}
if (current == null)
{
return;
}
preview = ((Component)Rect("Saved equipment", content.transform, 143f, 24f, 194f, 163f)).gameObject;
((Graphic)Label(preview.transform, "SAVED CYCLE ORDER >", 0f, 0f, 194f, 16f, 11f)).color = LoadoutTheme.Accent;
string[] array = new string[6] { "REV", "SHOT", "NAIL", "RAIL", "ROCKET", "ARMS" };
for (int i = 0; i < 6; i++)
{
float num = 18 + i * 21;
Label(preview.transform, array[i], 0f, num + 4f, 43f, 17f, 10f);
int[] array2 = ((i < 5) ? Catalog.OrderedWeapons(current, i) : (from index in Enumerable.Range(15, 4)
where current.Equipment[index] != 0
select index).ToArray());
if (array2.Length == 0)
{
Label(preview.transform, "OFF", 48f, num + 4f, 140f, 16f, 10f);
}
for (int num2 = 0; num2 < array2.Length; num2++)
{
int num3 = array2[num2];
float x = 46 + num2 * ((i < 5) ? 49 : 37);
RectTransform parent = Rect(Catalog.Keys[num3], preview.transform, x, num, (i < 5) ? 46 : 34, 20f);
bool flag = num3 >= 12 && num3 < 15 && current.GrenadeLauncherModes != null && current.GrenadeLauncherModes[num3 - 12];
bool flag2 = flag && !GrenadeLauncherCompatibility.IsLoaded;
Sprite val = icons.Get(num3, current.Equipment[num3]);
if (Object.op_Implicit((Object)(object)val))
{
Image obj = ((Component)Rect("Icon", (Transform)(object)parent, (i < 5) ? 10 : 0, 0f, 31f, 19f)).gameObject.AddComponent<Image>();
obj.sprite = val;
obj.preserveAspect = true;
((Graphic)obj).color = (flag2 ? Color.gray : EquipmentIcons.ColorFor(num3));
((Graphic)obj).raycastTarget = false;
}
else
{
Label((Transform)(object)parent, Catalog.Keys[num3].ToUpperInvariant(), 9f, 4f, 35f, 15f, 8f);
}
if (i < 5)
{
((Graphic)Label((Transform)(object)parent, (num2 + 1).ToString(), 0f, 0f, 10f, 16f, 12f)).color = LoadoutTheme.Accent;
}
if (flag || current.Equipment[num3] == 2)
{
((Graphic)Label((Transform)(object)parent, flag2 ? "GL!" : (flag ? "GL" : "ALT"), 24f, 12f, 22f, 9f, 7f)).color = (flag2 ? ((Graphic)availability).color : Color.white);
}
}
}
Label(preview.transform, (current.GrenadeLauncherModes == null) ? "1 > 2 > 3 = cycle ALT = alternate" : "1 > 2 > 3 = cycle ALT / GL = alternate", 0f, 146f, 194f, 16f, 9f);
}
private void SetStatus(string message)
{
status.text = message;
}
private void Run(Action action)
{
try
{
action();
Refresh();
}
catch (Exception ex)
{
Plugin.Log.LogError((object)ex);
SetStatus((ex is IOException || ex is UnauthorizedAccessException) ? "Could not save presets. Existing slots are unchanged; see the BepInEx log." : ex.Message);
}
}
private void Apply()
{
Run(delegate
{
Loadout loadout = Plugin.Store.Get(selected);
if (loadout != null)
{
SetStatus(EquipmentService.Apply(new GameEquipment(), loadout));
VariationInfo[] componentsInChildren = ((Component)shop).GetComponentsInChildren<VariationInfo>();
for (int i = 0; i < componentsInChildren.Length; i++)
{
componentsInChildren[i].UpdateMoney();
}
WeaponOrderController[] componentsInChildren2 = ((Component)shop).GetComponentsInChildren<WeaponOrderController>();
for (int i = 0; i < componentsInChildren2.Length; i++)
{
componentsInChildren2[i].ResetValues();
}
}
});
}
private void Save()
{
Loadout loadout = Plugin.Store.Get(selected);
try
{
if (loadout != null && loadout.SameEquipment(EquipmentService.PrepareSave(EquipmentService.Capture(new GameEquipment(), "Current"), loadout)))
{
SetStatus("This setup is already saved.");
Refresh();
return;
}
}
catch (Exception ex)
{
Plugin.Log.LogError((object)ex);
SetStatus(ex.Message);
Refresh();
return;
}
Action action = delegate
{
Run(delegate
{
Loadout loadout2 = Plugin.Store.Get(selected);
string text = loadout2?.Name ?? ("Loadout " + (selected + 1));
Plugin.Store.Save(selected, EquipmentService.PrepareSave(EquipmentService.Capture(new GameEquipment(), text), loadout2));
SetStatus("Saved " + text + ", including variant order.");
});
};
if (loadout != null)
{
Confirm("Overwrite " + loadout.Name + " with your current setup?" + (EquipmentService.HasUnavailableGrenades(loadout, GrenadeLauncherCompatibility.IsLoaded) ? " Saved grenade choices will be kept while the mod is missing." : ""), action);
}
else
{
action();
}
}
private void Delete()
{
Confirm("Delete " + Plugin.Store.Get(selected)?.Name + "?", delegate
{
Run(delegate
{
Plugin.Store.Save(selected, null);
SetStatus("Slot " + (selected + 1) + " cleared.");
});
});
}
private void Rename()
{
if (LoadoutDialog.IsOpen)
{
return;
}
int slot = selected;
dialog = LoadoutDialog.ShowRename(fontSource, Plugin.Store.Get(slot).Name, delegate(string name)
{
Run(delegate
{
Plugin.Store.Rename(slot, name);
SetStatus("Loadout renamed.");
});
});
}
private void Move(int offset)
{
Run(delegate
{
int second = selected + offset;
Plugin.Store.Swap(selected, second);
selected = second;
page = selected / 5;
SetStatus("Swapped slots. The selected setup and its color moved to slot " + (selected + 1) + ".");
});
}
private void ChooseColor()
{
if (LoadoutDialog.IsOpen)
{
return;
}
int slot = selected;
dialog = LoadoutDialog.ShowColor(fontSource, Plugin.Store.GetColor(slot), delegate(string value)
{
Run(delegate
{
Plugin.Store.SetColor(slot, value);
SetStatus("Slot " + (slot + 1) + " color saved.");
});
});
}
private void Confirm(string prompt, Action confirmed)
{
if (Object.op_Implicit((Object)(object)confirmation))
{
return;
}
content.SetActive(false);
((Component)rename.Button).gameObject.SetActive(false);
((Component)delete.Button).gameObject.SetActive(false);
((Component)color.Button).gameObject.SetActive(false);
confirmation = ((Component)Rect("Confirmation", ((Component)this).transform, 10f, 65f, 327f, 255f)).gameObject;
TMP_Text obj = Label(confirmation.transform, prompt, 10f, 10f, 307f, 110f, 20f);
obj.enableAutoSizing = true;
obj.fontSizeMin = 12f;
obj.fontSizeMax = 20f;
Action close = delegate
{
if (Object.op_Implicit((Object)(object)confirmation))
{
confirmation.SetActive(false);
Object.Destroy((Object)(object)confirmation);
confirmation = null;
}
content.SetActive(true);
((Component)rename.Button).gameObject.SetActive(true);
((Component)delete.Button).gameObject.SetActive(true);
((Component)color.Button).gameObject.SetActive(true);
};
MakeButton(confirmation.transform, "CONFIRM", 10f, 140f, 145f, 35f, delegate
{
close();
confirmed();
});
MakeButton(confirmation.transform, "CANCEL", 172f, 140f, 145f, 35f, close);
}
private TMP_Text Label(Transform parent, string text, float x, float y, float width, float height, float size)
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
TextMeshProUGUI obj = ((Component)Rect("Label", parent, x, y, width, height)).gameObject.AddComponent<TextMeshProUGUI>();
((TMP_Text)obj).font = fontSource.font;
((TMP_Text)obj).fontSharedMaterial = fontSource.fontSharedMaterial;
((TMP_Text)obj).fontSize = size;
((Graphic)obj).color = Color.white;
((TMP_Text)obj).richText = false;
((TMP_Text)obj).text = text;
((Graphic)obj).raycastTarget = false;
((TMP_Text)obj).alignment = (TextAlignmentOptions)257;
((TMP_Text)obj).overflowMode = (TextOverflowModes)1;
return (TMP_Text)(object)obj;
}
private UiButton MakeButton(Transform parent, string text, float x, float y, float width, float height, Action action)
{
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: 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_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_0157: Unknown result type (might be due to invalid IL or missing references)
//IL_0161: Expected O, but got Unknown
RectTransform val = Rect(text, parent, x, y, width, height);
Image image = ((Component)val).gameObject.AddComponent<Image>();
Button button = ((Component)val).gameObject.AddComponent<Button>();
LoadoutTheme.Style(button, image);
Button obj = button;
Navigation navigation = default(Navigation);
((Navigation)(ref navigation)).mode = (Mode)3;
((Selectable)obj).navigation = navigation;
TMP_Text val2 = Label((Transform)(object)val, text, 4f, 0f, width - 8f, height, 16f);
RectTransform rectTransform = val2.rectTransform;
rectTransform.anchorMin = Vector2.zero;
rectTransform.anchorMax = Vector2.one;
rectTransform.offsetMin = new Vector2(4f, 0f);
rectTransform.offsetMax = new Vector2(-4f, 0f);
val2.alignment = (TextAlignmentOptions)514;
val2.enableWordWrapping = false;
ShopButton val3 = ((Component)val).gameObject.AddComponent<ShopButton>();
val3.toActivate = Array.Empty<GameObject>();
val3.toDeactivate = Array.Empty<GameObject>();
val3.clickSound = arms.clickSound;
val3.failSound = arms.failSound;
int lastFrame = -1;
Action invoke = delegate
{
if (lastFrame == Time.frameCount || !((Selectable)button).interactable || !((Component)button).gameObject.activeInHierarchy || LoadoutDialog.IsOpen)
{
return;
}
lastFrame = Time.frameCount;
try
{
action();
}
catch (Exception ex)
{
Plugin.Log.LogError((object)ex);
if (Object.op_Implicit((Object)(object)status))
{
SetStatus(ex.Message);
}
}
};
((UnityEvent)button.onClick).AddListener((UnityAction)delegate
{
invoke();
});
val3.PointerClickSuccess += invoke;
return new UiButton(button, val3, val2);
}
internal static RectTransform Rect(string name, Transform parent, float x, float y, float width, float height)
{
//IL_0014: 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_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_003c: 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_003e: 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_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_0082: Expected O, but got Unknown
RectTransform val = (RectTransform)new GameObject(name, new Type[1] { typeof(RectTransform) })
{
layer = ((Component)parent).gameObject.layer
}.transform;
((Transform)val).SetParent(parent, false);
Vector2 val2 = default(Vector2);
((Vector2)(ref val2))..ctor(0f, 1f);
val.pivot = val2;
Vector2 anchorMin = (val.anchorMax = val2);
val.anchorMin = anchorMin;
val.anchoredPosition = new Vector2(x, 0f - y);
val.sizeDelta = new Vector2(width, height);
return val;
}
internal void Remove()
{
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
if (Object.op_Implicit((Object)(object)dialog))
{
dialog.Close();
}
foreach (ShopButton nativeButton in nativeButtons)
{
if (Object.op_Implicit((Object)(object)nativeButton))
{
nativeButton.toDeactivate = nativeButton.toDeactivate.Where((GameObject x) => (Object)(object)x != (Object)(object)((Component)this).gameObject).ToArray();
}
}
foreach (KeyValuePair<RectTransform, Vector2> originalPosition in originalPositions)
{
if (Object.op_Implicit((Object)(object)originalPosition.Key))
{
originalPosition.Key.anchoredPosition = originalPosition.Value;
}
}
if (entry != null && Object.op_Implicit((Object)(object)entry.Button))
{
Object.Destroy((Object)(object)((Component)entry.Button).gameObject);
}
if (Object.op_Implicit((Object)(object)shop) && Object.op_Implicit((Object)(object)((Component)shop).GetComponent<TerminalMarker>()))
{
Object.Destroy((Object)(object)((Component)shop).GetComponent<TerminalMarker>());
}
Object.Destroy((Object)(object)((Component)this).gameObject);
}
}
}
namespace TerminalLoadouts.Core
{
internal sealed class ActionSuspension<T>
{
private readonly T[] enabled;
private readonly Action<T> restore;
private bool released;
private ActionSuspension(T[] enabled, Action<T> restore)
{
this.enabled = enabled;
this.restore = restore;
}
internal static ActionSuspension<T> Suspend(IEnumerable<T> actions, Func<T, bool> isEnabled, Action<T> disable, Action<T> restore)
{
ActionSuspension<T> actionSuspension = new ActionSuspension<T>(actions.Where(isEnabled).ToArray(), restore);
try
{
T[] array = actionSuspension.enabled;
foreach (T obj in array)
{
disable(obj);
}
return actionSuspension;
}
catch
{
actionSuspension.Release();
throw;
}
}
internal void Release()
{
if (released)
{
return;
}
released = true;
List<Exception> list = new List<Exception>();
T[] array = enabled;
foreach (T obj in array)
{
try
{
restore(obj);
}
catch (Exception item)
{
list.Add(item);
}
}
if (list.Count <= 0)
{
return;
}
throw new AggregateException("Some gameplay input actions could not be restored.", list);
}
}
internal interface IEquipmentRuntime
{
bool Restricted { get; }
int GetInt(string key, int fallback);
string GetString(string key, string fallback);
bool HasKey(string key);
void SetInt(string key, int value);
void SetString(string key, string value);
void DeleteKey(string key);
int Gear(string id);
bool[] CaptureGrenadeModes();
void SetGrenadeModes(bool[] modes);
void RememberSelection();
void ResetWeapons();
void ResetFists();
void RestoreSelection();
}
internal static class EquipmentService
{
public static Loadout PrepareSave(Loadout current, Loadout existing)
{
current.Validate();
existing?.Validate();
Loadout loadout = current.Copy();
if (loadout.GrenadeLauncherModes == null && existing?.GrenadeLauncherModes != null)
{
loadout.GrenadeLauncherModes = (bool[])existing.GrenadeLauncherModes.Clone();
}
return loadout;
}
public static bool HasUnavailableGrenades(Loadout saved, bool modLoaded)
{
if (!modLoaded && saved?.GrenadeLauncherModes != null)
{
return Array.Exists(saved.GrenadeLauncherModes, (bool value) => value);
}
return false;
}
public static Loadout Capture(IEquipmentRuntime game, string name)
{
Loadout loadout = new Loadout
{
Name = name,
Equipment = new int[19],
Orders = new string[5]
};
for (int i = 0; i < Catalog.Keys.Length; i++)
{
loadout.Equipment[i] = game.GetInt("weapon." + Catalog.Keys[i], 1);
}
for (int j = 0; j < 5; j++)
{
loadout.Orders[j] = game.GetString("weapon." + Catalog.Families[j] + ".order", Catalog.DefaultOrder(j));
}
bool[] array = game.CaptureGrenadeModes();
loadout.GrenadeLauncherModes = ((array == null) ? null : ((bool[])array.Clone()));
loadout.Validate();
return loadout;
}
public static string Apply(IEquipmentRuntime game, Loadout preset)
{
preset.Validate();
Catalog.Resolve(preset, game.Gear, out var unavailable);
Loadout loadout = Capture(game, "Rollback");
bool flag = preset.GrenadeLauncherModes != null && loadout.GrenadeLauncherModes != null;
HashSet<string> hashSet = new HashSet<string>();
string[] keys = Catalog.Keys;
foreach (string text in keys)
{
if (!game.HasKey("weapon." + text))
{
hashSet.Add("weapon." + text);
}
}
keys = Catalog.Families;
foreach (string text2 in keys)
{
if (!game.HasKey("weapon." + text2 + ".order"))
{
hashSet.Add("weapon." + text2 + ".order");
}
}
game.RememberSelection();
try
{
Write(game, preset);
if (flag)
{
game.SetGrenadeModes((bool[])preset.GrenadeLauncherModes.Clone());
}
game.ResetWeapons();
game.ResetFists();
game.RestoreSelection();
}
catch (Exception ex)
{
try
{
Write(game, loadout);
if (flag)
{
game.SetGrenadeModes((bool[])loadout.GrenadeLauncherModes.Clone());
}
foreach (string item in hashSet)
{
game.DeleteKey(item);
}
game.ResetWeapons();
game.ResetFists();
game.RestoreSelection();
}
catch (Exception ex2)
{
throw new AggregateException("Apply and rollback failed. Reload the level before continuing.", ex, ex2);
}
throw new InvalidOperationException("Could not apply loadout. Previous equipment was restored.", ex);
}
return "Applied " + preset.Name + " with saved variant order." + ((unavailable == 0) ? "" : (" " + unavailable + " locked choice(s) skipped or using standard equipment.")) + ((loadout.GrenadeLauncherModes == null && Array.Exists(preset.GrenadeLauncherModes ?? Array.Empty<bool>(), (bool value) => value)) ? " Grenade Launcher is not loaded; standard rockets are used. Saved GL choices were kept." : "") + ((loadout.GrenadeLauncherModes != null && preset.GrenadeLauncherModes == null) ? " No GL choices saved: current grenade modes unchanged. SAVE CURRENT to include them." : "") + (game.Restricted ? " This level's forced equipment still takes priority." : "");
}
private static void Write(IEquipmentRuntime game, Loadout preset)
{
for (int i = 0; i < 19; i++)
{
game.SetInt("weapon." + Catalog.Keys[i], preset.Equipment[i]);
}
for (int j = 0; j < 5; j++)
{
game.SetString("weapon." + Catalog.Families[j] + ".order", preset.Orders[j]);
}
}
}
[JsonObject(/*Could not decode attribute arguments.*/)]
internal sealed class Loadout
{
[JsonProperty(/*Could not decode attribute arguments.*/)]
public string Name { get; set; }
[JsonProperty(/*Could not decode attribute arguments.*/)]
public int[] Equipment { get; set; }
[JsonProperty(/*Could not decode attribute arguments.*/)]
public string[] Orders { get; set; }
[JsonProperty(/*Could not decode attribute arguments.*/)]
public bool[] GrenadeLauncherModes { get; set; }
public Loadout Copy()
{
return new Loadout
{
Name = Name,
Equipment = (int[])Equipment.Clone(),
Orders = (string[])Orders.Clone(),
GrenadeLauncherModes = ((GrenadeLauncherModes == null) ? null : ((bool[])GrenadeLauncherModes.Clone()))
};
}
public bool SameEquipment(Loadout other)
{
if (other != null && Equipment.SequenceEqual(other.Equipment) && Orders.SequenceEqual(other.Orders))
{
if (GrenadeLauncherModes != null)
{
if (other.GrenadeLauncherModes != null)
{
return GrenadeLauncherModes.SequenceEqual(other.GrenadeLauncherModes);
}
return false;
}
return other.GrenadeLauncherModes == null;
}
return false;
}
public void Validate()
{
if (string.IsNullOrWhiteSpace(Name) || Name.Length > 32 || Name.Any(char.IsControl))
{
throw new FormatException("Loadout names must contain 1–32 printable characters.");
}
if (Equipment == null || Equipment.Length != Catalog.Keys.Length || Orders == null || Orders.Length != 5)
{
throw new FormatException("Incomplete equipment or ordering data.");
}
if (GrenadeLauncherModes != null && GrenadeLauncherModes.Length != 3)
{
throw new FormatException("Grenade Launcher requires three variant choices.");
}
for (int i = 0; i < Equipment.Length; i++)
{
if (Equipment[i] < 0 || Equipment[i] > ((i >= 9) ? 1 : 2))
{
throw new FormatException("Invalid equipment selection: " + Catalog.Keys[i]);
}
}
string[] orders = Orders;
foreach (string text in orders)
{
if (text == null || text.Length != 4 || text[3] != '4' || new string((from c in text.Take(3)
orderby c
select c).ToArray()) != "123")
{
throw new FormatException("Invalid variant order.");
}
}
}
}
internal static class Catalog
{
public const int SlotCount = 20;
public static readonly string[] Palette = new string[20]
{
"28D9E8", "FF647C", "83DD64", "FFB347", "AE83FF", "53A9FF", "F77EC4", "E8D554", "4CD8A2", "F58A61",
"8BA4FF", "C6E96D", "DB91DF", "68C6F0", "E8B78B", "A5C6B1", "D0A5FF", "FFA6AF", "79E6D7", "BFC9D9"
};
public static readonly string[] Families = new string[5] { "rev", "sho", "nai", "rai", "rock" };
public static readonly string[] FamilyNames = new string[5] { "Revolver", "Shotgun", "Nailgun", "Railcannon", "Rocket" };
public static readonly string[] Keys = Families.SelectMany((string f) => from v in Enumerable.Range(0, 3)
select f + v).Concat(new string[4] { "arm0", "arm1", "arm2", "arm3" }).ToArray();
public static string DefaultColor(int slot)
{
return Palette[slot];
}
public static bool ValidColor(string color)
{
if (color != null && color.Length == 6)
{
return color.All(Uri.IsHexDigit);
}
return false;
}
public static string DefaultOrder(int family)
{
if (family != 0)
{
return "1234";
}
return "1324";
}
public static int[] OrderedWeapons(Loadout saved, int family)
{
return (from index in Enumerable.Range(family * 3, 3)
where saved.Equipment[index] != 0
orderby saved.Orders[family][index % 3]
select index).ToArray();
}
public static string CleanName(string name, int slot)
{
string text = new string((name ?? "").Where((char c) => !char.IsControl(c)).ToArray()).Trim();
if (text.Length == 0)
{
return "Loadout " + (slot + 1);
}
if (text.Length > 32)
{
text = text.Substring(0, 32);
}
if (char.IsHighSurrogate(text[text.Length - 1]))
{
text = text.Substring(0, text.Length - 1);
}
return text;
}
public static int[] Resolve(Loadout saved, Func<string, int> gear, out int unavailable)
{
saved.Validate();
int[] array = (int[])saved.Equipment.Clone();
unavailable = 0;
for (int i = 0; i < array.Length; i++)
{
if (array[i] != 0)
{
if (i != 15 && ((i < 15) ? (gear(Keys[i]) <= 0) : (gear(Keys[i]) != 1)))
{
array[i] = 0;
}
else if (array[i] == 2 && gear(Families[i / 3] + "alt") <= 0)
{
array[i] = 1;
}
if (array[i] != saved.Equipment[i])
{
unavailable++;
}
}
}
return array;
}
public static string Describe(Loadout saved)
{
List<string> list = new List<string>();
int family;
for (family = 0; family < 5; family++)
{
IEnumerable<string> values = from v in Enumerable.Range(0, 3)
orderby saved.Orders[family][v]
where saved.Equipment[family * 3 + v] != 0
select ((v == 0) ? "B" : ((family != 0) ? ((v == 1) ? "G" : "R") : ((v == 1) ? "R" : "G"))) + ((saved.Equipment[family * 3 + v] == 2) ? "*" : "");
string text = string.Join(" ", values);
list.Add(FamilyNames[family] + ": " + ((text.Length == 0) ? "off" : text));
}
IEnumerable<string> enumerable = new string[4] { "Feedbacker", "Knuckleblaster", "Whiplash", "Gold" }.Where((string name, int i) => saved.Equipment[15 + i] == 1);
list.Add("Arms: " + (enumerable.Any() ? string.Join(", ", enumerable) : "off"));
return string.Join("\n", list);
}
}
[JsonObject(/*Could not decode attribute arguments.*/)]
internal sealed class PresetDocument
{
[JsonProperty(/*Could not decode attribute arguments.*/)]
public int Version { get; set; } = 3;
[JsonProperty(/*Could not decode attribute arguments.*/)]
public Loadout[] Slots { get; set; } = new Loadout[20];
[JsonProperty]
public string[] Colors { get; set; }
public void Validate()
{
if (Version < 1 || Version > 3)
{
throw new NotSupportedException("This preset file uses an unsupported version; it has not been changed.");
}
if (Slots == null || Slots.Length != ((Version == 1) ? 10 : 20))
{
throw new FormatException("Incorrect preset slot count.");
}
if (Version >= 2 && (Colors == null || Colors.Length != 20))
{
throw new FormatException("Incomplete slot colors.");
}
if (Colors != null)
{
string[] colors = Colors;
for (int i = 0; i < colors.Length; i++)
{
if (!Catalog.ValidColor(colors[i]))
{
throw new FormatException("Invalid slot color.");
}
}
}
Loadout[] slots = Slots;
for (int i = 0; i < slots.Length; i++)
{
slots[i]?.Validate();
}
}
public void Upgrade()
{
if (Version == 1)
{
Loadout[] array = new Loadout[20];
Array.Copy(Slots, array, Slots.Length);
Slots = array;
Version = 2;
}
if (Colors == null)
{
Colors = new string[20];
for (int i = 0; i < Colors.Length; i++)
{
Colors[i] = Catalog.DefaultColor(i);
}
}
Version = 3;
}
}
internal sealed class PresetStore
{
private readonly string path;
private PresetDocument document = new PresetDocument();
private bool recovered;
public string Notice { get; private set; }
public bool Writable { get; private set; } = true;
public string ErrorDetail { get; private set; }
public PresetStore(string path)
{
this.path = path;
document.Upgrade();
Load();
}
public Loadout Get(int index)
{
CheckIndex(index);
return document.Slots[index]?.Copy();
}
public string GetColor(int index)
{
CheckIndex(index);
return document.Colors[index];
}
private static void CheckIndex(int i)
{
if (i < 0 || i >= 20)
{
throw new ArgumentOutOfRangeException("i", "Choose a slot from 1 to 20.");
}
}
private static PresetDocument Read(string file)
{
//IL_0024: 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_0036: 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_0049: Expected O, but got Unknown
if (new FileInfo(file).Length > 1048576)
{
throw new FormatException("Preset file exceeds the size limit.");
}
PresetDocument obj = JsonConvert.DeserializeObject<PresetDocument>(File.ReadAllText(file), new JsonSerializerSettings
{
MaxDepth = 16,
TypeNameHandling = (TypeNameHandling)0,
MissingMemberHandling = (MissingMemberHandling)1
}) ?? throw new FormatException("Empty preset file.");
obj.Validate();
obj.Upgrade();
return obj;
}
private void Load()
{
if (!File.Exists(path) && !File.Exists(path + ".bak"))
{
return;
}
try
{
document = Read(path);
}
catch (NotSupportedException ex)
{
Writable = false;
Notice = ex.Message;
}
catch (Exception ex2)
{
try
{
document = Read(path + ".bak");
if (File.Exists(path))
{
File.Copy(path, path + ".corrupt-" + DateTime.UtcNow.ToString("yyyyMMddHHmmssfff") + "-" + Guid.NewGuid().ToString("N"));
}
recovered = true;
Notice = "Recovered presets from backup. The damaged file was preserved.";
}
catch (Exception ex3)
{
Writable = false;
Notice = "Presets could not be read. Files were preserved; see the log and README for recovery.";
ErrorDetail = ex2.Message + " Backup: " + ex3.Message;
}
}
}
public void Save(int index, Loadout preset)
{
CheckIndex(index);
if (!Writable)
{
throw new IOException(Notice);
}
preset?.Validate();
PresetDocument presetDocument = CopyDocument();
presetDocument.Slots[index] = preset?.Copy();
Commit(presetDocument);
}
private PresetDocument CopyDocument()
{
PresetDocument presetDocument = new PresetDocument
{
Colors = (string[])document.Colors.Clone()
};
for (int i = 0; i < 20; i++)
{
presetDocument.Slots[i] = document.Slots[i]?.Copy();
}
return presetDocument;
}
private void Commit(PresetDocument next)
{
if (!Writable)
{
throw new IOException(Notice);
}
next.Validate();
Persist(next);
document = next;
Notice = null;
}
public void SetColor(int index, string color)
{
CheckIndex(index);
if (!Catalog.ValidColor(color))
{
throw new FormatException("Enter six hexadecimal digits, such as 28D9E8.");
}
PresetDocument presetDocument = CopyDocument();
presetDocument.Colors[index] = color.ToUpperInvariant();
Commit(presetDocument);
}
public void Swap(int first, int second)
{
CheckIndex(first);
CheckIndex(second);
if (first != second)
{
PresetDocument presetDocument = CopyDocument();
Loadout loadout = presetDocument.Slots[first];
presetDocument.Slots[first] = presetDocument.Slots[second];
presetDocument.Slots[second] = loadout;
string text = presetDocument.Colors[first];
presetDocument.Colors[first] = presetDocument.Colors[second];
presetDocument.Colors[second] = text;
Commit(presetDocument);
}
}
public void Rename(int index, string name)
{
Loadout loadout = Get(index) ?? throw new InvalidOperationException("Save this slot before renaming it.");
loadout.Name = Catalog.CleanName(name, index);
Save(index, loadout);
}
private void Persist(PresetDocument next)
{
string sourceFileName = path + ".tmp-" + Guid.NewGuid().ToString("N");
try
{
Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path)));
using (FileStream fileStream = new FileStream(sourceFileName, FileMode.CreateNew, FileAccess.Write, FileShare.None))
{
using (StreamWriter streamWriter = new StreamWriter(fileStream, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false), 4096, leaveOpen: true))
{
streamWriter.Write(JsonConvert.SerializeObject((object)next, (Formatting)1));
streamWriter.Flush();
}
fileStream.Flush(flushToDisk: true);
}
if (File.Exists(path))
{
File.Replace(sourceFileName, path, recovered ? null : (path + ".bak"));
}
else
{
File.Move(sourceFileName, path);
}
recovered = false;
}
finally
{
if (File.Exists(sourceFileName))
{
File.Delete(sourceFileName);
}
}
}
}
}