using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using ModdingUtils.Utils;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.UI;
using UpgradeDraft.Models;
using UpgradeDraft.Services;
using UpgradeDraft.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: AssemblyVersion("0.0.0.0")]
[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.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace UpgradeDraft
{
[BepInPlugin("com.damian.rounds.upgradedraft", "Upgrade Draft", "1.0.13")]
[BepInProcess("Rounds.exe")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class UpgradeDraftPlugin : BaseUnityPlugin
{
public const string PluginGuid = "com.damian.rounds.upgradedraft";
public const string PluginName = "Upgrade Draft";
public const string PluginVersion = "1.0.13";
private static readonly int[] DefaultChances = new int[4] { 25, 50, 20, 5 };
private Harmony _harmony;
private int _chanceZero;
private int _chanceOne;
private int _chanceTwo;
private int _chanceThree;
internal static UpgradeDraftPlugin Instance { get; private set; }
internal static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger;
internal static PlayerDeckService DeckService { get; private set; }
internal static DraftRollService RollService { get; private set; }
internal static CardSelectionService SelectionService { get; private set; }
internal static UpgradePreviewService PreviewService { get; private set; }
internal static UpgradeCardVisualService VisualService { get; private set; }
internal static DraftCardNetworkService NetworkService { get; private set; }
internal static UpgradeDraftState State { get; private set; }
internal static SkipRerollService SkipRerollService { get; private set; }
internal ConfigEntry<int> NormalCardCount { get; private set; }
internal ConfigEntry<int> ChanceZeroUpgrades { get; private set; }
internal ConfigEntry<int> ChanceOneUpgrade { get; private set; }
internal ConfigEntry<int> ChanceTwoUpgrades { get; private set; }
internal ConfigEntry<int> ChanceThreeUpgrades { get; private set; }
internal ConfigEntry<bool> EnableUpgradeVisuals { get; private set; }
internal ConfigEntry<bool> EnableStatPreview { get; private set; }
internal ConfigEntry<string> UpgradeBlacklist { get; private set; }
internal ConfigEntry<bool> VerboseLogging { get; private set; }
internal ConfigEntry<bool> EnableSkipForPoint { get; private set; }
internal ConfigEntry<int> SkipPointsForReroll { get; private set; }
internal ConfigEntry<bool> EnableSkipRerollOverlay { get; private set; }
internal ConfigEntry<bool> AllowMultipleRerollsPerPick { get; private set; }
private void Awake()
{
//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Expected O, but got Unknown
Instance = this;
BindConfig();
ValidateConfig();
State = new UpgradeDraftState(((BaseUnityPlugin)this).Logger);
DeckService = new PlayerDeckService(((BaseUnityPlugin)this).Logger, this);
RollService = new DraftRollService(((BaseUnityPlugin)this).Logger, this);
SelectionService = new CardSelectionService(((BaseUnityPlugin)this).Logger, this, DeckService);
PreviewService = new UpgradePreviewService(((BaseUnityPlugin)this).Logger, this);
VisualService = new UpgradeCardVisualService(((BaseUnityPlugin)this).Logger, this, PreviewService);
NetworkService = new DraftCardNetworkService(((BaseUnityPlugin)this).Logger, this, VisualService);
SkipRerollService = new SkipRerollService(((BaseUnityPlugin)this).Logger, this);
if ((Object)(object)((Component)this).GetComponent<SkipRerollOverlay>() == (Object)null)
{
((Component)this).gameObject.AddComponent<SkipRerollOverlay>();
}
_harmony = new Harmony("com.damian.rounds.upgradedraft");
_harmony.PatchAll();
((BaseUnityPlugin)this).Logger.LogInfo((object)"Upgrade Draft 1.0.13 loaded.");
}
private void OnDestroy()
{
NetworkService?.Dispose();
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
internal int GetCardCount()
{
int num = Math.Max(1, NormalCardCount.Value);
if (num != 4)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)$"NormalCardCount is set to {num}. Values other than 4 are experimental.");
}
return num;
}
internal (int Zero, int One, int Two, int Three) GetWeightedChances()
{
return (_chanceZero, _chanceOne, _chanceTwo, _chanceThree);
}
internal bool IsVisualEnabled()
{
return EnableUpgradeVisuals.Value;
}
internal bool IsStatPreviewEnabled()
{
return EnableStatPreview.Value;
}
internal bool IsVerboseLoggingEnabled()
{
return VerboseLogging.Value;
}
internal bool IsSkipForPointEnabled()
{
return EnableSkipForPoint.Value;
}
internal bool IsSkipRerollOverlayEnabled()
{
return EnableSkipRerollOverlay.Value;
}
internal int GetSkipPointsForReroll()
{
return Math.Max(1, SkipPointsForReroll.Value);
}
internal bool IsMultipleRerollsPerPickAllowed()
{
return AllowMultipleRerollsPerPick.Value;
}
internal HashSet<string> GetBlacklist()
{
return new HashSet<string>(from v in (UpgradeBlacklist.Value ?? string.Empty).Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries)
select v.Trim().ToLowerInvariant() into v
where !string.IsNullOrWhiteSpace(v)
select v);
}
private void BindConfig()
{
NormalCardCount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "NormalCardCount", 4, "Number of visible card choices per draft pick. Values other than 4 are experimental.");
ChanceZeroUpgrades = ((BaseUnityPlugin)this).Config.Bind<int>("Chances", "ChanceZeroUpgrades", 25, "Chance weight for showing 0 upgrade cards.");
ChanceOneUpgrade = ((BaseUnityPlugin)this).Config.Bind<int>("Chances", "ChanceOneUpgrade", 50, "Chance weight for showing 1 upgrade card.");
ChanceTwoUpgrades = ((BaseUnityPlugin)this).Config.Bind<int>("Chances", "ChanceTwoUpgrades", 20, "Chance weight for showing 2 upgrade cards.");
ChanceThreeUpgrades = ((BaseUnityPlugin)this).Config.Bind<int>("Chances", "ChanceThreeUpgrades", 5, "Chance weight for showing 3 upgrade cards.");
EnableUpgradeVisuals = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "EnableUpgradeVisuals", true, "Adds UPGRADE visuals and ownership info to upgrade cards.");
EnableStatPreview = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "EnableStatPreview", true, "Appends conservative stacked stat preview lines for upgrade cards.");
EnableSkipRerollOverlay = ((BaseUnityPlugin)this).Config.Bind<bool>("UI", "EnableSkipRerollOverlay", true, "Show the Upgrade Draft status panel during card pick.");
UpgradeBlacklist = ((BaseUnityPlugin)this).Config.Bind<string>("Rules", "UpgradeBlacklist", string.Empty, "Comma-separated card names that are not allowed as upgrades.");
EnableSkipForPoint = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "EnableSkipForPoint", true, "Enable the 5th SKIP action card. If disabled, the action card is still shown as a no-stats pass card for compatibility.");
SkipPointsForReroll = ((BaseUnityPlugin)this).Config.Bind<int>("Rules", "SkipPointsForReroll", 2, "Skip points required for the 5th action card to become REROLL.");
AllowMultipleRerollsPerPick = ((BaseUnityPlugin)this).Config.Bind<bool>("Rules", "AllowMultipleRerollsPerPick", false, "Allow repeatedly picking REROLL during the same card choice.");
VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLogging", false, "Enable extra debug logging.");
}
private void ValidateConfig()
{
NormalCardCount.Value = Math.Max(1, NormalCardCount.Value);
SkipPointsForReroll.Value = Math.Max(1, SkipPointsForReroll.Value);
int num = Math.Max(0, ChanceZeroUpgrades.Value);
int num2 = Math.Max(0, ChanceOneUpgrade.Value);
int num3 = Math.Max(0, ChanceTwoUpgrades.Value);
int num4 = Math.Max(0, ChanceThreeUpgrades.Value);
int num5 = num + num2 + num3 + num4;
if (num5 <= 0)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)"Upgrade chance weights are invalid (sum <= 0). Falling back to defaults: 25/50/20/5.");
_chanceZero = DefaultChances[0];
_chanceOne = DefaultChances[1];
_chanceTwo = DefaultChances[2];
_chanceThree = DefaultChances[3];
return;
}
if (num5 == 100)
{
_chanceZero = num;
_chanceOne = num2;
_chanceTwo = num3;
_chanceThree = num4;
return;
}
double num6 = 100.0 / (double)num5;
_chanceZero = (int)Math.Round((double)num * num6);
_chanceOne = (int)Math.Round((double)num2 * num6);
_chanceTwo = (int)Math.Round((double)num3 * num6);
_chanceThree = (int)Math.Round((double)num4 * num6);
int num7 = _chanceZero + _chanceOne + _chanceTwo + _chanceThree;
int num8 = 100 - num7;
_chanceOne += num8;
((BaseUnityPlugin)this).Logger.LogWarning((object)$"Upgrade chance weights sum to {num5} instead of 100. Normalized to {_chanceZero}/{_chanceOne}/{_chanceTwo}/{_chanceThree}.");
}
}
}
namespace UpgradeDraft.UI
{
public sealed class DraftActionCardMarker : MonoBehaviour
{
public DraftActionType ActionType;
public int PickerId;
}
public sealed class SkipRerollOverlay : MonoBehaviour
{
private GUIStyle _badgeStyle;
private GUIStyle _actionStyle;
private GUIStyle _labelStyle;
private GUIStyle _titleStyle;
private void Awake()
{
//IL_000b: 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_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_003b: Expected O, but got Unknown
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: 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_005a: 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)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_0076: Expected O, but got Unknown
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00aa: Expected O, but got Unknown
//IL_00b5: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: 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)
//IL_00e5: Expected O, but got Unknown
GUIStyle val = new GUIStyle(GUI.skin.box)
{
fontSize = 22,
fontStyle = (FontStyle)1,
alignment = (TextAnchor)4
};
val.normal.textColor = Color.cyan;
_badgeStyle = val;
GUIStyle val2 = new GUIStyle(GUI.skin.box)
{
fontSize = 18,
fontStyle = (FontStyle)1,
alignment = (TextAnchor)4
};
val2.normal.textColor = Color.white;
_actionStyle = val2;
GUIStyle val3 = new GUIStyle(GUI.skin.label)
{
fontSize = 15,
alignment = (TextAnchor)3
};
val3.normal.textColor = Color.white;
_labelStyle = val3;
GUIStyle val4 = new GUIStyle(GUI.skin.label)
{
fontSize = 18,
fontStyle = (FontStyle)1,
alignment = (TextAnchor)3
};
val4.normal.textColor = Color.yellow;
_titleStyle = val4;
}
private void Update()
{
if (IsReady())
{
CardChoice instance = CardChoice.instance;
_ = instance.pickrID;
if (UpgradeDraftPlugin.SkipRerollService.IsCardChoiceOpen(instance) && !UpgradeDraftPlugin.SkipRerollService.IsCardChoiceBusy(instance))
{
UpgradeDraftPlugin.SkipRerollService.IsLocalClientControllingPick(instance);
}
}
}
private void OnGUI()
{
//IL_00a2: 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_00fd: 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)
//IL_0172: Unknown result type (might be due to invalid IL or missing references)
//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
//IL_0205: Unknown result type (might be due to invalid IL or missing references)
//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
if (!IsReady())
{
return;
}
CardChoice instance = CardChoice.instance;
if (instance == null)
{
return;
}
int pickrID = instance.pickrID;
if (UpgradeDraftPlugin.SkipRerollService.IsCardChoiceOpen(instance))
{
int skipPoints = UpgradeDraftPlugin.State.GetSkipPoints(pickrID);
bool num = UpgradeDraftPlugin.SkipRerollService.IsLocalClientControllingPick(instance);
int skipPointsForReroll = UpgradeDraftPlugin.Instance.GetSkipPointsForReroll();
string text = ((skipPoints >= skipPointsForReroll) ? "REROLL" : "SKIP");
string text2 = ((skipPoints >= skipPointsForReroll) ? "Pick the 5th card to redraw this choice." : "Pick the 5th card to pass and gain a point.");
float num2 = 390f;
float num3 = 150f;
float num4 = 24f;
float num5 = Mathf.Max(24f, (float)Screen.height * 0.18f);
GUI.Box(new Rect(num4, num5, num2, num3), string.Empty);
GUI.Box(new Rect(num4 + 12f, num5 + 12f, 54f, 54f), "UD", _badgeStyle);
GUI.Label(new Rect(num4 + 78f, num5 + 10f, num2 - 90f, 28f), "Upgrade Draft", _titleStyle);
GUI.Label(new Rect(num4 + 78f, num5 + 38f, num2 - 90f, 22f), $"Skip Points: {skipPoints}/{skipPointsForReroll}", _labelStyle);
GUI.Label(new Rect(num4 + 78f, num5 + 60f, num2 - 90f, 22f), "4 draft cards + 1 action card", _labelStyle);
GUI.Box(new Rect(num4 + 16f, num5 + 88f, 110f, 34f), text, _actionStyle);
if (!num)
{
GUI.Label(new Rect(num4 + 138f, num5 + 94f, num2 - 154f, 22f), "Waiting for the picking player.", _labelStyle);
}
else
{
GUI.Label(new Rect(num4 + 138f, num5 + 94f, num2 - 154f, 22f), text2, _labelStyle);
}
}
}
private static bool IsReady()
{
if ((Object)(object)UpgradeDraftPlugin.Instance == (Object)null || UpgradeDraftPlugin.State == null || UpgradeDraftPlugin.SkipRerollService == null)
{
return false;
}
if (!UpgradeDraftPlugin.Instance.IsSkipRerollOverlayEnabled())
{
return false;
}
return CardChoice.instance != null;
}
}
public sealed class UpgradeCardMarker : MonoBehaviour
{
public bool IsUpgrade;
public int OwnedBefore;
public int OwnedAfter;
public string SourceCardName;
}
public sealed class UpgradeCardVisualService
{
private readonly ManualLogSource _logger;
private readonly UpgradeDraftPlugin _plugin;
private readonly UpgradePreviewService _previewService;
public UpgradeCardVisualService(ManualLogSource logger, UpgradeDraftPlugin plugin, UpgradePreviewService previewService)
{
_logger = logger;
_plugin = plugin;
_previewService = previewService;
}
public void ApplyUpgradeVisual(GameObject spawnedCard, DraftCardEntry entry)
{
if (!_plugin.IsVisualEnabled() || spawnedCard == null || entry == null)
{
return;
}
try
{
PrepareChoiceCard(spawnedCard);
UpgradeCardMarker obj = spawnedCard.GetComponent<UpgradeCardMarker>() ?? spawnedCard.AddComponent<UpgradeCardMarker>();
obj.IsUpgrade = true;
obj.OwnedBefore = entry.OwnedBefore;
obj.OwnedAfter = entry.OwnedAfter;
obj.SourceCardName = entry.Card.cardName;
ApplyTextComponents(spawnedCard, entry);
}
catch (Exception ex)
{
_logger.LogWarning((object)("Failed to apply upgrade visuals on card object '" + ((Object)spawnedCard).name + "'. Error: " + ex.Message));
}
}
public void ApplyUpgradeVisual(GameObject spawnedCard, string sourceCardName, int ownedBefore, int ownedAfter)
{
if (!_plugin.IsVisualEnabled() || spawnedCard == null)
{
return;
}
try
{
PrepareChoiceCard(spawnedCard);
CardInfo component = spawnedCard.GetComponent<CardInfo>();
if (component != null)
{
UpgradeCardMarker upgradeCardMarker = spawnedCard.GetComponent<UpgradeCardMarker>() ?? spawnedCard.AddComponent<UpgradeCardMarker>();
upgradeCardMarker.IsUpgrade = true;
upgradeCardMarker.OwnedBefore = ((ownedBefore >= 0) ? ownedBefore : 0);
upgradeCardMarker.OwnedAfter = ((ownedAfter < 0) ? (upgradeCardMarker.OwnedBefore + 1) : ownedAfter);
upgradeCardMarker.SourceCardName = (string.IsNullOrWhiteSpace(sourceCardName) ? component.cardName : sourceCardName);
ApplyUpgradeTextComponents(spawnedCard, upgradeCardMarker.SourceCardName, upgradeCardMarker.OwnedBefore, upgradeCardMarker.OwnedAfter);
}
}
catch (Exception ex)
{
_logger.LogWarning((object)("Failed to apply networked upgrade visuals on card object '" + ((Object)spawnedCard).name + "'. Error: " + ex.Message));
}
}
public void ApplyActionVisual(GameObject spawnedCard, DraftCardEntry entry, int pickerId)
{
if (spawnedCard != null && entry != null && entry.IsAction)
{
ApplyActionVisual(spawnedCard, entry.ActionType, pickerId);
}
}
public void ApplyActionVisual(GameObject spawnedCard, DraftActionType actionType, int pickerId)
{
if (spawnedCard == null || actionType == DraftActionType.None)
{
return;
}
try
{
PrepareChoiceCard(spawnedCard);
DraftActionCardMarker obj = spawnedCard.GetComponent<DraftActionCardMarker>() ?? spawnedCard.AddComponent<DraftActionCardMarker>();
obj.ActionType = actionType;
obj.PickerId = pickerId;
ApplyActionTextComponents(spawnedCard, actionType);
}
catch (Exception ex)
{
_logger.LogWarning((object)("Failed to apply action card visuals on card object '" + ((Object)spawnedCard).name + "'. Error: " + ex.Message));
}
}
public void PrepareChoiceCard(GameObject spawnedCard)
{
if (spawnedCard == null)
{
return;
}
try
{
Collider2D[] componentsInChildren = spawnedCard.GetComponentsInChildren<Collider2D>(true);
foreach (Collider2D val in componentsInChildren)
{
if (val != null)
{
((Behaviour)val).enabled = false;
}
}
Collider[] componentsInChildren2 = spawnedCard.GetComponentsInChildren<Collider>(true);
foreach (Collider val2 in componentsInChildren2)
{
if (val2 != null)
{
val2.enabled = false;
}
}
Rigidbody[] componentsInChildren3 = spawnedCard.GetComponentsInChildren<Rigidbody>(true);
foreach (Rigidbody val3 in componentsInChildren3)
{
if (val3 != null)
{
val3.detectCollisions = false;
val3.isKinematic = true;
}
}
Rigidbody2D[] componentsInChildren4 = spawnedCard.GetComponentsInChildren<Rigidbody2D>(true);
foreach (Rigidbody2D val4 in componentsInChildren4)
{
if (val4 != null)
{
val4.simulated = false;
}
}
}
catch (Exception ex)
{
if (_plugin.IsVerboseLoggingEnabled())
{
_logger.LogWarning((object)("Failed to prepare card-choice physics for '" + ((Object)spawnedCard).name + "'. Error: " + ex.Message));
}
}
}
private void ApplyTextComponents(GameObject spawnedCard, DraftCardEntry entry)
{
string titleText = _previewService.BuildUpgradeTitle(entry);
string descText = BuildShortUpgradeDescription(entry);
ApplyTextComponents(spawnedCard, titleText, descText, "Upgrade card");
}
private void ApplyUpgradeTextComponents(GameObject spawnedCard, string sourceCardName, int ownedBefore, int ownedAfter)
{
string titleText = "UPGRADE: " + sourceCardName;
string descText = $"Upgrade: grants another copy. Owned: {ownedBefore} -> {ownedAfter}";
ApplyTextComponents(spawnedCard, titleText, descText, "Networked upgrade card");
}
private void ApplyTextComponents(GameObject spawnedCard, string titleText, string descText, string label)
{
List<Component> list = (from c in spawnedCard.GetComponentsInChildren<Component>(true)
where (Object)(object)c != (Object)null
where HasStringTextProperty(((object)c).GetType())
select c).ToList();
if (list.Count == 0)
{
_logger.LogWarning((object)(label + " '" + ((Object)spawnedCard).name + "' has no discovered text components to patch."));
return;
}
bool flag = false;
foreach (Component item in list)
{
string text = ((Object)item.gameObject).name.ToLowerInvariant();
if (!string.IsNullOrWhiteSpace(GetTextProperty(item)))
{
if (text.Contains("title") || text.Contains("name"))
{
SetTextProperty(item, titleText);
flag = true;
}
else if (text.Contains("desc") || text.Contains("description"))
{
SetTextProperty(item, descText);
flag = true;
}
}
}
if (!flag)
{
_logger.LogWarning((object)(label + " '" + ((Object)spawnedCard).name + "' did not expose recognizable title/description text components."));
}
}
private void ApplyActionTextComponents(GameObject spawnedCard, DraftActionType actionType)
{
string value = ((actionType == DraftActionType.Reroll) ? "REROLL" : "SKIP");
string value2 = ((actionType == DraftActionType.Reroll) ? "Spend skip points to redraw this card choice." : "Gain 1 skip point and pass this card choice.");
foreach (Component item in (from c in spawnedCard.GetComponentsInChildren<Component>(true)
where (Object)(object)c != (Object)null
where HasStringTextProperty(((object)c).GetType())
select c).ToList())
{
string text = ((Object)item.gameObject).name.ToLowerInvariant();
if (!string.IsNullOrWhiteSpace(GetTextProperty(item)))
{
if (text.Contains("title") || text.Contains("name"))
{
SetTextProperty(item, value);
}
else if (text.Contains("desc") || text.Contains("description"))
{
SetTextProperty(item, value2);
}
}
}
}
private static string BuildShortUpgradeDescription(DraftCardEntry entry)
{
string text = entry.Card.cardDestription ?? string.Empty;
text = text.Trim();
string text2 = $"Upgrade: grants another copy. Owned: {entry.OwnedBefore} -> {entry.OwnedAfter}";
if (string.IsNullOrWhiteSpace(text))
{
return text2;
}
return text + "\n" + text2;
}
private static bool HasStringTextProperty(Type type)
{
PropertyInfo property = type.GetProperty("text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (property != null && property.PropertyType == typeof(string) && property.CanRead)
{
return property.CanWrite;
}
return false;
}
private static string GetTextProperty(Component component)
{
return ((object)component).GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(component, null) as string;
}
private static void SetTextProperty(Component component, string value)
{
((object)component).GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(component, value, null);
}
}
}
namespace UpgradeDraft.Services
{
public sealed class CardSelectionService
{
private readonly ManualLogSource _logger;
private readonly UpgradeDraftPlugin _plugin;
private readonly PlayerDeckService _deckService;
public CardSelectionService(ManualLogSource logger, UpgradeDraftPlugin plugin, PlayerDeckService deckService)
{
_logger = logger;
_plugin = plugin;
_deckService = deckService;
}
public List<DraftCardEntry> BuildDraftEntries(CardChoice cardChoice, Player player, DraftPlan plan)
{
HashSet<string> blacklist = _plugin.GetBlacklist();
List<CardInfo> eligibleUpgradeCards = _deckService.GetEligibleUpgradeCards(player, blacklist);
HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
List<DraftCardEntry> list = new List<DraftCardEntry>();
foreach (CardInfo item in PickRandomDistinct(eligibleUpgradeCards, plan.ActualUpgradeCount))
{
int ownedCount = _deckService.GetOwnedCount(player, item);
list.Add(new DraftCardEntry(item, isUpgrade: true, ownedCount));
hashSet.Add(_deckService.GetStableCardId(item));
}
List<CardInfo> list2 = SelectNewCards(cardChoice, player, plan.NewCardCount, hashSet, strictUnique: true, strictNotOwned: true);
if (list2.Count < plan.NewCardCount)
{
_logger.LogWarning((object)$"Unable to fill all new-card slots with strict unique+not-owned rules. Needed {plan.NewCardCount}, got {list2.Count}. Trying duplicate-new fallback.");
int wanted = plan.NewCardCount - list2.Count;
list2.AddRange(SelectNewCards(cardChoice, player, wanted, hashSet, strictUnique: false, strictNotOwned: true));
}
if (list2.Count < plan.NewCardCount)
{
_logger.LogWarning((object)$"Still missing new cards after duplicate-new fallback. Needed {plan.NewCardCount}, got {list2.Count}. Trying broad safety fallback.");
int wanted2 = plan.NewCardCount - list2.Count;
list2.AddRange(SelectNewCards(cardChoice, player, wanted2, hashSet, strictUnique: false, strictNotOwned: false));
}
foreach (CardInfo item2 in list2)
{
int ownedCount2 = _deckService.GetOwnedCount(player, item2);
list.Add(new DraftCardEntry(item2, isUpgrade: false, ownedCount2));
hashSet.Add(_deckService.GetStableCardId(item2));
}
if (list.Count < plan.TotalCardCount)
{
_logger.LogWarning((object)$"Draft pool has {list.Count}/{plan.TotalCardCount} cards after all selection fallbacks. Letting vanilla SpawnUniqueCard fill remainder as safety.");
}
return list;
}
private List<CardInfo> SelectNewCards(CardChoice cardChoice, Player player, int wanted, ISet<string> existingCardIds, bool strictUnique, bool strictNotOwned)
{
List<CardInfo> list = new List<CardInfo>();
if (wanted <= 0)
{
return list;
}
int num = 0;
int num2 = Math.Max(1000, wanted * 400);
while (list.Count < wanted && num < num2)
{
num++;
CardInfo randomCardWithCondition = Cards.instance.GetRandomCardWithCondition(player, (Gun)null, (GunAmmo)null, (CharacterData)null, (HealthHandler)null, (Gravity)null, (Block)null, (CharacterStatModifiers)null, BuildSelectionCondition(cardChoice, player, existingCardIds, list, strictUnique, strictNotOwned), 1000);
if (randomCardWithCondition != null && (!strictNotOwned || !_deckService.PlayerOwnsCard(player, randomCardWithCondition)) && !_deckService.IsBlacklisted(randomCardWithCondition, _plugin.GetBlacklist()))
{
string stableCardId = _deckService.GetStableCardId(randomCardWithCondition);
if (!strictUnique || !existingCardIds.Contains(stableCardId))
{
list.Add(randomCardWithCondition);
existingCardIds.Add(stableCardId);
}
}
}
return list;
}
private Func<CardInfo, Player, Gun, GunAmmo, CharacterData, HealthHandler, Gravity, Block, CharacterStatModifiers, bool> BuildSelectionCondition(CardChoice cardChoice, Player player, ISet<string> selectedIds, IEnumerable<CardInfo> localNewCards, bool strictUnique, bool strictNotOwned)
{
HashSet<string> localIds = new HashSet<string>(localNewCards.Where((CardInfo c) => c != null).Select(_deckService.GetStableCardId), StringComparer.Ordinal);
Func<CardInfo, Player, bool> baseCondition = BuildCardChoiceCompatibleCondition(cardChoice);
return delegate(CardInfo card, Player p, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers stats)
{
if (card == null)
{
return false;
}
if (strictNotOwned && _deckService.PlayerOwnsCard(player, card))
{
return false;
}
if (_deckService.IsBlacklisted(card, _plugin.GetBlacklist()))
{
return false;
}
if (!Cards.instance.PlayerIsAllowedCard(player, card))
{
return false;
}
if (!baseCondition(card, player))
{
return false;
}
if (strictUnique)
{
string stableCardId = _deckService.GetStableCardId(card);
if (selectedIds.Contains(stableCardId) || localIds.Contains(stableCardId))
{
return false;
}
}
return true;
};
}
private Func<CardInfo, Player, bool> BuildCardChoiceCompatibleCondition(CardChoice cardChoice)
{
return delegate(CardInfo card, Player player)
{
if (card == null)
{
return false;
}
try
{
if ((Object)(object)cardChoice != (Object)null && cardChoice.pickrID != -1)
{
object fieldOrPropertyValue = ReflectionUtils.GetFieldOrPropertyValue(((Component)player.data).GetComponent("Holding"), "holdable");
Component val = (Component)((fieldOrPropertyValue is Component) ? fieldOrPropertyValue : null);
if (val != null)
{
Gun component = val.GetComponent<Gun>();
Gun component2 = ((Component)card).GetComponent<Gun>();
if (component != null && component2 != null && component2.lockGunToDefault && component.lockGunToDefault)
{
return false;
}
}
}
}
catch (Exception ex)
{
if (_plugin.IsVerboseLoggingEnabled())
{
_logger.LogWarning((object)("CardChoice-compatible condition failed to inspect lockGunToDefault: " + ex.Message));
}
}
return true;
};
}
private List<CardInfo> PickRandomDistinct(List<CardInfo> cards, int amount)
{
List<CardInfo> list = new List<CardInfo>();
if (cards == null || cards.Count == 0 || amount <= 0)
{
return list;
}
List<CardInfo> list2 = cards.Where((CardInfo c) => c != null).ToList();
for (int i = 0; i < list2.Count; i++)
{
int index = Random.Range(i, list2.Count);
CardInfo value = list2[i];
list2[i] = list2[index];
list2[index] = value;
}
for (int j = 0; j < Math.Min(amount, list2.Count); j++)
{
list.Add(list2[j]);
}
return list;
}
}
public sealed class DraftCardNetworkService : IDisposable
{
[CompilerGenerated]
private sealed class <ApplyWhenSpawned>d__9 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public int viewId;
public bool isUpgrade;
public DraftCardNetworkService <>4__this;
public string sourceName;
public int ownedBefore;
public int ownedAfter;
public DraftActionType actionType;
public int pickerId;
private int <attempt>5__2;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <ApplyWhenSpawned>d__9(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
int num = <>1__state;
DraftCardNetworkService draftCardNetworkService = <>4__this;
switch (num)
{
default:
return false;
case 0:
<>1__state = -1;
<attempt>5__2 = 0;
break;
case 1:
<>1__state = -1;
<attempt>5__2++;
break;
}
if (<attempt>5__2 < 90)
{
PhotonView photonView = PhotonNetwork.GetPhotonView(viewId);
if (photonView != null && ((Component)photonView).gameObject != null)
{
if (isUpgrade)
{
draftCardNetworkService._visualService.ApplyUpgradeVisual(((Component)photonView).gameObject, sourceName, ownedBefore, ownedAfter);
}
else if (actionType != 0)
{
draftCardNetworkService._visualService.ApplyActionVisual(((Component)photonView).gameObject, actionType, pickerId);
}
else
{
draftCardNetworkService._visualService.PrepareChoiceCard(((Component)photonView).gameObject);
}
return false;
}
<>2__current = null;
<>1__state = 1;
return true;
}
if (draftCardNetworkService._plugin.IsVerboseLoggingEnabled())
{
draftCardNetworkService._logger.LogWarning((object)$"Timed out waiting for PhotonView {viewId} to apply UpgradeDraft visual sync.");
}
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 byte VisualEventCode = 87;
private const int MaxApplyAttempts = 90;
private readonly ManualLogSource _logger;
private readonly UpgradeDraftPlugin _plugin;
private readonly UpgradeCardVisualService _visualService;
public DraftCardNetworkService(ManualLogSource logger, UpgradeDraftPlugin plugin, UpgradeCardVisualService visualService)
{
_logger = logger;
_plugin = plugin;
_visualService = visualService;
PhotonNetwork.NetworkingClient.EventReceived += OnEventReceived;
}
public void Dispose()
{
if (PhotonNetwork.NetworkingClient != null)
{
PhotonNetwork.NetworkingClient.EventReceived -= OnEventReceived;
}
}
public void BroadcastSpawn(GameObject spawnedCard, DraftCardEntry entry, int pickerId)
{
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Expected O, but got Unknown
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
if (spawnedCard != null && entry != null)
{
PhotonView component = spawnedCard.GetComponent<PhotonView>();
if (component != null)
{
object[] array = new object[7]
{
component.ViewID,
entry.IsUpgrade,
(int)entry.ActionType,
pickerId,
entry.OwnedBefore,
entry.OwnedAfter,
((Object)(object)entry.Card != (Object)null) ? entry.Card.cardName : string.Empty
};
RaiseEventOptions val = new RaiseEventOptions
{
Receivers = (ReceiverGroup)0
};
PhotonNetwork.RaiseEvent((byte)87, (object)array, val, SendOptions.SendReliable);
}
}
}
private void OnEventReceived(EventData photonEvent)
{
if (photonEvent.Code != 87 || !(photonEvent.CustomData is object[] array) || array.Length < 7)
{
return;
}
try
{
int viewId = Convert.ToInt32(array[0]);
bool isUpgrade = Convert.ToBoolean(array[1]);
DraftActionType actionType = (DraftActionType)Convert.ToInt32(array[2]);
int pickerId = Convert.ToInt32(array[3]);
int ownedBefore = Convert.ToInt32(array[4]);
int ownedAfter = Convert.ToInt32(array[5]);
string sourceName = (array[6] as string) ?? string.Empty;
((MonoBehaviour)_plugin).StartCoroutine(ApplyWhenSpawned(viewId, isUpgrade, actionType, pickerId, ownedBefore, ownedAfter, sourceName));
}
catch (Exception ex)
{
_logger.LogWarning((object)("Failed to parse UpgradeDraft visual sync event: " + ex.Message));
}
}
[IteratorStateMachine(typeof(<ApplyWhenSpawned>d__9))]
private IEnumerator ApplyWhenSpawned(int viewId, bool isUpgrade, DraftActionType actionType, int pickerId, int ownedBefore, int ownedAfter, string sourceName)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <ApplyWhenSpawned>d__9(0)
{
<>4__this = this,
viewId = viewId,
isUpgrade = isUpgrade,
actionType = actionType,
pickerId = pickerId,
ownedBefore = ownedBefore,
ownedAfter = ownedAfter,
sourceName = sourceName
};
}
}
public sealed class DraftRollService
{
private readonly ManualLogSource _logger;
private readonly UpgradeDraftPlugin _plugin;
public DraftRollService(ManualLogSource logger, UpgradeDraftPlugin plugin)
{
_logger = logger;
_plugin = plugin;
}
public DraftPlan BuildPlan(int eligibleUpgradeCount)
{
int cardCount = _plugin.GetCardCount();
int rollValue;
int num = RollDesiredUpgradeCount(out rollValue);
int num2 = Math.Min(Math.Max(0, num), Math.Max(0, eligibleUpgradeCount));
DraftPlan draftPlan = new DraftPlan
{
DesiredUpgradeCount = num,
ActualUpgradeCount = num2,
NewCardCount = Math.Max(0, cardCount - num2),
TotalCardCount = cardCount,
RollValue = rollValue,
FallbackReason = string.Empty
};
if (num2 != num)
{
draftPlan.FallbackReason = $"Clamped upgrades from desired {num} to {num2} because only {eligibleUpgradeCount} eligible upgrade card(s) exist.";
_logger.LogWarning((object)draftPlan.FallbackReason);
}
return draftPlan;
}
private int RollDesiredUpgradeCount(out int rollValue)
{
(int, int, int, int) weightedChances = _plugin.GetWeightedChances();
rollValue = Random.Range(0, 100);
int item = weightedChances.Item1;
int num = item + weightedChances.Item2;
int num2 = num + weightedChances.Item3;
if (rollValue < item)
{
return 0;
}
if (rollValue < num)
{
return 1;
}
if (rollValue < num2)
{
return 2;
}
return 3;
}
}
public sealed class PlayerDeckService
{
private readonly ManualLogSource _logger;
private readonly UpgradeDraftPlugin _plugin;
public PlayerDeckService(ManualLogSource logger, UpgradeDraftPlugin plugin)
{
_logger = logger;
_plugin = plugin;
}
public List<CardInfo> GetOwnedCards(Player player)
{
if (player == null)
{
return new List<CardInfo>();
}
try
{
object fieldOrPropertyValue = ReflectionUtils.GetFieldOrPropertyValue(player, "data");
if (fieldOrPropertyValue == null)
{
return new List<CardInfo>();
}
List<CardInfo> list = ReflectionUtils.ToTypedList<CardInfo>(ReflectionUtils.GetFieldOrPropertyValue(fieldOrPropertyValue, "currentCards"));
if (list.Count > 0)
{
return list;
}
list = ReflectionUtils.ToTypedList<CardInfo>(ReflectionUtils.GetFieldOrPropertyValue(fieldOrPropertyValue, "cards"));
if (list.Count > 0)
{
return list;
}
}
catch (Exception ex)
{
_logger.LogWarning((object)$"Failed to read owned cards for player {player.playerID}: {ex.Message}");
}
return new List<CardInfo>();
}
public int GetOwnedCount(Player player, CardInfo card)
{
if (player == null || card == null)
{
return 0;
}
string cardName = ((Object)((Component)card).gameObject).name;
return GetOwnedCards(player).Count((CardInfo c) => c != null && string.Equals(((Object)((Component)c).gameObject).name, cardName, StringComparison.Ordinal));
}
public bool PlayerOwnsCard(Player player, CardInfo card)
{
return GetOwnedCount(player, card) > 0;
}
public List<CardInfo> GetEligibleUpgradeCards(Player player, ISet<string> blacklistLower)
{
List<CardInfo> ownedCards = GetOwnedCards(player);
HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal);
List<CardInfo> list = new List<CardInfo>();
foreach (CardInfo item in ownedCards)
{
if (IsEligibleUpgradeCard(player, item, blacklistLower))
{
string stableCardId = GetStableCardId(item);
if (hashSet.Add(stableCardId))
{
list.Add(item);
}
}
}
return list;
}
public bool IsEligibleUpgradeCard(Player player, CardInfo card, ISet<string> blacklistLower)
{
if (player == null || card == null)
{
return false;
}
if (!PlayerOwnsCard(player, card))
{
return false;
}
if (!card.allowMultiple)
{
return false;
}
if (IsBlacklisted(card, blacklistLower))
{
return false;
}
if (!Cards.instance.PlayerIsAllowedCard(player, card))
{
return false;
}
return true;
}
public bool IsBlacklisted(CardInfo card, ISet<string> blacklistLower)
{
if (card == null || blacklistLower == null || blacklistLower.Count == 0)
{
return false;
}
string item = (card.cardName ?? string.Empty).Trim().ToLowerInvariant();
string item2 = (((Object)(object)((Component)card).gameObject != (Object)null) ? ((Object)((Component)card).gameObject).name : string.Empty).Replace("(Clone)", string.Empty).Trim().ToLowerInvariant();
if (!blacklistLower.Contains(item))
{
return blacklistLower.Contains(item2);
}
return true;
}
public string GetStableCardId(CardInfo card)
{
if (card == null)
{
return "null";
}
if (!string.IsNullOrWhiteSpace(card.cardName))
{
return card.cardName.Trim().ToLowerInvariant();
}
string text = (((Object)(object)((Component)card).gameObject != (Object)null) ? ((Object)((Component)card).gameObject).name : string.Empty);
if (!string.IsNullOrWhiteSpace(text))
{
return text.Replace("(Clone)", string.Empty).Trim().ToLowerInvariant();
}
return ((Object)card).GetInstanceID().ToString();
}
}
internal static class ReflectionUtils
{
internal static object GetFieldOrPropertyValue(object instance, string name)
{
if (instance == null || string.IsNullOrWhiteSpace(name))
{
return null;
}
Type type = instance.GetType();
FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (field != null)
{
return field.GetValue(instance);
}
return type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(instance, null);
}
internal static bool TrySetProperty(object instance, string propertyName, object value)
{
if (instance == null || string.IsNullOrWhiteSpace(propertyName))
{
return false;
}
PropertyInfo property = instance.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (property == null || !property.CanWrite)
{
return false;
}
property.SetValue(instance, value, null);
return true;
}
internal static List<T> ToTypedList<T>(object maybeList) where T : class
{
if (maybeList == null)
{
return new List<T>();
}
if (maybeList is IList<T> source)
{
return source.Where((T item) => item != null).ToList();
}
if (maybeList is IEnumerable enumerable)
{
List<T> list = new List<T>();
{
foreach (object item3 in enumerable)
{
if (item3 is T item2)
{
list.Add(item2);
}
}
return list;
}
}
return new List<T>();
}
}
public sealed class SkipRerollService
{
[CompilerGenerated]
private sealed class <RerollAfterSelectionFrame>d__9 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public CardChoice cardChoice;
public int pickerId;
public SkipRerollService <>4__this;
public int pointsSpent;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <RerollAfterSelectionFrame>d__9(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
int num = <>1__state;
SkipRerollService skipRerollService = <>4__this;
switch (num)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = null;
<>1__state = 1;
return true;
case 1:
{
<>1__state = -1;
if (cardChoice == null)
{
return false;
}
cardChoice.pickrID = pickerId;
UpgradeDraftPlugin.State.ClearDraftPlanOnly("Reroll action card picked.");
Traverse val = Traverse.Create((object)cardChoice).Field("picks");
int value = val.GetValue<int>();
val.SetValue((object)(value + 1));
if (AccessTools.Method(((object)cardChoice).GetType(), "ReplaceCards", (Type[])null, (Type[])null).Invoke(cardChoice, new object[2] { null, true }) is IEnumerator enumerator)
{
UpgradeDraftPlugin.State.MarkRerolledThisPick();
((MonoBehaviour)cardChoice).StartCoroutine(enumerator);
int skipPoints = UpgradeDraftPlugin.State.GetSkipPoints(pickerId);
skipRerollService._logger.LogInfo((object)$"Player {pickerId} picked REROLL. Spent {pointsSpent} skip points (remaining: {skipPoints}).");
}
else
{
val.SetValue((object)value);
skipRerollService._logger.LogWarning((object)"CardChoice.ReplaceCards did not return IEnumerator. Reroll action could not start coroutine.");
}
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 readonly ManualLogSource _logger;
private readonly UpgradeDraftPlugin _plugin;
public SkipRerollService(ManualLogSource logger, UpgradeDraftPlugin plugin)
{
_logger = logger;
_plugin = plugin;
}
public bool IsCardChoiceBusy(CardChoice cardChoice)
{
try
{
object value = Traverse.Create((object)cardChoice).Field("isPlaying").GetValue();
if (value is bool)
{
return (bool)value;
}
}
catch (Exception)
{
}
return false;
}
public bool IsCardChoiceOpen(CardChoice cardChoice)
{
if (cardChoice == null || cardChoice.pickrID < 0)
{
return false;
}
try
{
object value = Traverse.Create((object)cardChoice).Field("IsPicking").GetValue();
bool flag = default(bool);
int num;
if (value is bool)
{
flag = (bool)value;
num = 1;
}
else
{
num = 0;
}
if (((uint)num & (flag ? 1u : 0u)) != 0)
{
return true;
}
}
catch (Exception)
{
}
try
{
if (Traverse.Create((object)cardChoice).Field("spawnedCards").GetValue() is ICollection collection)
{
return collection.Count > 0;
}
}
catch (Exception)
{
}
return false;
}
public bool IsLocalClientControllingPick(CardChoice cardChoice)
{
Player val = ResolvePickingPlayer(cardChoice);
if (val == null)
{
return true;
}
try
{
CharacterData data = val.data;
if (data == null)
{
return true;
}
object fieldOrPropertyValue = ReflectionUtils.GetFieldOrPropertyValue(data, "view");
if (fieldOrPropertyValue == null)
{
return true;
}
object fieldOrPropertyValue2 = ReflectionUtils.GetFieldOrPropertyValue(fieldOrPropertyValue, "IsMine");
if (fieldOrPropertyValue2 is bool)
{
return (bool)fieldOrPropertyValue2;
}
}
catch (Exception ex)
{
if (_plugin.IsVerboseLoggingEnabled())
{
_logger.LogWarning((object)("Unable to resolve local pick ownership. Defaulting to visible controls. Error: " + ex.Message));
}
}
return true;
}
public bool CanReroll(CardChoice cardChoice, int pickerId, out string reason)
{
reason = string.Empty;
if (cardChoice == null || pickerId < 0)
{
reason = "invalid_card_choice";
return false;
}
if (IsCardChoiceBusy(cardChoice))
{
reason = "card_choice_busy";
return false;
}
int skipPointsForReroll = _plugin.GetSkipPointsForReroll();
if (UpgradeDraftPlugin.State.GetSkipPoints(pickerId) < skipPointsForReroll)
{
reason = "not_enough_points";
return false;
}
if (UpgradeDraftPlugin.State.RerolledThisPick && !_plugin.IsMultipleRerollsPerPickAllowed())
{
reason = "already_rerolled_this_pick";
return false;
}
if (AccessTools.Method(((object)cardChoice).GetType(), "ReplaceCards", (Type[])null, (Type[])null) == null)
{
reason = "replace_cards_method_missing";
return false;
}
return true;
}
private Player ResolvePickingPlayer(CardChoice cardChoice)
{
if (cardChoice == null || PlayerManager.instance == null)
{
return null;
}
try
{
if (Convert.ToInt32(Traverse.Create((object)cardChoice).Field("pickerType").GetValue()) == 0)
{
return PlayerManager.instance.GetPlayersInTeam(cardChoice.pickrID).FirstOrDefault();
}
if (cardChoice.pickrID >= 0 && cardChoice.pickrID < PlayerManager.instance.players.Count())
{
return PlayerManager.instance.players[cardChoice.pickrID];
}
}
catch
{
}
return null;
}
public bool TryReroll(CardChoice cardChoice, int pickerId)
{
if (!CanReroll(cardChoice, pickerId, out var reason))
{
if (_plugin.IsVerboseLoggingEnabled())
{
_logger.LogInfo((object)$"Reroll denied for player {pickerId}. Reason={reason}");
}
return false;
}
int skipPointsForReroll = _plugin.GetSkipPointsForReroll();
if (!UpgradeDraftPlugin.State.TryConsumeSkipPoints(pickerId, skipPointsForReroll))
{
_logger.LogWarning((object)$"Failed to consume reroll points for player {pickerId}. This should not happen after CanReroll check.");
return false;
}
((MonoBehaviour)cardChoice).StartCoroutine(RerollAfterSelectionFrame(cardChoice, pickerId, skipPointsForReroll));
return true;
}
[IteratorStateMachine(typeof(<RerollAfterSelectionFrame>d__9))]
private IEnumerator RerollAfterSelectionFrame(CardChoice cardChoice, int pickerId, int pointsSpent)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <RerollAfterSelectionFrame>d__9(0)
{
<>4__this = this,
cardChoice = cardChoice,
pickerId = pickerId,
pointsSpent = pointsSpent
};
}
}
public sealed class UpgradeDraftState
{
private readonly ManualLogSource _logger;
private readonly Queue<DraftCardEntry> _pendingEntries = new Queue<DraftCardEntry>();
private readonly Dictionary<int, DraftCardEntry> _spawnedCardMap = new Dictionary<int, DraftCardEntry>();
private readonly Dictionary<int, int> _skipPointsByPlayerId = new Dictionary<int, int>();
private int _currentPickerId = -999;
private bool _planReady;
private bool _rerolledThisPick;
public bool HasPlanForCurrentPick => _planReady;
public int CurrentPickerId => _currentPickerId;
public bool RerolledThisPick => _rerolledThisPick;
public UpgradeDraftState(ManualLogSource logger)
{
_logger = logger;
}
public void BeginPick(int pickerId)
{
if (_currentPickerId != pickerId)
{
Clear($"Picker changed from {_currentPickerId} to {pickerId}.");
}
_currentPickerId = pickerId;
_rerolledThisPick = false;
}
public void SetPlannedEntries(IEnumerable<DraftCardEntry> entries)
{
_pendingEntries.Clear();
foreach (DraftCardEntry entry in entries)
{
_pendingEntries.Enqueue(entry);
}
_planReady = true;
}
public bool TryDequeueNext(out DraftCardEntry entry)
{
entry = null;
if (_pendingEntries.Count == 0)
{
return false;
}
entry = _pendingEntries.Dequeue();
return true;
}
public void RegisterSpawnedCard(GameObject spawnedCard, DraftCardEntry entry)
{
if (spawnedCard != null && entry != null)
{
_spawnedCardMap[((Object)spawnedCard).GetInstanceID()] = entry;
}
}
public bool TryGetSpawnedEntry(GameObject spawnedCard, out DraftCardEntry entry)
{
entry = null;
if (spawnedCard == null)
{
return false;
}
return _spawnedCardMap.TryGetValue(((Object)spawnedCard).GetInstanceID(), out entry);
}
public void Clear(string reason = "")
{
if (!string.IsNullOrWhiteSpace(reason))
{
_logger.LogDebug((object)("Clearing UpgradeDraft state: " + reason));
}
_pendingEntries.Clear();
_spawnedCardMap.Clear();
_planReady = false;
_currentPickerId = -999;
_rerolledThisPick = false;
}
public void ClearDraftPlanOnly(string reason = "")
{
if (!string.IsNullOrWhiteSpace(reason))
{
_logger.LogDebug((object)("Clearing draft plan only: " + reason));
}
_pendingEntries.Clear();
_spawnedCardMap.Clear();
_planReady = false;
}
public int GetSkipPoints(int playerId)
{
if (!_skipPointsByPlayerId.TryGetValue(playerId, out var value))
{
return 0;
}
return value;
}
public int AddSkipPoint(int playerId)
{
int num = GetSkipPoints(playerId) + 1;
_skipPointsByPlayerId[playerId] = num;
return num;
}
public bool TryConsumeSkipPoints(int playerId, int pointsToConsume)
{
if (pointsToConsume <= 0)
{
return true;
}
int skipPoints = GetSkipPoints(playerId);
if (skipPoints < pointsToConsume)
{
return false;
}
_skipPointsByPlayerId[playerId] = skipPoints - pointsToConsume;
return true;
}
public void MarkRerolledThisPick()
{
_rerolledThisPick = true;
}
}
public sealed class UpgradePreviewService
{
private static readonly Regex NumericRegex = new Regex("([+-]?\\d+(\\.\\d+)?)", RegexOptions.Compiled);
private readonly ManualLogSource _logger;
private readonly UpgradeDraftPlugin _plugin;
public UpgradePreviewService(ManualLogSource logger, UpgradeDraftPlugin plugin)
{
_logger = logger;
_plugin = plugin;
}
public string BuildUpgradeTitle(DraftCardEntry entry)
{
return "UPGRADE: " + entry.Card.cardName;
}
public string BuildUpgradeDescription(DraftCardEntry entry)
{
StringBuilder stringBuilder = new StringBuilder();
string text = entry.Card.cardDestription ?? string.Empty;
if (!string.IsNullOrWhiteSpace(text))
{
stringBuilder.AppendLine(text.Trim());
}
stringBuilder.AppendLine("Upgrade pick: selecting this card grants another copy of the same card.");
stringBuilder.AppendLine($"Owned: {entry.OwnedBefore} -> {entry.OwnedAfter}");
if (_plugin.IsStatPreviewEnabled())
{
string value = BuildStackedStatPreview(entry);
if (!string.IsNullOrWhiteSpace(value))
{
stringBuilder.AppendLine();
stringBuilder.AppendLine(value);
}
}
return stringBuilder.ToString().TrimEnd();
}
public string BuildOwnedLine(DraftCardEntry entry)
{
return $"Owned: {entry.OwnedBefore} -> {entry.OwnedAfter}";
}
public string BuildStackedStatPreview(DraftCardEntry entry)
{
CardInfoStat[] cardStats = entry.Card.cardStats;
if (cardStats == null || cardStats.Length == 0)
{
return "Stack preview: no card stat lines available.";
}
List<string> list = new List<string>();
CardInfoStat[] array = cardStats;
foreach (CardInfoStat val in array)
{
if (TryBuildStackLine(val, entry.OwnedAfter, out var line))
{
list.Add(line);
}
else
{
list.Add(val.stat + ": " + val.amount);
}
}
return string.Join("\n", list);
}
private bool TryBuildStackLine(CardInfoStat stat, int ownedAfter, out string line)
{
line = null;
if (string.IsNullOrWhiteSpace(stat.amount))
{
return false;
}
Match match = NumericRegex.Match(stat.amount);
if (!match.Success)
{
return false;
}
if (!float.TryParse(match.Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
{
return false;
}
string text = stat.amount.Replace(match.Value, string.Empty).Trim();
float value = result * (float)ownedAfter;
if (stat.amount.Contains("%"))
{
line = stat.stat + ": " + stat.amount + " (" + FormatSigned(value) + "% total from this card after pick)";
return true;
}
if (!string.IsNullOrWhiteSpace(text))
{
line = stat.stat + ": " + stat.amount + " (" + FormatSigned(value) + " " + text + " total from this card after pick)";
return true;
}
line = stat.stat + ": " + stat.amount + " (" + FormatSigned(value) + " total from this card after pick)";
return true;
}
private static string FormatSigned(float value)
{
if (!(value >= 0f))
{
return value.ToString("0.##", CultureInfo.InvariantCulture);
}
return $"+{value:0.##}";
}
}
}
namespace UpgradeDraft.Patches
{
[HarmonyPatch(typeof(CardChoice), "Pick")]
internal static class CardChoiceActionPickPatch
{
private static bool Prefix(CardChoice __instance, GameObject pickedCard)
{
if (pickedCard == null)
{
return true;
}
DraftActionCardMarker component = pickedCard.GetComponent<DraftActionCardMarker>();
if (component == null)
{
return true;
}
try
{
if (component.ActionType == DraftActionType.Skip)
{
return !HandleSkip(__instance, pickedCard, component.PickerId);
}
if (component.ActionType == DraftActionType.Reroll)
{
if (UpgradeDraftPlugin.SkipRerollService.TryReroll(__instance, component.PickerId))
{
return false;
}
UpgradeDraftPlugin.Log.LogWarning((object)"REROLL action card failed. Ending the pick without applying action-card stats to avoid corrupting card choice.");
return !HandleActionEndPick(__instance, pickedCard, component.PickerId);
}
}
catch (Exception arg)
{
UpgradeDraftPlugin.Log.LogWarning((object)$"Failed to handle UpgradeDraft action card: {arg}");
}
return false;
}
private static bool HandleSkip(CardChoice cardChoice, GameObject pickedCard, int pickerId)
{
if (cardChoice == null || pickedCard == null || pickerId < 0)
{
return false;
}
int num = UpgradeDraftPlugin.State.AddSkipPoint(pickerId);
UpgradeDraftPlugin.State.ClearDraftPlanOnly("Skip action card picked.");
if (!HandleActionEndPick(cardChoice, pickedCard, pickerId))
{
return false;
}
UpgradeDraftPlugin.Log.LogInfo((object)$"Player {pickerId} picked SKIP and gained 1 skip point (total: {num}).");
return true;
}
private static bool HandleActionEndPick(CardChoice cardChoice, GameObject pickedCard, int pickerId)
{
if (cardChoice == null || pickedCard == null || pickerId < 0)
{
return false;
}
int[] array = AccessTools.Method(typeof(CardChoice), "CardIDs", (Type[])null, (Type[])null)?.Invoke(cardChoice, null) as int[];
PhotonView component = ((Component)cardChoice).GetComponent<PhotonView>();
PhotonView component2 = pickedCard.GetComponent<PhotonView>();
PublicInt component3 = pickedCard.GetComponent<PublicInt>();
if (array == null || component == null || component2 == null || component3 == null)
{
UpgradeDraftPlugin.Log.LogWarning((object)"Skip action card could not access vanilla card-pick RPC data.");
return false;
}
component.RPC("RPCA_DoEndPick", (RpcTarget)0, new object[4] { array, component2.ViewID, component3.theInt, pickerId });
return true;
}
}
[HarmonyPatch(typeof(CardChoice), "RPCA_DoEndPick")]
internal static class CardChoiceEndPickCleanupPatch
{
[CompilerGenerated]
private sealed class <CleanupLeftoverChoiceCards>d__1 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public int[] cardIDs;
public int targetCardID;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <CleanupLeftoverChoiceCards>d__1(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected O, but got Unknown
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = (object)new WaitForSeconds(0.45f);
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
CleanupNow(cardIDs, targetCardID, includePickedCard: false);
<>2__current = (object)new WaitForSeconds(1.05f);
<>1__state = 2;
return true;
case 2:
<>1__state = -1;
CleanupNow(cardIDs, targetCardID, includePickedCard: true);
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 static void Postfix(int[] cardIDs, int targetCardID)
{
if (!((Object)(object)UpgradeDraftPlugin.Instance == (Object)null) && cardIDs != null && cardIDs.Length != 0)
{
((MonoBehaviour)UpgradeDraftPlugin.Instance).StartCoroutine(CleanupLeftoverChoiceCards(cardIDs, targetCardID));
}
}
[IteratorStateMachine(typeof(<CleanupLeftoverChoiceCards>d__1))]
private static IEnumerator CleanupLeftoverChoiceCards(int[] cardIDs, int targetCardID)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <CleanupLeftoverChoiceCards>d__1(0)
{
cardIDs = cardIDs,
targetCardID = targetCardID
};
}
private static void CleanupNow(int[] cardIDs, int targetCardID, bool includePickedCard)
{
foreach (int num in cardIDs)
{
if (!includePickedCard && num == targetCardID)
{
continue;
}
PhotonView photonView = PhotonNetwork.GetPhotonView(num);
if (photonView != null && ((Component)photonView).gameObject != null)
{
UpgradeDraftPlugin.VisualService?.PrepareChoiceCard(((Component)photonView).gameObject);
if (PhotonNetwork.InRoom && photonView.IsMine)
{
PhotonNetwork.Destroy(((Component)photonView).gameObject);
}
else
{
Object.Destroy((Object)(object)((Component)photonView).gameObject);
}
}
}
}
}
[HarmonyPatch(typeof(CardChoice), "StartPick")]
internal static class CardChoiceStartPickPatch
{
private static void Prefix(CardChoice __instance, int pickerIDToSet)
{
if (UpgradeDraftPlugin.State != null)
{
UpgradeDraftPlugin.State.Clear("Starting new StartPick flow.");
UpgradeDraftPlugin.State.BeginPick(pickerIDToSet);
}
}
}
[HarmonyPatch(typeof(CardChoice), "DoPick")]
internal static class CardChoiceDoPickPatch
{
private static void Prefix(CardChoice __instance, int picketIDToSet)
{
if (UpgradeDraftPlugin.State != null)
{
UpgradeDraftPlugin.State.Clear("Starting new DoPick flow.");
UpgradeDraftPlugin.State.BeginPick(picketIDToSet);
}
}
}
internal static class CardChoiceSlotLimiter
{
public static void Apply(CardChoice cardChoice)
{
UpgradeDraftPlugin instance = UpgradeDraftPlugin.Instance;
if ((Object)(object)instance == (Object)null || cardChoice == null)
{
return;
}
int num = instance.GetCardCount() + 1;
if (num <= 0)
{
return;
}
Traverse val = Traverse.Create((object)cardChoice);
Transform[] value = val.Field("children").GetValue<Transform[]>();
if (value != null && value.Length > num)
{
Transform[] array = (Transform[])(object)new Transform[num];
Array.Copy(value, array, num);
val.Field("children").SetValue((object)array);
if (instance.IsVerboseLoggingEnabled())
{
UpgradeDraftPlugin.Log.LogInfo((object)$"Limited CardChoice spawn slots from {value.Length} to {num}.");
}
}
}
}
[HarmonyPatch(typeof(CardChoice), "Start")]
internal static class CardChoiceStartLimitSlotsPatch
{
private static void Postfix(CardChoice __instance)
{
CardChoiceSlotLimiter.Apply(__instance);
}
}
[HarmonyPatch(typeof(CardChoice), "SpawnUniqueCard")]
internal static class CardChoiceSpawnUniqueCardPatch
{
private static bool Prefix(ref GameObject __result, CardChoice __instance, Vector3 pos, Quaternion rot)
{
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
UpgradeDraftPlugin instance = UpgradeDraftPlugin.Instance;
if ((Object)(object)instance == (Object)null || UpgradeDraftPlugin.State == null)
{
return true;
}
try
{
Player val = ResolvePickingPlayer(__instance);
if (val == null)
{
UpgradeDraftPlugin.Log.LogWarning((object)"Could not resolve picking player. Falling back to vanilla SpawnUniqueCard.");
return true;
}
UpgradeDraftPlugin.State.BeginPick(val.playerID);
if (!UpgradeDraftPlugin.State.HasPlanForCurrentPick)
{
BuildPlanForCurrentPick(__instance, val);
}
if (!UpgradeDraftPlugin.State.TryDequeueNext(out var entry) || entry == null || entry.Card == null)
{
if (instance.IsVerboseLoggingEnabled())
{
UpgradeDraftPlugin.Log.LogInfo((object)"No queued draft entry available; falling back to vanilla SpawnUniqueCard.");
}
return true;
}
GameObject val2 = SpawnCardObject(__instance, entry.Card, pos, rot);
if (val2 == null)
{
UpgradeDraftPlugin.Log.LogWarning((object)"Custom spawn returned null. Falling back to vanilla SpawnUniqueCard.");
return true;
}
UpgradeDraftPlugin.VisualService.PrepareChoiceCard(val2);
if (entry.IsAction)
{
UpgradeDraftPlugin.VisualService.ApplyActionVisual(val2, entry, val.playerID);
}
else if (entry.IsUpgrade)
{
UpgradeDraftPlugin.VisualService.ApplyUpgradeVisual(val2, entry);
}
UpgradeDraftPlugin.NetworkService?.BroadcastSpawn(val2, entry, val.playerID);
UpgradeDraftPlugin.State.RegisterSpawnedCard(val2, entry);
__result = val2;
return false;
}
catch (Exception arg)
{
UpgradeDraftPlugin.Log.LogWarning((object)$"UpgradeDraft SpawnUniqueCard patch failed: {arg}");
return true;
}
}
private static void BuildPlanForCurrentPick(CardChoice cardChoice, Player pickingPlayer)
{
int count = UpgradeDraftPlugin.DeckService.GetEligibleUpgradeCards(pickingPlayer, UpgradeDraftPlugin.Instance.GetBlacklist()).Count;
DraftPlan draftPlan = UpgradeDraftPlugin.RollService.BuildPlan(count);
List<DraftCardEntry> list = UpgradeDraftPlugin.SelectionService.BuildDraftEntries(cardChoice, pickingPlayer, draftPlan);
CardInfo val = ResolveActionCardSource(cardChoice);
if (val != null)
{
DraftActionType actionType = ((UpgradeDraftPlugin.State.GetSkipPoints(pickingPlayer.playerID) < UpgradeDraftPlugin.Instance.GetSkipPointsForReroll()) ? DraftActionType.Skip : DraftActionType.Reroll);
list.Add(new DraftCardEntry(val, actionType));
}
else
{
UpgradeDraftPlugin.Log.LogWarning((object)"Unable to resolve an action-card source. The 5th skip/reroll card will not be shown.");
}
UpgradeDraftPlugin.State.SetPlannedEntries(list);
if (!string.IsNullOrWhiteSpace(draftPlan.FallbackReason))
{
UpgradeDraftPlugin.Log.LogWarning((object)draftPlan.FallbackReason);
}
if (UpgradeDraftPlugin.Instance.IsVerboseLoggingEnabled())
{
UpgradeDraftPlugin.Log.LogInfo((object)$"Built draft plan (roll={draftPlan.RollValue}): desiredUpgrades={draftPlan.DesiredUpgradeCount}, actualUpgrades={draftPlan.ActualUpgradeCount}, newCards={draftPlan.NewCardCount}, total={draftPlan.TotalCardCount}, generatedEntries={list.Count}.");
}
}
private static CardInfo ResolveActionCardSource(CardChoice cardChoice)
{
try
{
return Traverse.Create((object)cardChoice).Field("cards").GetValue<CardInfo[]>()?.FirstOrDefault((Func<CardInfo, bool>)((CardInfo card) => card != null && ((Component)card).gameObject != null));
}
catch (Exception ex)
{
UpgradeDraftPlugin.Log.LogWarning((object)("Failed to resolve action-card source: " + ex.Message));
return null;
}
}
private static Player ResolvePickingPlayer(CardChoice cardChoice)
{
try
{
if (Convert.ToInt32(Traverse.Create((object)cardChoice).Field("pickerType").GetValue()) == 0)
{
return PlayerManager.instance.GetPlayersInTeam(cardChoice.pickrID).FirstOrDefault();
}
if (cardChoice.pickrID >= 0 && cardChoice.pickrID < PlayerManager.instance.players.Count())
{
return PlayerManager.instance.players[cardChoice.pickrID];
}
}
catch (Exception ex)
{
UpgradeDraftPlugin.Log.LogWarning((object)("Failed to resolve picking player from CardChoice. Error: " + ex.Message));
}
return null;
}
private static GameObject SpawnCardObject(CardChoice cardChoice, CardInfo sourceCard, Vector3 pos, Quaternion rot)
{
//IL_002d: 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)
if (sourceCard == null)
{
return null;
}
try
{
object? obj = typeof(CardChoice).InvokeMember("Spawn", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, cardChoice, new object[3]
{
((Component)sourceCard).gameObject,
pos,
rot
});
GameObject val = (GameObject)((obj is GameObject) ? obj : null);
if (val == null)
{
return null;
}
CardInfo component = val.GetComponent<CardInfo>();
if (component != null)
{
component.sourceCard = sourceCard;
}
return val;
}
catch (Exception ex)
{
UpgradeDraftPlugin.Log.LogWarning((object)("Failed to spawn custom card object for '" + sourceCard.cardName + "': " + ex.Message));
return null;
}
}
}
[HarmonyPatch(typeof(CardVisuals), "ChangeSelected")]
internal static class CardVisualsChoiceOverlayPatch
{
private static bool Prefix(CardVisuals __instance, bool setSelected)
{
if (!ShouldStabilizeChoiceVisual(__instance))
{
return true;
}
try
{
ApplyStableChoiceVisual(__instance, setSelected);
}
catch (Exception ex)
{
if ((Object)(object)UpgradeDraftPlugin.Instance != (Object)null && UpgradeDraftPlugin.Instance.IsVerboseLoggingEnabled())
{
UpgradeDraftPlugin.Log.LogWarning((object)("Failed to stabilize card-choice visual: " + ex.Message));
}
}
return false;
}
private static bool ShouldStabilizeChoiceVisual(CardVisuals visuals)
{
if (visuals == null || (Object)(object)UpgradeDraftPlugin.Instance == (Object)null)
{
return false;
}
CardChoice instance = CardChoice.instance;
if (instance == null || instance.pickrID < 0 || !instance.IsPicking)
{
return false;
}
return ((Component)visuals).GetComponentInParent<CardInfo>() != null;
}
private static void ApplyStableChoiceVisual(CardVisuals visuals, bool setSelected)
{
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: 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_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: 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_0120: 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)
visuals.isSelected = setSelected;
if (visuals.objectsToToggle != null)
{
GameObject[] objectsToToggle = visuals.objectsToToggle;
foreach (GameObject val in objectsToToggle)
{
if (val != null)
{
val.SetActive(false);
}
}
}
CanvasGroup[] componentsInChildren = ((Component)visuals).GetComponentsInChildren<CanvasGroup>(true);
foreach (CanvasGroup val2 in componentsInChildren)
{
if (val2 != null)
{
val2.alpha = 1f;
}
}
CardAnimation[] componentsInChildren2 = ((Component)visuals).GetComponentsInChildren<CardAnimation>(true);
foreach (CardAnimation val3 in componentsInChildren2)
{
if (val3 != null)
{
((Behaviour)val3).enabled = true;
}
}
CurveAnimation[] componentsInChildren3 = ((Component)visuals).GetComponentsInChildren<CurveAnimation>(true);
foreach (CurveAnimation val4 in componentsInChildren3)
{
if (val4 != null && (int)val4.currentState != 0)
{
val4.PlayIn();
}
}
Color color = (setSelected ? visuals.defaultColor : Color.Lerp(visuals.defaultColor, visuals.chillColor, 0.35f));
if (visuals.images != null)
{
Image[] images = visuals.images;
foreach (Image val5 in images)
{
if (val5 != null)
{
((Graphic)val5).color = color;
}
}
}
if (visuals.nameText != null)
{
((Graphic)visuals.nameText).color = color;
}
ScaleShake component = ((Component)visuals).GetComponent<ScaleShake>();
if (component != null)
{
component.targetScale = (setSelected ? 1.12f : 1f);
}
}
}
}
namespace UpgradeDraft.Models
{
public enum DraftActionType
{
None,
Skip,
Reroll
}
public sealed class DraftCardEntry
{
public CardInfo Card { get; }
public bool IsUpgrade { get; }
public bool IsAction => ActionType != DraftActionType.None;
public DraftActionType ActionType { get; }
public int OwnedBefore { get; }
public int OwnedAfter { get; }
public DraftCardEntry(CardInfo card, bool isUpgrade, int ownedBefore)
{
Card = card ?? throw new ArgumentNullException("card");
IsUpgrade = isUpgrade;
OwnedBefore = ((ownedBefore >= 0) ? ownedBefore : 0);
OwnedAfter = (IsUpgrade ? (OwnedBefore + 1) : OwnedBefore);
ActionType = DraftActionType.None;
}
public DraftCardEntry(CardInfo card, DraftActionType actionType)
{
if (actionType == DraftActionType.None)
{
throw new ArgumentException("Action card entry requires an action type.", "actionType");
}
Card = card ?? throw new ArgumentNullException("card");
ActionType = actionType;
IsUpgrade = false;
OwnedBefore = 0;
OwnedAfter = 0;
}
}
public sealed class DraftPlan
{
public int DesiredUpgradeCount { get; set; }
public int ActualUpgradeCount { get; set; }
public int NewCardCount { get; set; }
public int TotalCardCount { get; set; }
public int RollValue { get; set; }
public string FallbackReason { get; set; }
}
}