using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ShopDiscounts")] [assembly: AssemblyDescription("Mod for to get random Discounts on Items in the R.E.P.O. Shop! Developed by Jettcodey.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Jettcodey")] [assembly: AssemblyProduct("ShopDiscounts")] [assembly: AssemblyCopyright("Copyright © Jettcodey 2026")] [assembly: ComVisible(false)] [assembly: Guid("49136d56-4387-44af-acca-43a6ca0714ce")] [assembly: AssemblyFileVersion("1.0.3")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.3.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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 ShopDiscounts { public static class ConfigManager { public static ConfigEntry UseCustomDiscount; public static ConfigEntry CustomDiscountValue; public static ConfigEntry ChanceNoDiscount; public static ConfigEntry ChanceLowDiscount; public static ConfigEntry ChanceMediumDiscount; public static ConfigEntry ChanceHighDiscount; public static ConfigEntry ChanceMaxDiscount; public static ConfigEntry ChanceUltraDiscount; public static ConfigEntry ChanceLegendaryDiscount; public static void Init(ConfigFile config) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Expected O, but got Unknown //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Expected O, but got Unknown //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Expected O, but got Unknown UseCustomDiscount = config.Bind("Custom Discount", "Enable Custom Discount", false, "Skip rolling and just use a fixed discount."); CustomDiscountValue = config.Bind("Custom Discount", "Discount Percentage", 0, new ConfigDescription("Fixed discount % to apply.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); ChanceNoDiscount = config.Bind("Chances", "0% Discount Chance", 5, new ConfigDescription("Weight for no discount.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); ChanceLowDiscount = config.Bind("Chances", "1-10% Discount Chance", 40, new ConfigDescription("Weight for small discount.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); ChanceMediumDiscount = config.Bind("Chances", "11-25% Discount Chance", 25, new ConfigDescription("Weight for medium discount.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); ChanceHighDiscount = config.Bind("Chances", "26-45% Discount Chance", 15, new ConfigDescription("Weight for high discount.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); ChanceMaxDiscount = config.Bind("Chances", "46-65% Discount Chance", 10, new ConfigDescription("Weight for max discount.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); ChanceUltraDiscount = config.Bind("Chances", "66-85% Discount Chance", 4, new ConfigDescription("Weight for ultra discount.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); ChanceLegendaryDiscount = config.Bind("Chances", "86-100% Discount Chance", 1, new ConfigDescription("Weight for legendary discount.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); } } internal static class DiscountEvents { public const byte EV_DISCOUNT_ROLLED = 156; public static void RaiseDiscountRolled(int pct) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0045: Unknown result type (might be due to invalid IL or missing references) if (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom) { ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogInfo((object)"Not in a room, So Maybe SP or Internet died lol"); } return; } RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)0 }; PhotonNetwork.RaiseEvent((byte)156, (object)new object[1] { pct }, val, SendOptions.SendReliable); ManualLogSource logger2 = Plugin.Logger; if (logger2 != null) { logger2.LogInfo((object)$"sent {pct}% discount to clients"); } } } internal class DiscountEventListener : MonoBehaviourPunCallbacks, IOnEventCallback { private static bool _created; public static void Ensure() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown if (!_created) { _created = true; GameObject val = new GameObject("ShopDiscounts_EventListener"); Object.DontDestroyOnLoad((Object)(object)val); val.AddComponent(); ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogInfo((object)"Discount event listener ready."); } } } public override void OnJoinedRoom() { DiscountManager.ResetDiscount(); } public override void OnLeftRoom() { DiscountManager.ResetDiscount(); } public void OnEvent(EventData photonEvent) { if (photonEvent.Code == 156 && photonEvent.CustomData is object[] array && array.Length >= 1) { int num = (int)array[0]; DiscountManager.ReceiveDiscount(num); ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogInfo((object)$"Got discount from host: {num}%"); } } } } public static class DiscountManager { private static readonly Dictionary _originalPrices = new Dictionary(); public static int CurrentDiscount { get; internal set; } public static bool IsDiscountSynced { get; private set; } public static void RollDiscount() { if (ConfigManager.UseCustomDiscount.Value) { CurrentDiscount = Mathf.Clamp(ConfigManager.CustomDiscountValue.Value, 0, 100); IsDiscountSynced = true; ManualLogSource logger = Plugin.Logger; if (logger != null) { logger.LogInfo((object)$"Custom discount set to {CurrentDiscount}%"); } return; } int value = ConfigManager.ChanceNoDiscount.Value; int value2 = ConfigManager.ChanceLowDiscount.Value; int value3 = ConfigManager.ChanceMediumDiscount.Value; int value4 = ConfigManager.ChanceHighDiscount.Value; int value5 = ConfigManager.ChanceMaxDiscount.Value; int value6 = ConfigManager.ChanceUltraDiscount.Value; int value7 = ConfigManager.ChanceLegendaryDiscount.Value; int num = value + value2 + value3 + value4 + value5 + value6 + value7; if (num <= 0) { CurrentDiscount = 0; IsDiscountSynced = true; ManualLogSource logger2 = Plugin.Logger; if (logger2 != null) { logger2.LogWarning((object)"All discount weights are 0, defaulting to no discount"); } return; } int num2 = Random.Range(0, num); if (num2 < value) { CurrentDiscount = 0; } else if (num2 < value + value2) { CurrentDiscount = Random.Range(1, 11); } else if (num2 < value + value2 + value3) { CurrentDiscount = Random.Range(11, 26); } else if (num2 < value + value2 + value3 + value4) { CurrentDiscount = Random.Range(26, 46); } else if (num2 < value + value2 + value3 + value4 + value5) { CurrentDiscount = Random.Range(46, 66); } else if (num2 < value + value2 + value3 + value4 + value5 + value6) { CurrentDiscount = Random.Range(66, 86); } else { CurrentDiscount = Random.Range(86, 101); } IsDiscountSynced = true; ManualLogSource logger3 = Plugin.Logger; if (logger3 != null) { logger3.LogInfo((object)$"rolled {CurrentDiscount}% shop discount"); } } public static void SyncToClients() { if (SemiFunc.IsMasterClientOrSingleplayer()) { if (PhotonNetwork.IsConnected && PhotonNetwork.InRoom) { DiscountEvents.RaiseDiscountRolled(CurrentDiscount); } else { ApplyDiscountToAllItems(); } } } public static void ReceiveDiscount(int discount) { CurrentDiscount = discount; IsDiscountSynced = true; ApplyDiscountToAllItems(); } public static void ResetDiscount() { CurrentDiscount = 0; IsDiscountSynced = false; _originalPrices.Clear(); } public static void ApplyDiscountToItem(ItemAttributes item) { if ((Object)(object)item == (Object)null || CurrentDiscount <= 0 || _originalPrices.ContainsKey(item)) { return; } _originalPrices[item] = item.value; int num = Mathf.RoundToInt((float)item.value * (1f - (float)CurrentDiscount / 100f)); if (num < 1 && item.value > 0) { num = 1; } item.value = num; if (SemiFunc.IsMasterClientOrSingleplayer()) { PhotonView component = ((Component)item).GetComponent(); if ((Object)(object)component != (Object)null && PhotonNetwork.IsConnected) { component.RPC("GetValueRPC", (RpcTarget)1, new object[1] { num }); } } } public static void RestoreItemPrice(ItemAttributes item) { if ((Object)(object)item == (Object)null || !_originalPrices.TryGetValue(item, out var value)) { return; } item.value = value; _originalPrices.Remove(item); if (SemiFunc.IsMasterClientOrSingleplayer()) { PhotonView component = ((Component)item).GetComponent(); if ((Object)(object)component != (Object)null && PhotonNetwork.IsConnected) { component.RPC("GetValueRPC", (RpcTarget)1, new object[1] { value }); } } } public static void ApplyDiscountToAllItems() { if (CurrentDiscount <= 0) { return; } foreach (ItemAttributes shopping in ShopManager.instance.shoppingList) { ApplyDiscountToItem(shopping); } } public static void RestoreAllItemPrices() { foreach (KeyValuePair originalPrice in _originalPrices) { if ((Object)(object)originalPrice.Key == (Object)null) { continue; } originalPrice.Key.value = originalPrice.Value; if (SemiFunc.IsMasterClientOrSingleplayer()) { PhotonView component = ((Component)originalPrice.Key).GetComponent(); if ((Object)(object)component != (Object)null && PhotonNetwork.IsConnected) { component.RPC("GetValueRPC", (RpcTarget)1, new object[1] { originalPrice.Value }); } } } _originalPrices.Clear(); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "Jettcodey.ShopDiscounts"; public const string PLUGIN_NAME = "Shop Discounts"; public const string PLUGIN_VERSION = "1.0.3"; } [BepInPlugin("Jettcodey.ShopDiscounts", "Shop Discounts", "1.0.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private Harmony _harmony; public static Plugin Instance { get; private set; } internal static ManualLogSource Logger { get; private set; } private void Awake() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown Instance = this; Logger = ((BaseUnityPlugin)this).Logger; ConfigManager.Init(((BaseUnityPlugin)this).Config); _harmony = new Harmony("Jettcodey.ShopDiscounts"); _harmony.PatchAll(); SceneManager.sceneLoaded += OnFirstScene; Logger.LogInfo((object)"Plugin Shop Discounts v1.0.3 loaded successfully."); } private void OnFirstScene(Scene scene, LoadSceneMode mode) { DiscountEventListener.Ensure(); SceneManager.sceneLoaded -= OnFirstScene; } } } namespace ShopDiscounts.Patches { [HarmonyPatch(typeof(ExtractionPoint))] public class ExtractionPointPatches { [HarmonyPostfix] [HarmonyPatch("SetHaulText")] public static void AddDiscountTextToScreen(ExtractionPoint __instance) { if (SemiFunc.RunIsShop()) { int currentDiscount = DiscountManager.CurrentDiscount; if (currentDiscount > 0 && !((TMP_Text)__instance.haulGoalScreen).text.Contains("(-")) { TextMeshPro haulGoalScreen = __instance.haulGoalScreen; ((TMP_Text)haulGoalScreen).text = ((TMP_Text)haulGoalScreen).text + $" (-{currentDiscount}%)"; } } } [HarmonyPostfix] [HarmonyPatch("DestroyAllPhysObjectsInShoppingList")] public static void RevertItemPrices() { if (SemiFunc.RunIsShop()) { DiscountManager.RestoreAllItemPrices(); } } } [HarmonyPatch(typeof(ShopManager))] public class ShopManagerPatches { [HarmonyPostfix] [HarmonyPatch("ShopInitialize")] public static void GenerateDiscountOnLoad() { if (SemiFunc.RunIsShop() && SemiFunc.IsMasterClientOrSingleplayer()) { DiscountManager.RollDiscount(); DiscountManager.SyncToClients(); } } [HarmonyPrefix] [HarmonyPatch("ShoppingListItemAdd")] public static void OnItemAdded(ItemAttributes item) { if (SemiFunc.RunIsShop() && DiscountManager.IsDiscountSynced) { DiscountManager.ApplyDiscountToItem(item); } } [HarmonyPrefix] [HarmonyPatch("ShoppingListItemRemove")] public static void OnItemRemoved(ItemAttributes item) { if (SemiFunc.RunIsShop()) { DiscountManager.RestoreItemPrice(item); } } [HarmonyPrefix] [HarmonyPatch("ShopCheck")] public static void EnsureDiscountBeforeCheck() { if (SemiFunc.RunIsShop()) { if (!DiscountManager.IsDiscountSynced) { DiscountManager.CurrentDiscount = 0; } DiscountManager.ApplyDiscountToAllItems(); } } } }