using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using InfoOverhaul.Delta;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using ShieldsMod.Cards;
using ShieldsMod.Networking;
using ShieldsMod.Poison;
using ShieldsMod.Shield;
using UnboundLib;
using UnboundLib.Cards;
using UnboundLib.GameModes;
using UnboundLib.Networking;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.1", FrameworkDisplayName = ".NET Framework 4.7.1")]
[assembly: AssemblyCompany("ShieldsMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+661a91535814621160b5d94d61679bade4fe1c2d")]
[assembly: AssemblyProduct("Shields Mod for ROUNDS")]
[assembly: AssemblyTitle("ShieldsMod")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.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.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace ShieldsMod
{
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInPlugin("ShieldsMod", "Shields Mod for ROUNDS", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Logger;
private void Awake()
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
Logger = ((BaseUnityPlugin)this).Logger;
SLog.Section("Plugin Awake");
new Harmony("ShieldsMod").PatchAll();
((Component)this).gameObject.AddComponent<ShieldManager>();
((Component)this).gameObject.AddComponent<PoisonResistanceManager>();
ShieldCardRegistrar.RegisterAll();
PoisonCardRegistrar.RegisterAll();
SLog.Line("Plugin ShieldsMod loaded.");
}
}
internal static class SLog
{
private const string Sep = "=====================";
public static void Section(string title)
{
Plugin.Logger.LogInfo((object)"=====================");
Plugin.Logger.LogInfo((object)("[ShieldsMod] " + title));
Plugin.Logger.LogInfo((object)"=====================");
}
public static void Line(string message)
{
Plugin.Logger.LogInfo((object)("[ShieldsMod] " + message));
}
public static void Warn(string message)
{
Plugin.Logger.LogWarning((object)("[ShieldsMod] " + message));
}
public static void Error(string message)
{
Plugin.Logger.LogError((object)("[ShieldsMod] " + message));
}
}
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "ShieldsMod";
public const string PLUGIN_NAME = "Shields Mod for ROUNDS";
public const string PLUGIN_VERSION = "1.0.0";
}
}
namespace ShieldsMod.Shield
{
internal static class ShieldHandRebuild
{
private static Dictionary<string, float> _multiplierByCardName;
internal static void RegisterTier(CardInfo card, float multiplier)
{
if (!((Object)(object)card == (Object)null) && !string.IsNullOrEmpty(card.cardName))
{
if (_multiplierByCardName == null)
{
_multiplierByCardName = new Dictionary<string, float>(StringComparer.Ordinal);
}
_multiplierByCardName[card.cardName] = multiplier;
}
}
internal static void RebuildForPlayer(int playerID)
{
if ((Object)(object)ShieldManager.instance == (Object)null || (Object)(object)PlayerManager.instance == (Object)null)
{
return;
}
Player val = PlayerManager.instance.players.Find((Player p) => p.playerID == playerID);
if (val?.data?.currentCards == null)
{
return;
}
float num = 100f;
int num2 = 0;
if (_multiplierByCardName != null)
{
foreach (CardInfo currentCard in val.data.currentCards)
{
if (!((Object)(object)currentCard == (Object)null))
{
string cardName = currentCard.cardName;
if (string.IsNullOrEmpty(cardName) && (Object)(object)currentCard.sourceCard != (Object)null)
{
cardName = currentCard.sourceCard.cardName;
}
if (!string.IsNullOrEmpty(cardName) && _multiplierByCardName.TryGetValue(cardName, out var value))
{
num *= value;
num2++;
}
}
}
}
ShieldState orCreateShield = ShieldManager.instance.GetOrCreateShield(playerID);
float max = orCreateShield.Max;
orCreateShield.Max = num;
orCreateShield.Current = Mathf.Min(orCreateShield.Current, orCreateShield.Max);
ShieldManager.instance.RefreshVisual(playerID);
SLog.Line($"ShieldHandRebuild player={playerID} tiers={num2} max {max:F0} -> {orCreateShield.Max:F0} current={orCreateShield.Current:F0}");
}
}
public class ShieldManager : MonoBehaviour
{
[CompilerGenerated]
private sealed class <OnBattleStart>d__8 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <OnBattleStart>d__8(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;
instance?.ResetAllForBattle();
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 <OnGameStart>d__10 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <OnGameStart>d__10(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;
instance?.CleanupOrphanedAttachments();
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 <OnPointEnd>d__9 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <OnPointEnd>d__9(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;
instance?.CleanupOrphanedAttachments();
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();
}
}
public static ShieldManager instance;
private readonly Dictionary<int, ShieldState> _shields = new Dictionary<int, ShieldState>();
private readonly Dictionary<int, ShieldVisual> _visuals = new Dictionary<int, ShieldVisual>();
private readonly Dictionary<int, ShieldParryTrigger> _parryTriggers = new Dictionary<int, ShieldParryTrigger>();
private readonly Dictionary<int, float> _poisonDrainBlockedUntil = new Dictionary<int, float>();
private const float PoisonDrainBlockDuration = 4f;
private void Awake()
{
instance = this;
Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
SLog.Section("ShieldManager — Awake");
GameModeManager.AddHook("BattleStart", (Func<IGameModeHandler, IEnumerator>)OnBattleStart);
GameModeManager.AddHook("PointEnd", (Func<IGameModeHandler, IEnumerator>)OnPointEnd);
GameModeManager.AddHook("GameStart", (Func<IGameModeHandler, IEnumerator>)OnGameStart);
}
private void OnDestroy()
{
if ((Object)(object)instance == (Object)(object)this)
{
instance = null;
}
}
[IteratorStateMachine(typeof(<OnBattleStart>d__8))]
private static IEnumerator OnBattleStart(IGameModeHandler gm)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <OnBattleStart>d__8(0);
}
[IteratorStateMachine(typeof(<OnPointEnd>d__9))]
private static IEnumerator OnPointEnd(IGameModeHandler gm)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <OnPointEnd>d__9(0);
}
[IteratorStateMachine(typeof(<OnGameStart>d__10))]
private static IEnumerator OnGameStart(IGameModeHandler gm)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <OnGameStart>d__10(0);
}
public void ResetAllForBattle()
{
_poisonDrainBlockedUntil.Clear();
SLog.Section("ShieldManager — ResetAllForBattle");
if ((Object)(object)PlayerManager.instance == (Object)null)
{
SLog.Warn("PlayerManager.instance is null.");
return;
}
foreach (Player player in PlayerManager.instance.players)
{
if (!((Object)(object)player == (Object)null))
{
ShieldState orCreateShield = GetOrCreateShield(player.playerID);
orCreateShield.ResetToFull();
EnsureAttachments(player, orCreateShield);
RefreshVisual(player.playerID);
SLog.Line($"player={player.playerID} shield={orCreateShield.Current}/{orCreateShield.Max}");
}
}
}
public ShieldState GetOrCreateShield(int playerID)
{
if (!_shields.TryGetValue(playerID, out var value))
{
value = new ShieldState();
_shields[playerID] = value;
}
return value;
}
public ShieldState GetShield(int playerID)
{
return GetOrCreateShield(playerID);
}
public bool TryAbsorbFull(int playerID, float damageAmount, out bool depleted)
{
depleted = false;
ShieldState orCreateShield = GetOrCreateShield(playerID);
if (!orCreateShield.IsActive || damageAmount <= 0f)
{
return false;
}
if (damageAmount >= orCreateShield.Current)
{
orCreateShield.Current = 0f;
depleted = true;
}
else
{
orCreateShield.Current -= damageAmount;
}
RefreshVisual(playerID);
return true;
}
public void MarkPoisonDepleted(int playerID)
{
_poisonDrainBlockedUntil[playerID] = Time.time + 4f;
}
public bool IsPoisonDrainBlocked(int playerID)
{
if (_poisonDrainBlockedUntil.TryGetValue(playerID, out var value))
{
return Time.time < value;
}
return false;
}
public void RefreshVisual(int playerID)
{
if (_visuals.TryGetValue(playerID, out var value) && (Object)(object)value != (Object)null)
{
value.Refresh();
}
if (_parryTriggers.TryGetValue(playerID, out var value2) && (Object)(object)value2 != (Object)null)
{
value2.UpdateEnabled();
}
}
private void EnsureAttachments(Player player, ShieldState state)
{
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
int playerID = player.playerID;
if (!_visuals.TryGetValue(playerID, out var value) || (Object)(object)value == (Object)null)
{
GameObject val = new GameObject($"ShieldVisual_P{playerID}");
val.transform.SetParent(((Component)player).transform, false);
value = val.AddComponent<ShieldVisual>();
value.Init(player, state);
_visuals[playerID] = value;
}
else
{
value.SetState(state);
value.Refresh();
}
if (!_parryTriggers.TryGetValue(playerID, out var value2) || (Object)(object)value2 == (Object)null)
{
GameObject val2 = new GameObject($"ShieldParry_P{playerID}");
val2.transform.SetParent(((Component)player).transform, false);
value2 = val2.AddComponent<ShieldParryTrigger>();
float radius = ShieldVisual.GetBodyRadius(player) * 1.44f;
value2.Init(player, state, radius);
_parryTriggers[playerID] = value2;
}
else
{
value2.SetState(state);
value2.UpdateEnabled();
}
}
private void CleanupOrphanedAttachments()
{
List<int> list = new List<int>();
foreach (KeyValuePair<int, ShieldVisual> visual in _visuals)
{
if ((Object)(object)visual.Value == (Object)null)
{
list.Add(visual.Key);
}
}
foreach (int item in list)
{
_visuals.Remove(item);
}
List<int> list2 = new List<int>();
foreach (KeyValuePair<int, ShieldParryTrigger> parryTrigger in _parryTriggers)
{
if ((Object)(object)parryTrigger.Value == (Object)null)
{
list2.Add(parryTrigger.Key);
}
}
foreach (int item2 in list2)
{
_parryTriggers.Remove(item2);
}
}
}
public class ShieldParryTrigger : MonoBehaviour
{
private Player _owner;
private Block _block;
private CircleCollider2D _trigger;
private ShieldState _state;
private readonly HashSet<int> _recentlyDeflected = new HashSet<int>();
public void Init(Player owner, ShieldState state, float radius)
{
_owner = owner;
_state = state;
_block = ((Component)owner).GetComponent<Block>();
_trigger = ((Component)this).gameObject.AddComponent<CircleCollider2D>();
((Collider2D)_trigger).isTrigger = true;
_trigger.radius = radius;
Rigidbody2D obj = ((Component)this).gameObject.AddComponent<Rigidbody2D>();
obj.bodyType = (RigidbodyType2D)1;
obj.simulated = true;
UpdateEnabled();
}
public void SetState(ShieldState state)
{
_state = state;
}
public void SetRadius(float worldRadius)
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)_owner == (Object)null) && !((Object)(object)_trigger == (Object)null))
{
float num = Mathf.Max(((Component)_owner).transform.localScale.x, 0.01f);
_trigger.radius = worldRadius / num;
}
}
public void UpdateEnabled()
{
if ((Object)(object)_trigger != (Object)null)
{
((Behaviour)_trigger).enabled = _state != null && _state.IsActive;
}
}
private void LateUpdate()
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)_owner == (Object)null))
{
((Component)this).transform.position = ((Component)_owner).transform.position;
float bodyRadius = ShieldVisual.GetBodyRadius(_owner);
SetRadius(bodyRadius * 1.44f);
UpdateEnabled();
}
}
private void OnTriggerEnter2D(Collider2D other)
{
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: 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_00da: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_owner == (Object)null || (Object)(object)_block == (Object)null || _state == null || !_state.IsActive || !_block.IsBlocking())
{
return;
}
ProjectileHit val = ((Component)other).GetComponent<ProjectileHit>() ?? ((Component)other).GetComponentInParent<ProjectileHit>();
if ((Object)(object)val == (Object)null)
{
return;
}
PhotonView component = ((Component)val).GetComponent<PhotonView>();
if ((Object)(object)component == (Object)null || !component.IsMine)
{
return;
}
int instanceID = ((Object)((Component)val).gameObject).GetInstanceID();
if (!_recentlyDeflected.Contains(instanceID) && IsEnemyProjectile(val))
{
Vector3 position = ((Component)val).transform.position;
Vector3 val2 = ((Component)val).transform.forward;
if (((Vector3)(ref val2)).sqrMagnitude < 0.001f)
{
Vector3 val3 = position - ((Component)_owner).transform.position;
val2 = ((Vector3)(ref val3)).normalized;
}
_recentlyDeflected.Add(instanceID);
_block.DoBlock(((Component)val).gameObject, val2, position);
SLog.Line($"Outer parry player={_owner.playerID} projectile={((Object)((Component)val).gameObject).name}");
}
}
private bool IsEnemyProjectile(ProjectileHit projHit)
{
Player val = projHit.ownPlayer;
if ((Object)(object)val == (Object)null)
{
SpawnedAttack component = ((Component)projHit).GetComponent<SpawnedAttack>();
if ((Object)(object)component != (Object)null)
{
val = component.spawner;
}
}
if ((Object)(object)val == (Object)null)
{
return true;
}
if (val.playerID != _owner.playerID)
{
return (Object)(object)((Component)val).transform.root != (Object)(object)((Component)_owner).transform.root;
}
return false;
}
private void OnTriggerExit2D(Collider2D other)
{
ProjectileHit val = ((Component)other).GetComponent<ProjectileHit>() ?? ((Component)other).GetComponentInParent<ProjectileHit>();
if ((Object)(object)val != (Object)null)
{
_recentlyDeflected.Remove(((Object)((Component)val).gameObject).GetInstanceID());
}
}
}
public class ShieldState
{
public const float DefaultMax = 100f;
public float Max = 100f;
public float Current = 100f;
public const float BubbleAlpha = 0.05f;
public float Percent
{
get
{
if (!(Max > 0f))
{
return 0f;
}
return Current / Max;
}
}
public bool IsActive => Current > 0f;
public void ResetToFull()
{
Current = Max;
}
public Color GetBubbleColor(float alpha = 0.05f)
{
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: Unknown result type (might be due to invalid IL or missing references)
float percent = Percent;
Color val = default(Color);
if (percent > 0.65f)
{
((Color)(ref val))..ctor(0.2f, 0.9f, 0.25f);
}
else if (percent > 0.35f)
{
((Color)(ref val))..ctor(0.95f, 0.85f, 0.15f);
}
else
{
((Color)(ref val))..ctor(0.95f, 0.2f, 0.15f);
}
return new Color(val.r, val.g, val.b, alpha);
}
}
public class ShieldVisual : MonoBehaviour
{
public const float SizeMultiplier = 1.44f;
private const int CircleTexSize = 128;
private Player _player;
private SpriteRenderer _sprite;
private ShieldState _state;
public static Sprite SharedCircleSprite { get; private set; }
public void Init(Player player, ShieldState state)
{
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Expected O, but got Unknown
_player = player;
_state = state;
if ((Object)(object)SharedCircleSprite == (Object)null)
{
SharedCircleSprite = CreateCircleSprite(128);
}
GameObject val = new GameObject("ShieldBubbleSprite");
val.transform.SetParent(((Component)this).transform, false);
_sprite = val.AddComponent<SpriteRenderer>();
_sprite.sprite = SharedCircleSprite;
((Renderer)_sprite).sortingOrder = -1;
int num = SortingLayer.NameToID("Player" + (player.playerID + 1));
if (num != 0)
{
((Renderer)_sprite).sortingLayerID = num;
}
player.data.SetWobbleObjectChild(((Component)this).transform);
Refresh();
}
public void SetState(ShieldState state)
{
_state = state;
}
public void Refresh()
{
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: 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_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_sprite == (Object)null || (Object)(object)_player == (Object)null || _state == null)
{
return;
}
if (!_state.IsActive)
{
((Renderer)_sprite).enabled = false;
return;
}
((Renderer)_sprite).enabled = true;
_sprite.color = _state.GetBubbleColor();
float num = GetBodyRadius(_player) * 2f * 1.44f;
Bounds bounds = _sprite.sprite.bounds;
float x = ((Bounds)(ref bounds)).size.x;
if (x > 0.0001f)
{
((Component)_sprite).transform.localScale = Vector3.one * (num / x);
}
}
public static float GetBodyRadius(Player player)
{
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)player == (Object)null)
{
return 0.5f;
}
CircleCollider2D val = ((Component)player).GetComponent<CircleCollider2D>();
if ((Object)(object)val == (Object)null)
{
val = ((Component)player).GetComponentInChildren<CircleCollider2D>();
}
return (((Object)(object)val != (Object)null) ? val.radius : 0.5f) * ((Component)player).transform.localScale.x;
}
private void LateUpdate()
{
if (_state != null && _state.IsActive)
{
Refresh();
}
}
private static Sprite CreateCircleSprite(int size)
{
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Expected O, but got Unknown
//IL_00ab: 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_0079: Unknown result type (might be due to invalid IL or missing references)
Texture2D val = new Texture2D(size, size, (TextureFormat)4, false);
((Texture)val).filterMode = (FilterMode)1;
float num = (float)(size - 1) * 0.5f;
float num2 = num - 1f;
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
float num3 = (float)j - num;
float num4 = (float)i - num;
float num5 = Mathf.Sqrt(num3 * num3 + num4 * num4);
float num6 = ((num5 <= num2) ? 1f : Mathf.Clamp01(1f - (num5 - num2)));
val.SetPixel(j, i, new Color(1f, 1f, 1f, num6));
}
}
val.Apply();
return Sprite.Create(val, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f), (float)size);
}
}
}
namespace ShieldsMod.Poison
{
internal static class PoisonDamageDetector
{
public static bool IsPoisonDamage(Color blinkColor, GameObject damagingWeapon)
{
//IL_003e: 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_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)damagingWeapon != (Object)null)
{
if ((Object)(object)damagingWeapon.GetComponentInChildren<RayHitPoison>() != (Object)null)
{
return true;
}
Transform root = damagingWeapon.transform.root;
if ((Object)(object)root != (Object)null && (Object)(object)((Component)root).GetComponentInChildren<RayHitPoison>() != (Object)null)
{
return true;
}
}
if (blinkColor.g > 0.35f && blinkColor.g >= blinkColor.r)
{
return blinkColor.g >= blinkColor.b;
}
return false;
}
}
internal static class PoisonHandRebuild
{
private static Dictionary<string, float> _reductionByCardName;
internal static void RegisterTier(string cardName, float totalReduction)
{
if (!string.IsNullOrEmpty(cardName))
{
if (_reductionByCardName == null)
{
_reductionByCardName = new Dictionary<string, float>(StringComparer.Ordinal);
}
_reductionByCardName[cardName] = totalReduction;
}
}
internal static float ComputeReductionFromHand(IEnumerable<CardInfo> cards)
{
float num = 0f;
if (_reductionByCardName == null || cards == null)
{
return num;
}
foreach (CardInfo card in cards)
{
if (!((Object)(object)card == (Object)null))
{
string cardName = card.cardName;
if (string.IsNullOrEmpty(cardName) && (Object)(object)card.sourceCard != (Object)null)
{
cardName = card.sourceCard.cardName;
}
if (!string.IsNullOrEmpty(cardName) && _reductionByCardName.TryGetValue(cardName, out var value))
{
num = Math.Max(num, value);
}
}
}
return num;
}
internal static void RebuildForPlayer(int playerID)
{
PoisonResistanceManager.instance?.RebuildForPlayer(playerID);
}
}
public class PoisonResistanceManager : MonoBehaviour
{
[CompilerGenerated]
private sealed class <OnBattleStart>d__3 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <OnBattleStart>d__3(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 ((Object)(object)PlayerManager.instance == (Object)null)
{
return false;
}
foreach (Player player in PlayerManager.instance.players)
{
if ((Object)(object)player != (Object)null)
{
instance?.RebuildForPlayer(player.playerID);
}
}
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();
}
}
public static PoisonResistanceManager instance;
private readonly Dictionary<int, float> _reductionByPlayer = new Dictionary<int, float>();
private void Awake()
{
instance = this;
Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject);
GameModeManager.AddHook("BattleStart", (Func<IGameModeHandler, IEnumerator>)OnBattleStart);
SLog.Section("PoisonResistanceManager — Awake");
}
[IteratorStateMachine(typeof(<OnBattleStart>d__3))]
private static IEnumerator OnBattleStart(IGameModeHandler gm)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <OnBattleStart>d__3(0);
}
private void OnDestroy()
{
if ((Object)(object)instance == (Object)(object)this)
{
instance = null;
}
}
public float GetReduction(int playerID)
{
if (!_reductionByPlayer.TryGetValue(playerID, out var value))
{
return 0f;
}
return value;
}
public float GetReductionPercent(int playerID)
{
return GetReduction(playerID) * 100f;
}
public void RebuildForPlayer(int playerID)
{
if (!((Object)(object)PlayerManager.instance == (Object)null))
{
Player val = PlayerManager.instance.players.Find((Player p) => p.playerID == playerID);
if (val?.data?.currentCards != null)
{
float num = PoisonHandRebuild.ComputeReductionFromHand(val.data.currentCards);
_reductionByPlayer[playerID] = num;
SLog.Line($"PoisonResistance rebuild player={playerID} reduction={num * 100f:F0}%");
}
}
}
public float ApplyResistance(int playerID, float rawDamage, out float resistedAmount)
{
float reduction = GetReduction(playerID);
resistedAmount = rawDamage * reduction;
return rawDamage - resistedAmount;
}
}
}
namespace ShieldsMod.Patches
{
[HarmonyPatch]
internal static class CardDeleteRebuildPatch
{
private static MethodBase TargetMethod()
{
Type type = AccessTools.TypeByName("Rounds2Mod.CardDeleteManager");
if (!(type == null))
{
return AccessTools.Method(type, "URPC_SyncDelete", (Type[])null, (Type[])null);
}
return null;
}
private static bool Prepare()
{
bool num = TargetMethod() != null;
if (!num)
{
SLog.Line("CardDeleteRebuildPatch — Rounds2Mod.CardDeleteManager not found; delete hook skipped.");
}
return num;
}
private static void Postfix(int playerID)
{
ShieldHandRebuild.RebuildForPlayer(playerID);
PoisonHandRebuild.RebuildForPlayer(playerID);
}
}
[HarmonyPatch(typeof(HealthHandler), "DoDamage")]
internal static class HealthHandlerDoDamagePatch
{
[HarmonyPrefix]
private static bool Prefix(HealthHandler __instance, ref Vector2 damage, Vector2 position, Color blinkColor, GameObject damagingWeapon, Player damagingPlayer, bool healthRemoval, bool lethal, bool ignoreBlock)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: 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_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_0155: Unknown result type (might be due to invalid IL or missing references)
if (damage == Vector2.zero)
{
return true;
}
Player component = ((Component)__instance).GetComponent<Player>();
if ((Object)(object)component == (Object)null)
{
return true;
}
float magnitude = ((Vector2)(ref damage)).magnitude;
float num = magnitude;
bool flag = PoisonDamageDetector.IsPoisonDamage(blinkColor, damagingWeapon);
if (flag && (Object)(object)PoisonResistanceManager.instance != (Object)null && PoisonResistanceManager.instance.GetReduction(component.playerID) > 0f)
{
num = PoisonResistanceManager.instance.ApplyResistance(component.playerID, magnitude, out var _);
if (num > 0f)
{
damage = ((Vector2)(ref damage)).normalized * num;
}
else
{
damage = Vector2.zero;
}
}
if (num <= 0f)
{
return false;
}
if ((Object)(object)ShieldManager.instance == (Object)null)
{
if (flag && magnitude > num)
{
LogPoisonPlayerDamage(component.playerID, magnitude, num);
}
return true;
}
if (!ShieldManager.instance.TryAbsorbFull(component.playerID, num, out var depleted))
{
if (flag && ShieldManager.instance.IsPoisonDrainBlocked(component.playerID))
{
SLog.Line($"[ShieldsMod] Poison tick for player {component.playerID} suppressed — shield already drained this DoT.");
return false;
}
if (flag && magnitude > num)
{
LogPoisonPlayerDamage(component.playerID, magnitude, num);
}
return true;
}
if (flag && depleted)
{
ShieldManager.instance.MarkPoisonDepleted(component.playerID);
}
if (flag && magnitude > num)
{
LogPoisonShieldDamage(component.playerID, magnitude, num, depleted);
}
damage = Vector2.zero;
if ((Object)(object)component.data?.view != (Object)null && component.data.view.IsMine)
{
ShieldNetworkSync.BroadcastShieldHealth(component.playerID, ShieldManager.instance.GetShield(component.playerID).Current);
}
return false;
}
private static void LogPoisonPlayerDamage(int playerID, float rawAmount, float actualAmount)
{
SLog.Section("Poison resistance — player");
SLog.Line($"Player {playerID} would've taken {rawAmount:F1} poison damage but took {actualAmount:F1} instead.");
}
private static void LogPoisonShieldDamage(int playerID, float rawAmount, float actualAmount, bool depleted)
{
SLog.Section("Poison resistance — shield");
SLog.Line($"Player {playerID}'s shield would've taken {rawAmount:F1} poison damage but took {actualAmount:F1} instead (depleted={depleted}).");
}
}
}
namespace ShieldsMod.Networking
{
public static class ShieldNetworkSync
{
public static void BroadcastShieldHealth(int playerID, float current)
{
SLog.Line($"BroadcastShieldHealth player={playerID} current={current:F1}");
NetworkingManager.RPC(typeof(ShieldNetworkSync), "URPC_SetShieldHealth", new object[2] { playerID, current });
}
[UnboundRPC]
public static void URPC_SetShieldHealth(int playerID, float current)
{
if (!((Object)(object)ShieldManager.instance == (Object)null))
{
ShieldState orCreateShield = ShieldManager.instance.GetOrCreateShield(playerID);
orCreateShield.Current = Mathf.Clamp(current, 0f, orCreateShield.Max);
ShieldManager.instance.RefreshVisual(playerID);
SLog.Line($"URPC_SetShieldHealth player={playerID} current={orCreateShield.Current:F1}");
}
}
}
}
namespace ShieldsMod.Cards
{
public static class CardArtLoader
{
private static readonly Dictionary<string, GameObject> Cache = new Dictionary<string, GameObject>();
public static string AssetsDirectory => Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "", "assets");
public static GameObject Load(string fileName)
{
//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
//IL_00d9: Expected O, but got Unknown
//IL_0151: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_017c: Unknown result type (might be due to invalid IL or missing references)
//IL_0183: Expected O, but got Unknown
//IL_0192: Unknown result type (might be due to invalid IL or missing references)
//IL_019d: Unknown result type (might be due to invalid IL or missing references)
//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
SLog.Section("CardArtLoader.Load — '" + fileName + "'");
SLog.Line("AssetsDirectory = " + AssetsDirectory);
if (string.IsNullOrEmpty(fileName))
{
SLog.Warn("Load called with empty fileName — returning null.");
return null;
}
if (Cache.TryGetValue(fileName, out var value) && (Object)(object)value != (Object)null)
{
SLog.Line("Returning cached art object.");
return value;
}
string text = Path.Combine(AssetsDirectory, fileName);
SLog.Line("Full path = " + text);
SLog.Line($"File.Exists = {File.Exists(text)}");
if (!File.Exists(text))
{
SLog.Warn("Card art not found at: " + text);
return null;
}
byte[] array = File.ReadAllBytes(text);
SLog.Line($"Read {array.Length} bytes.");
Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
bool flag = ImageConversion.LoadImage(val, array);
SLog.Line($"Texture.LoadImage = {flag}, size = {((Texture)val).width}x{((Texture)val).height}");
if (!flag)
{
SLog.Warn("Failed to decode card art: " + text);
Object.Destroy((Object)(object)val);
return null;
}
((Texture)val).filterMode = (FilterMode)1;
((Texture)val).wrapMode = (TextureWrapMode)1;
Sprite sprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
GameObject val2 = new GameObject("ShieldsCardArt_" + fileName);
Object.DontDestroyOnLoad((Object)(object)val2);
RectTransform obj = val2.AddComponent<RectTransform>();
obj.anchorMin = Vector2.zero;
obj.anchorMax = Vector2.one;
obj.offsetMin = Vector2.zero;
obj.offsetMax = Vector2.zero;
((Transform)obj).localPosition = Vector3.up * 10000f;
Image obj2 = val2.AddComponent<Image>();
obj2.sprite = sprite;
obj2.preserveAspect = true;
((Graphic)obj2).raycastTarget = false;
Cache[fileName] = val2;
SLog.Line("Loaded card art '" + fileName + "' from " + text);
return val2;
}
}
internal static class PoisonCardDeltaRegistrar
{
internal static void RegisterAll()
{
SLog.Section("PoisonCardDeltaRegistrar — RegisterAll");
RegisterTier(PoisonCardRegistry.Lv1, 0.25f);
RegisterTier(PoisonCardRegistry.Lv2, 0.5f);
RegisterTier(PoisonCardRegistry.Lv3, 0.75f);
}
private static void RegisterTier(CardInfo card, float totalReduction)
{
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: Expected O, but got Unknown
if (!((Object)(object)card == (Object)null))
{
PoisonHandRebuild.RegisterTier(card.cardName, totalReduction);
CardDeltaRegistry.RegisterSimple(card.cardName, (SimpleDeltaProvider)((Player player, CardInfo _) => ComputeDelta(player, totalReduction)));
SLog.Line($"Registered poison delta preview for '{card.cardName}' ({totalReduction * 100f:F0}%).");
}
}
private static IReadOnlyList<(string label, string before, string after)> ComputeDelta(Player player, float tierReduction)
{
if ((Object)(object)player == (Object)null || (Object)(object)PoisonResistanceManager.instance == (Object)null)
{
return Array.Empty<(string, string, string)>();
}
float reductionPercent = PoisonResistanceManager.instance.GetReductionPercent(player.playerID);
float num = tierReduction * 100f;
return new(string, string, string)[1] { ("Poison Resistance", $"{reductionPercent:F0}%", $"{num:F0}%") };
}
}
internal static class PoisonCardRegistrar
{
internal static void RegisterAll()
{
SLog.Section("PoisonCardRegistrar — RegisterAll");
CustomCard.BuildCard<PoisonResistanceLv3>((Action<CardInfo>)delegate(CardInfo ci)
{
PoisonCardRegistry.Lv3 = ci;
});
CustomCard.BuildCard<PoisonResistanceLv2>((Action<CardInfo>)delegate(CardInfo ci)
{
PoisonCardRegistry.Lv2 = ci;
});
CustomCard.BuildCard<PoisonResistanceLv1>((Action<CardInfo>)OnLv1Built);
}
private static void OnLv1Built(CardInfo ci)
{
PoisonCardRegistry.Lv1 = ci;
SLog.Line("Registered Poison Resistance LV1: " + ci.cardName);
PoisonCardRegistry.WireLevelChain();
RegisterPrerequisites();
PoisonCardDeltaRegistrar.RegisterAll();
}
private static void RegisterPrerequisites()
{
SLog.Section("PoisonCardRegistrar — RegisterPrerequisites");
if (!RtgPrerequisiteBridge.IsAvailable)
{
SLog.Warn("RoundsTheGathering not available — poison cards will NOT be unlock-gated.");
return;
}
TryRegister(PoisonCardRegistry.Lv2, PoisonCardRegistry.Lv1);
TryRegister(PoisonCardRegistry.Lv3, PoisonCardRegistry.Lv2);
}
private static void TryRegister(CardInfo card, CardInfo required)
{
if (!((Object)(object)card == (Object)null) && !((Object)(object)required == (Object)null))
{
bool flag = RtgPrerequisiteBridge.Register(card.cardName, required.cardName);
SLog.Line($"Prereq: \"{card.cardName}\" requires \"{required.cardName}\" — registered={flag}");
}
}
}
internal static class PoisonCardRegistry
{
internal static CardInfo Lv1;
internal static CardInfo Lv2;
internal static CardInfo Lv3;
internal static void WireLevelChain()
{
SetNext<PoisonResistanceLv1>(Lv1, Lv2);
SetNext<PoisonResistanceLv2>(Lv2, Lv3);
SLog.Line("Poison card level chain wired (LV1 -> LV3).");
}
private static void SetNext<T>(CardInfo from, CardInfo to) where T : PoisonResistanceBase
{
if (!((Object)(object)from == (Object)null))
{
T component = ((Component)from).GetComponent<T>();
if ((Object)(object)component != (Object)null)
{
component.NextLevelCard = to;
}
}
}
}
public abstract class PoisonResistanceBase : CustomCard
{
public CardInfo NextLevelCard;
protected abstract int Level { get; }
protected abstract float TotalReduction { get; }
protected abstract string ArtFileName { get; }
protected abstract Rarity CardRarity { get; }
protected override string GetTitle()
{
return "Poison Resistance " + Roman(Level);
}
protected override string GetDescription()
{
return "Decrease the effects of Poison on both you and your shield by " + PercentLabel(TotalReduction) + ".";
}
protected override CardInfoStat[] GetStats()
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Expected O, but got Unknown
return (CardInfoStat[])(object)new CardInfoStat[1]
{
new CardInfoStat
{
positive = true,
amount = PercentLabel(TotalReduction),
stat = "Poison Resist",
simepleAmount = (SimpleAmount)0
}
};
}
protected override Rarity GetRarity()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return CardRarity;
}
protected override GameObject GetCardArt()
{
return CardArtLoader.Load(ArtFileName);
}
protected override CardThemeColorType GetTheme()
{
return (CardThemeColorType)5;
}
public override string GetModName()
{
return "ShieldsMod";
}
public override void SetupCard(CardInfo cardInfo, Gun gun, ApplyCardStats cardStats, CharacterStatModifiers statModifiers, Block block)
{
cardInfo.allowMultiple = false;
}
public override void OnAddCard(Player player, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers characterStats)
{
if (!((Object)(object)player == (Object)null))
{
PoisonResistanceManager.instance?.RebuildForPlayer(player.playerID);
SLog.Section($"PoisonResistance LV{Level} — OnAddCard");
SLog.Line($"player={player.playerID} totalReduction={TotalReduction * 100f:F0}%");
if ((Object)(object)NextLevelCard != (Object)null)
{
SLog.Line($"Next tier '{NextLevelCard.cardName}' becomes draftable now that LV{Level} is owned.");
}
}
}
private static string PercentLabel(float reduction)
{
return $"{Mathf.RoundToInt(reduction * 100f)}%";
}
private static string Roman(int level)
{
return level switch
{
1 => "I",
2 => "II",
3 => "III",
_ => level.ToString(),
};
}
}
public class PoisonResistanceLv1 : PoisonResistanceBase
{
protected override int Level => 1;
protected override float TotalReduction => 0.25f;
protected override string ArtFileName => "poison_resistance_lv1.png";
protected override Rarity CardRarity => (Rarity)0;
}
public class PoisonResistanceLv2 : PoisonResistanceBase
{
protected override int Level => 2;
protected override float TotalReduction => 0.5f;
protected override string ArtFileName => "poison_resistance_lv2.png";
protected override Rarity CardRarity => (Rarity)2;
}
public class PoisonResistanceLv3 : PoisonResistanceBase
{
protected override int Level => 3;
protected override float TotalReduction => 0.75f;
protected override string ArtFileName => "poison_resistance_lv3.png";
protected override Rarity CardRarity => (Rarity)2;
}
internal static class RtgPrerequisiteBridge
{
private static MethodInfo _registerMethod;
private static bool _resolved;
public static bool IsAvailable
{
get
{
Resolve();
return _registerMethod != null;
}
}
private static void Resolve()
{
if (_resolved)
{
return;
}
_resolved = true;
try
{
Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "RoundsTheGathering");
if (assembly == null)
{
SLog.Warn("RoundsTheGathering assembly not found — shield unlock chain will not be registered.");
return;
}
Type type = assembly.GetType("RoundsTheGathering.CardPrerequisiteRegistry");
if (type == null)
{
SLog.Warn("RoundsTheGathering.CardPrerequisiteRegistry type not found.");
return;
}
_registerMethod = type.GetMethod("RegisterPrerequisite", BindingFlags.Static | BindingFlags.Public, null, new Type[2]
{
typeof(string),
typeof(string)
}, null);
if (_registerMethod == null)
{
SLog.Warn("RegisterPrerequisite(string, string) not found on CardPrerequisiteRegistry.");
}
}
catch (Exception ex)
{
SLog.Error("Failed to resolve RoundsTheGathering registry: " + ex.Message);
}
}
internal static bool Register(string cardName, string requiredCardName)
{
Resolve();
if (_registerMethod == null)
{
return false;
}
try
{
_registerMethod.Invoke(null, new object[2] { cardName, requiredCardName });
return true;
}
catch (Exception ex)
{
SLog.Error("RegisterPrerequisite invoke failed: " + ex.Message);
return false;
}
}
}
internal static class ShieldCardDeltaRegistrar
{
internal static void RegisterAll()
{
SLog.Section("ShieldCardDeltaRegistrar — RegisterAll");
RegisterTier(ShieldCardRegistry.Lv1, 1.1f);
RegisterTier(ShieldCardRegistry.Lv2, 1.25f);
RegisterTier(ShieldCardRegistry.Lv3, 1.5f);
RegisterTier(ShieldCardRegistry.Lv4, 2f);
RegisterTier(ShieldCardRegistry.Lv5, 2.65f);
}
private static void RegisterTier(CardInfo card, float multiplier)
{
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: Expected O, but got Unknown
if ((Object)(object)card == (Object)null)
{
SLog.Warn("ShieldCardDeltaRegistrar — skipped null card reference.");
return;
}
ShieldHandRebuild.RegisterTier(card, multiplier);
CardDeltaRegistry.RegisterSimple(card.cardName, (SimpleDeltaProvider)((Player player, CardInfo _) => ComputeShieldDelta(player, multiplier)));
SLog.Line($"Registered stat-delta preview for '{card.cardName}' (x{multiplier:F2}).");
}
private static IReadOnlyList<(string label, string before, string after)> ComputeShieldDelta(Player player, float multiplier)
{
if ((Object)(object)player == (Object)null || (Object)(object)ShieldManager.instance == (Object)null)
{
return Array.Empty<(string, string, string)>();
}
float max = ShieldManager.instance.GetShield(player.playerID).Max;
float num = max * multiplier;
return new(string, string, string)[1] { ("Shield Max", $"{max:F0}", $"{num:F0}") };
}
}
internal static class ShieldCardRegistrar
{
internal static void RegisterAll()
{
SLog.Section("ShieldCardRegistrar — RegisterAll");
CustomCard.BuildCard<UpgradeShieldLv5>((Action<CardInfo>)OnLv5Built);
CustomCard.BuildCard<UpgradeShieldLv4>((Action<CardInfo>)OnLv4Built);
CustomCard.BuildCard<UpgradeShieldLv3>((Action<CardInfo>)OnLv3Built);
CustomCard.BuildCard<UpgradeShieldLv2>((Action<CardInfo>)OnLv2Built);
CustomCard.BuildCard<UpgradeShieldLv1>((Action<CardInfo>)OnLv1Built);
}
private static void OnLv5Built(CardInfo ci)
{
ShieldCardRegistry.Lv5 = ci;
SLog.Line("Registered LV5: " + ci.cardName);
}
private static void OnLv4Built(CardInfo ci)
{
ShieldCardRegistry.Lv4 = ci;
SLog.Line("Registered LV4: " + ci.cardName);
}
private static void OnLv3Built(CardInfo ci)
{
ShieldCardRegistry.Lv3 = ci;
SLog.Line("Registered LV3: " + ci.cardName);
}
private static void OnLv2Built(CardInfo ci)
{
ShieldCardRegistry.Lv2 = ci;
SLog.Line("Registered LV2: " + ci.cardName);
}
private static void OnLv1Built(CardInfo ci)
{
ShieldCardRegistry.Lv1 = ci;
SLog.Line("Registered LV1: " + ci.cardName);
ShieldCardRegistry.WireLevelChain();
RegisterPrerequisites();
ShieldCardDeltaRegistrar.RegisterAll();
}
private static void RegisterPrerequisites()
{
SLog.Section("ShieldCardRegistrar — RegisterPrerequisites");
if (!RtgPrerequisiteBridge.IsAvailable)
{
SLog.Warn("RoundsTheGathering not available — shield cards will NOT be unlock-gated.");
return;
}
TryRegister(ShieldCardRegistry.Lv2, ShieldCardRegistry.Lv1);
TryRegister(ShieldCardRegistry.Lv3, ShieldCardRegistry.Lv2);
TryRegister(ShieldCardRegistry.Lv4, ShieldCardRegistry.Lv3);
TryRegister(ShieldCardRegistry.Lv5, ShieldCardRegistry.Lv4);
}
private static void TryRegister(CardInfo card, CardInfo required)
{
if ((Object)(object)card == (Object)null || (Object)(object)required == (Object)null)
{
SLog.Warn("Skipping prerequisite registration — a card reference was null.");
return;
}
bool flag = RtgPrerequisiteBridge.Register(card.cardName, required.cardName);
SLog.Line($"Prereq: \"{card.cardName}\" requires \"{required.cardName}\" — registered={flag}");
}
}
internal static class ShieldCardRegistry
{
internal static CardInfo Lv1;
internal static CardInfo Lv2;
internal static CardInfo Lv3;
internal static CardInfo Lv4;
internal static CardInfo Lv5;
internal static void WireLevelChain()
{
SetNext<UpgradeShieldLv1>(Lv1, Lv2);
SetNext<UpgradeShieldLv2>(Lv2, Lv3);
SetNext<UpgradeShieldLv3>(Lv3, Lv4);
SetNext<UpgradeShieldLv4>(Lv4, Lv5);
SLog.Line("Shield card level chain wired (LV1 -> LV5).");
}
private static void SetNext<T>(CardInfo from, CardInfo to) where T : UpgradeShieldHealthBase
{
if (!((Object)(object)from == (Object)null))
{
T component = ((Component)from).GetComponent<T>();
if ((Object)(object)component != (Object)null)
{
component.NextLevelCard = to;
}
}
}
}
public abstract class UpgradeShieldHealthBase : CustomCard
{
public CardInfo NextLevelCard;
protected abstract int Level { get; }
protected abstract float Multiplier { get; }
protected abstract string ArtFileName { get; }
protected abstract Rarity CardRarity { get; }
protected override string GetTitle()
{
return "Upgrade Shield Health " + Roman(Level);
}
protected override string GetDescription()
{
return "Increases max shield health by " + PercentLabel(Multiplier) + ". Multiplies with other shield upgrades.";
}
protected override CardInfoStat[] GetStats()
{
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Expected O, but got Unknown
return (CardInfoStat[])(object)new CardInfoStat[1]
{
new CardInfoStat
{
positive = true,
amount = PercentLabel(Multiplier),
stat = "Shield Max",
simepleAmount = (SimpleAmount)0
}
};
}
protected override Rarity GetRarity()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
return CardRarity;
}
protected override GameObject GetCardArt()
{
return CardArtLoader.Load(ArtFileName);
}
protected override CardThemeColorType GetTheme()
{
return (CardThemeColorType)2;
}
public override string GetModName()
{
return "ShieldsMod";
}
public override void SetupCard(CardInfo cardInfo, Gun gun, ApplyCardStats cardStats, CharacterStatModifiers statModifiers, Block block)
{
cardInfo.allowMultiple = false;
}
public override void OnAddCard(Player player, Gun gun, GunAmmo gunAmmo, CharacterData data, HealthHandler health, Gravity gravity, Block block, CharacterStatModifiers characterStats)
{
if (!((Object)(object)player == (Object)null) && !((Object)(object)ShieldManager.instance == (Object)null))
{
int playerID = player.playerID;
ShieldState orCreateShield = ShieldManager.instance.GetOrCreateShield(playerID);
float max = orCreateShield.Max;
orCreateShield.Max *= Multiplier;
orCreateShield.Current = Mathf.Min(orCreateShield.Current, orCreateShield.Max);
ShieldManager.instance.RefreshVisual(playerID);
SLog.Section($"UpgradeShieldHealth LV{Level} — OnAddCard");
SLog.Line($"player={playerID} multiplier={Multiplier:F2} max {max:F1} -> {orCreateShield.Max:F1}");
if ((Object)(object)NextLevelCard != (Object)null)
{
SLog.Line($"Next tier '{NextLevelCard.cardName}' becomes draftable now that LV{Level} is owned.");
}
else
{
SLog.Line("This is the final tier (no next level).");
}
}
}
private static string PercentLabel(float multiplier)
{
return $"+{Mathf.RoundToInt((multiplier - 1f) * 100f)}%";
}
private static string Roman(int level)
{
return level switch
{
1 => "I",
2 => "II",
3 => "III",
4 => "IV",
5 => "V",
_ => level.ToString(),
};
}
}
public class UpgradeShieldLv1 : UpgradeShieldHealthBase
{
protected override int Level => 1;
protected override float Multiplier => 1.1f;
protected override string ArtFileName => "lv1_artwork.png";
protected override Rarity CardRarity => (Rarity)0;
}
public class UpgradeShieldLv2 : UpgradeShieldHealthBase
{
protected override int Level => 2;
protected override float Multiplier => 1.25f;
protected override string ArtFileName => "lv2_artwork.png";
protected override Rarity CardRarity => (Rarity)0;
}
public class UpgradeShieldLv3 : UpgradeShieldHealthBase
{
protected override int Level => 3;
protected override float Multiplier => 1.5f;
protected override string ArtFileName => "lv3_artwork.png";
protected override Rarity CardRarity => (Rarity)1;
}
public class UpgradeShieldLv4 : UpgradeShieldHealthBase
{
protected override int Level => 4;
protected override float Multiplier => 2f;
protected override string ArtFileName => "lv4_artwork.png";
protected override Rarity CardRarity => (Rarity)1;
}
public class UpgradeShieldLv5 : UpgradeShieldHealthBase
{
protected override int Level => 5;
protected override float Multiplier => 2.65f;
protected override string ArtFileName => "lv5_artwork.png";
protected override Rarity CardRarity => (Rarity)2;
}
}