using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using NoRedraw.Patches;
using Photon.Pun;
using TMPro;
using UnboundLib;
using UnboundLib.GameModes;
using UnboundLib.Networking;
using UnboundLib.Utils.UI;
using UnityEngine;
using UnityEngine.Events;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("NoRedraw")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("NoRedraw")]
[assembly: AssemblyTitle("NoRedraw")]
[assembly: AssemblyVersion("1.0.0.0")]
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;
}
}
}
namespace NoRedraw
{
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("com.nic.rounds.noredraw", "No Redraw", "1.1.0")]
[BepInProcess("Rounds.exe")]
public class NoRedraw : BaseUnityPlugin
{
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static UnityAction <>9__16_0;
public static UnityAction<bool> <>9__17_0;
public static UnityAction<bool> <>9__17_1;
public static UnityAction<bool> <>9__17_2;
public static Func<string, bool> <>9__23_0;
public static Func<string, bool> <>9__25_0;
public static Func<CardInfo, bool> <>9__27_0;
internal void <Start>b__16_0()
{
}
internal void <BuildMenu>b__17_0(bool value)
{
Enabled = value;
EnabledConfig.Value = value;
}
internal void <BuildMenu>b__17_1(bool value)
{
DiscardOnDraw = value;
DiscardOnDrawConfig.Value = value;
}
internal void <BuildMenu>b__17_2(bool value)
{
ResetOnNewRound = value;
ResetOnNewRoundConfig.Value = value;
}
internal bool <GetCardAliases>b__23_0(string name)
{
return !string.IsNullOrWhiteSpace(name);
}
internal bool <IsCardRemoved>b__25_0(string alias)
{
return PickedCards.Contains(alias);
}
internal bool <GetRandomAllowedCard>b__27_0(CardInfo c)
{
return (Object)(object)c != (Object)null && !IsCardRemoved(c);
}
}
[CompilerGenerated]
private sealed class <OnGameStart>d__20 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public IGameModeHandler gm;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <OnGameStart>d__20(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
if (<>1__state != 0)
{
return false;
}
<>1__state = -1;
PickedCards.Clear();
Log.LogInfo((object)"Card pool reset — new game.");
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
[CompilerGenerated]
private sealed class <OnRoundStart>d__21 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public IGameModeHandler gm;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <OnRoundStart>d__21(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
if (<>1__state != 0)
{
return false;
}
<>1__state = -1;
if (Enabled && ResetOnNewRound)
{
PickedCards.Clear();
Log.LogInfo((object)"Card pool reset — new round.");
}
return false;
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
private const string ModId = "com.nic.rounds.noredraw";
private const string ModName = "No Redraw";
public const string Version = "1.1.0";
internal static ManualLogSource Log;
private static ConfigEntry<bool> EnabledConfig;
private static ConfigEntry<bool> ResetOnNewRoundConfig;
private static ConfigEntry<bool> DiscardOnDrawConfig;
public static bool Enabled = true;
public static bool ResetOnNewRound = false;
public static bool DiscardOnDraw = false;
public static HashSet<string> PickedCards = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
public static NoRedraw instance { get; private set; }
private void Awake()
{
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Log.LogInfo((object)"NoRedraw Awake() running...");
EnabledConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("NoRedraw", "Enabled", true, "When enabled, cards are removed from the draw pool after use");
ResetOnNewRoundConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("NoRedraw", "ResetOnNewRound", false, "If true, the pool resets every round instead of only on new game");
DiscardOnDrawConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("NoRedraw", "DiscardOnDraw", false, "If true, cards are discarded when drawn (shown as options), not just when picked");
try
{
Harmony val = new Harmony("com.nic.rounds.noredraw");
val.PatchAll();
Log.LogInfo((object)"Harmony patches applied successfully.");
ApplyUnboundConditionPatch(val);
}
catch (Exception ex)
{
Log.LogError((object)("Harmony patching FAILED: " + ex));
}
}
private void Start()
{
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Expected O, but got Unknown
instance = this;
Enabled = EnabledConfig.Value;
ResetOnNewRound = ResetOnNewRoundConfig.Value;
DiscardOnDraw = DiscardOnDrawConfig.Value;
object obj = <>c.<>9__16_0;
if (obj == null)
{
UnityAction val = delegate
{
};
<>c.<>9__16_0 = val;
obj = (object)val;
}
Unbound.RegisterMenu("No Redraw", (UnityAction)obj, (Action<GameObject>)BuildMenu, (GameObject)null, false);
Unbound.RegisterHandshake("com.nic.rounds.noredraw", (Action)OnHandShakeCompleted);
GameModeManager.AddHook("GameStart", (Func<IGameModeHandler, IEnumerator>)OnGameStart);
GameModeManager.AddHook("RoundStart", (Func<IGameModeHandler, IEnumerator>)OnRoundStart);
Unbound.RegisterCredits("No Redraw", new string[1] { "Nic" }, "GitHub", "https://github.com/nic/NoRedraw");
Log.LogInfo((object)("NoRedraw Start() complete. Enabled=" + Enabled + " ResetOnNewRound=" + ResetOnNewRound + " DiscardOnDraw=" + DiscardOnDraw));
}
private void BuildMenu(GameObject menu)
{
TextMeshProUGUI val = default(TextMeshProUGUI);
MenuHandler.CreateText("No Redraw Settings", menu, ref val, 60, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
MenuHandler.CreateToggle(Enabled, "Enable No Redraw", menu, (UnityAction<bool>)delegate(bool value)
{
Enabled = value;
EnabledConfig.Value = value;
}, 50, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
MenuHandler.CreateToggle(DiscardOnDraw, "True Deck Mode (discard on draw)", menu, (UnityAction<bool>)delegate(bool value)
{
DiscardOnDraw = value;
DiscardOnDrawConfig.Value = value;
}, 50, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
MenuHandler.CreateToggle(ResetOnNewRound, "Reset Pool Each Round", menu, (UnityAction<bool>)delegate(bool value)
{
ResetOnNewRound = value;
ResetOnNewRoundConfig.Value = value;
}, 50, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
MenuHandler.CreateText(" ", menu, ref val, 20, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
MenuHandler.CreateText("OFF: cards removed only when picked.\nTRUE DECK: cards removed when shown as options.\nPool auto-resets when empty.", menu, ref val, 30, true, (Color?)null, (TMP_FontAsset)null, (Material)null, (TextAlignmentOptions?)null);
}
private void OnHandShakeCompleted()
{
if (PhotonNetwork.IsMasterClient)
{
NetworkingManager.RPC_Others(typeof(NoRedraw), "SyncSettings", new object[3] { Enabled, ResetOnNewRound, DiscardOnDraw });
}
}
[UnboundRPC]
private static void SyncSettings(bool enabled, bool resetOnNewRound, bool discardOnDraw)
{
Enabled = enabled;
ResetOnNewRound = resetOnNewRound;
DiscardOnDraw = discardOnDraw;
}
[IteratorStateMachine(typeof(<OnGameStart>d__20))]
private static IEnumerator OnGameStart(IGameModeHandler gm)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <OnGameStart>d__20(0)
{
gm = gm
};
}
[IteratorStateMachine(typeof(<OnRoundStart>d__21))]
private static IEnumerator OnRoundStart(IGameModeHandler gm)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <OnRoundStart>d__21(0)
{
gm = gm
};
}
internal static string GetCardKey(CardInfo cardInfo)
{
if ((Object)(object)cardInfo == (Object)null)
{
return string.Empty;
}
string text = (((Object)(object)cardInfo.sourceCard != (Object)null) ? cardInfo.sourceCard.cardName : null);
if (!string.IsNullOrWhiteSpace(text))
{
return text.Trim();
}
return string.IsNullOrWhiteSpace(cardInfo.cardName) ? string.Empty : cardInfo.cardName.Trim();
}
internal static string[] GetCardAliases(CardInfo cardInfo)
{
if ((Object)(object)cardInfo == (Object)null)
{
return Array.Empty<string>();
}
return new string[3]
{
GetCardKey(cardInfo),
string.IsNullOrWhiteSpace(cardInfo.cardName) ? null : cardInfo.cardName.Trim(),
((Object)(object)cardInfo.sourceCard == (Object)null || string.IsNullOrWhiteSpace(cardInfo.sourceCard.cardName)) ? null : cardInfo.sourceCard.cardName.Trim()
}.Where((string name) => !string.IsNullOrWhiteSpace(name)).Cast<string>().Distinct<string>(StringComparer.OrdinalIgnoreCase)
.ToArray();
}
private static void ApplyUnboundConditionPatch(Harmony harmony)
{
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Expected O, but got Unknown
try
{
Type type = AccessTools.TypeByName("CardChoiceSpawnUniqueCardPatch.CardChoicePatchSpawnUniqueCard");
if (type == null)
{
Log.LogInfo((object)"CardChoiceSpawnUniqueCardPatch not present — skipping condition patch.");
return;
}
MethodBase methodBase = AccessTools.Method(type, "GetCondition", (Type[])null, (Type[])null);
if (methodBase == null)
{
Log.LogWarning((object)"CardChoiceSpawnUniqueCardPatch.GetCondition method not found.");
return;
}
HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(Patch_CardChoiceSpawnUniqueCardPatch_GetCondition), "Postfix", (Type[])null, (Type[])null));
harmony.Patch(methodBase, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
Log.LogInfo((object)"Successfully patched CardChoiceSpawnUniqueCardPatch.GetCondition.");
}
catch (Exception ex)
{
Log.LogError((object)("Failed to apply UnboundLib condition patch: " + ex));
}
}
internal static bool IsCardRemoved(CardInfo cardInfo)
{
return GetCardAliases(cardInfo).Any((string alias) => PickedCards.Contains(alias));
}
internal static float GetCardWeight(CardInfo cardInfo)
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Expected I4, but got Unknown
if ((Object)(object)cardInfo == (Object)null)
{
return 0f;
}
Rarity rarity = cardInfo.rarity;
Rarity val = rarity;
return (int)val switch
{
0 => 10f,
1 => 4f,
2 => 1f,
_ => 0f,
};
}
internal static GameObject GetRandomAllowedCard(CardInfo[] cards)
{
if (cards == null || cards.Length == 0)
{
return null;
}
CardInfo[] array = cards.Where((CardInfo c) => (Object)(object)c != (Object)null && !IsCardRemoved(c)).ToArray();
if (array.Length == 0)
{
return null;
}
float num = ((IEnumerable<CardInfo>)array).Sum((Func<CardInfo, float>)GetCardWeight);
if (num <= 0f)
{
return ((Component)array[Random.Range(0, array.Length)]).gameObject;
}
float num2 = Random.Range(0f, num);
CardInfo[] array2 = array;
foreach (CardInfo val in array2)
{
num2 -= GetCardWeight(val);
if (num2 <= 0f)
{
return ((Component)val).gameObject;
}
}
return ((Component)array[^1]).gameObject;
}
internal static void RememberCard(CardInfo cardInfo, string reason)
{
string[] cardAliases = GetCardAliases(cardInfo);
if (cardAliases.Length != 0)
{
bool flag = false;
string[] array = cardAliases;
foreach (string item in array)
{
flag |= PickedCards.Add(item);
}
if (flag)
{
string text = cardAliases[0];
string text2 = ((cardAliases.Length > 1) ? (" aliases=[" + string.Join(", ", cardAliases) + "]") : string.Empty);
Log.LogInfo((object)(reason + ": \"" + text + "\" — " + PickedCards.Count + " unique entries removed." + text2));
}
}
}
}
}
namespace NoRedraw.Patches
{
[HarmonyPatch(typeof(CardChoice), "Pick")]
internal class Patch_CardChoice_Pick
{
private static void Prefix(GameObject pickedCard)
{
if (!NoRedraw.Enabled || (Object)(object)pickedCard == (Object)null || NoRedraw.DiscardOnDraw)
{
return;
}
CardInfo component = pickedCard.GetComponent<CardInfo>();
if (!((Object)(object)component == (Object)null))
{
if (!string.IsNullOrEmpty(component.cardName) && (Object)(object)component.sourceCard != (Object)null && !string.Equals(component.cardName, component.sourceCard.cardName, StringComparison.OrdinalIgnoreCase))
{
NoRedraw.Log.LogInfo((object)("Pick name mismatch: runtime=\"" + component.cardName + "\" source=\"" + component.sourceCard.cardName + "\""));
}
NoRedraw.RememberCard(component, "Picked");
}
}
}
[HarmonyPatch(typeof(CardChoice), "GetRanomCard")]
[HarmonyPriority(800)]
internal class Patch_CardChoice_GetRanomCard
{
private static CardInfo[]? _originalCards;
private static void Prefix(CardChoice __instance)
{
if (NoRedraw.Enabled && NoRedraw.PickedCards.Count != 0)
{
_originalCards = __instance.cards;
CardInfo[] array = __instance.cards.Where((CardInfo c) => !NoRedraw.IsCardRemoved(c)).ToArray();
if (array.Length != 0)
{
__instance.cards = array;
NoRedraw.Log.LogInfo((object)("Filtered pool: " + array.Length + "/" + _originalCards.Length + " cards available."));
}
else
{
NoRedraw.Log.LogInfo((object)"All cards drawn! Resetting pool.");
NoRedraw.PickedCards.Clear();
_originalCards = null;
}
}
}
private static void Postfix(CardChoice __instance, ref GameObject __result)
{
if (_originalCards != null)
{
__instance.cards = _originalCards;
_originalCards = null;
}
if (!NoRedraw.Enabled || (Object)(object)__result == (Object)null)
{
return;
}
CardInfo component = __result.GetComponent<CardInfo>();
if ((Object)(object)component == (Object)null || !NoRedraw.IsCardRemoved(component))
{
return;
}
GameObject randomAllowedCard = NoRedraw.GetRandomAllowedCard(__instance.cards);
if ((Object)(object)randomAllowedCard == (Object)null)
{
NoRedraw.Log.LogWarning((object)("Blocked repeat draw \"" + component.cardName + "\" but found no replacement."));
return;
}
CardInfo component2 = randomAllowedCard.GetComponent<CardInfo>();
if ((Object)(object)component2 == (Object)null || NoRedraw.IsCardRemoved(component2))
{
NoRedraw.Log.LogWarning((object)"Blocked repeat draw but replacement was invalid.");
return;
}
NoRedraw.Log.LogWarning((object)("Blocked repeat draw \"" + NoRedraw.GetCardKey(component) + "\" and replaced it with \"" + NoRedraw.GetCardKey(component2) + "\"."));
__result = randomAllowedCard;
}
}
[HarmonyPatch(typeof(CardChoice), "SpawnUniqueCard")]
[HarmonyPriority(800)]
internal class Patch_CardChoice_SpawnUniqueCard
{
private static CardInfo[]? _originalCards;
private static void Prefix(CardChoice __instance)
{
if (NoRedraw.Enabled && NoRedraw.PickedCards.Count != 0)
{
_originalCards = __instance.cards;
CardInfo[] array = __instance.cards.Where((CardInfo c) => (Object)(object)c != (Object)null && !NoRedraw.IsCardRemoved(c)).ToArray();
if (array.Length != 0)
{
__instance.cards = array;
return;
}
NoRedraw.Log.LogInfo((object)"SpawnUniqueCard: all cards exhausted — resetting pool.");
NoRedraw.PickedCards.Clear();
_originalCards = null;
}
}
private static void Postfix(CardChoice __instance, ref GameObject __result)
{
if (_originalCards != null)
{
__instance.cards = _originalCards;
_originalCards = null;
}
if (!NoRedraw.Enabled || !NoRedraw.DiscardOnDraw || (Object)(object)__result == (Object)null)
{
return;
}
CardInfo component = __result.GetComponent<CardInfo>();
if (!((Object)(object)component == (Object)null))
{
if (!string.IsNullOrEmpty(component.cardName) && (Object)(object)component.sourceCard != (Object)null && !string.Equals(component.cardName, component.sourceCard.cardName, StringComparison.OrdinalIgnoreCase))
{
NoRedraw.Log.LogInfo((object)("Draw name mismatch: runtime=\"" + component.cardName + "\" source=\"" + component.sourceCard.cardName + "\""));
}
NoRedraw.RememberCard(component, "Drawn & discarded");
}
}
}
internal class Patch_CardChoiceSpawnUniqueCardPatch_GetCondition
{
public static void Postfix(CardChoice instance, ref Func<CardInfo, Player, Gun, GunAmmo, CharacterData, HealthHandler, Gravity, Block, CharacterStatModifiers, bool> __result)
{
if (__result == null)
{
return;
}
Func<CardInfo, Player, Gun, GunAmmo, CharacterData, HealthHandler, Gravity, Block, CharacterStatModifiers, bool> original = __result;
__result = delegate(CardInfo card, Player player, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers stats)
{
if (!original(card, player, gun, gunAmmo, data, health, gravity, block, stats))
{
return false;
}
if (!NoRedraw.Enabled || (Object)(object)card == (Object)null)
{
return true;
}
bool flag = NoRedraw.IsCardRemoved(card);
if (flag)
{
NoRedraw.Log.LogInfo((object)("Rejected removed card in external unique-card patch: \"" + NoRedraw.GetCardKey(card) + "\""));
}
return !flag;
};
}
}
}