Decompiled source of ShrineOfDio v1.6.3

ShrineOfDio.dll

Decompiled 4 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using On.EntityStates.CaptainSupplyDrop;
using On.RoR2;
using R2API.Utils;
using RoR2;
using RoR2.Hologram;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ShrineOfDio")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ShrineOfDio")]
[assembly: AssemblyTitle("ShrineOfDio")]
[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 ShrineOfDio
{
	[BepInPlugin("com.MagnusMagnuson.ShrineOfDio", "ShrineOfDio", "1.6.1")]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class ShrineOfDio : BaseUnityPlugin
	{
		public static ConfigEntry<bool> UseBalancedMode;

		public static ConfigEntry<int> ResurrectionCost;

		public static ConfigEntry<bool> AllowDuringTeleporterCharge;

		public static ConfigEntry<bool> AllowHacking;

		public const int UNINITIALIZED = -2;

		public const int BALANCED_MODE = -1;

		public int clientCost = -2;

		public bool isBalancedMode;

		private HashSet<NetworkUser> isDead = new HashSet<NetworkUser>();

		public void Awake()
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Expected O, but got Unknown
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Expected O, but got Unknown
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Expected O, but got Unknown
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Expected O, but got Unknown
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Expected O, but got Unknown
			InitConfig();
			HackingMainState.PurchaseInteractionIsValidTarget += new hook_PurchaseInteractionIsValidTarget(HackingMainState_PurchaseInteractionIsValidTarget);
			OutsideInteractableLocker.LockPurchasable += new hook_LockPurchasable(OutsideInteractableLocker_LockPurchasable);
			SceneDirector.PlaceTeleporter += (hook_PlaceTeleporter)delegate(orig_PlaceTeleporter orig, SceneDirector self)
			{
				orig.Invoke(self);
				if (!RoR2Application.isInSinglePlayer)
				{
					SpawnShrineOfDio(self);
				}
			};
			ShrineHealingBehavior.FixedUpdate += (hook_FixedUpdate)delegate(orig_FixedUpdate orig, ShrineHealingBehavior self)
			{
				//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cf: Expected O, but got Unknown
				orig.Invoke(self);
				if (!NetworkServer.active && clientCost == -2)
				{
					int cost = Reflection.GetFieldValue<PurchaseInteraction>((object)self, "purchaseInteraction").cost;
					if (cost != clientCost)
					{
						clientCost = cost;
						if (clientCost == -1)
						{
							isBalancedMode = true;
						}
						else
						{
							isBalancedMode = false;
						}
						Type[] array = (from t in typeof(ChestRevealer).Assembly.GetTypes()
							where typeof(IInteractable).IsAssignableFrom(t)
							select t).ToArray();
						for (int i = 0; i < array.Length; i++)
						{
							foreach (MonoBehaviour item in InstanceTracker.FindInstancesEnumerable(array[i]))
							{
								if (((IInteractable)item).ShouldShowOnScanner() && ((object)(IInteractable)item).ToString().ToLower().Contains("shrinehealing"))
								{
									UpdateShrineDisplay(((Component)item).GetComponentInParent<ShrineHealingBehavior>());
								}
							}
						}
					}
				}
			};
			Stage.Start += (hook_Start)delegate(orig_Start orig, Stage self)
			{
				IEnumerator result = orig.Invoke(self);
				if (!RoR2Application.isInSinglePlayer && NetworkServer.active)
				{
					isDead.Clear();
				}
				return result;
			};
			ShrineHealingBehavior.Awake += (hook_Awake)delegate(orig_Awake orig, ShrineHealingBehavior self)
			{
				//IL_0092: 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)
				orig.Invoke(self);
				if (!RoR2Application.isInSinglePlayer)
				{
					PurchaseInteraction fieldValue = Reflection.GetFieldValue<PurchaseInteraction>((object)self, "purchaseInteraction");
					fieldValue.contextToken = "Offer to the Shrine of Dio";
					fieldValue.displayNameToken = "Shrine of Dio";
					self.costMultiplierPerPurchase = 1f;
					if (NetworkServer.active)
					{
						isBalancedMode = UseBalancedMode.Value;
						if (UseBalancedMode.Value)
						{
							fieldValue.costType = (CostTypeIndex)0;
							fieldValue.cost = -1;
							((Component)fieldValue).GetComponent<HologramProjector>().displayDistance = 0f;
							((Component)self).GetComponent<HologramProjector>().displayDistance = 0f;
						}
						else
						{
							fieldValue.costType = (CostTypeIndex)1;
							fieldValue.cost = ResurrectionCost.Value;
						}
					}
					else
					{
						clientCost = -2;
					}
				}
			};
			ShrineHealingBehavior.AddShrineStack += (hook_AddShrineStack)delegate(orig_AddShrineStack orig, ShrineHealingBehavior self, Interactor interactor)
			{
				//IL_0088: Unknown result type (might be due to invalid IL or missing references)
				//IL_0098: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f5: Expected O, but got Unknown
				//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
				//IL_0104: Unknown result type (might be due to invalid IL or missing references)
				//IL_0110: Unknown result type (might be due to invalid IL or missing references)
				//IL_011a: Unknown result type (might be due to invalid IL or missing references)
				//IL_012b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0130: Unknown result type (might be due to invalid IL or missing references)
				//IL_013b: Expected O, but got Unknown
				//IL_0171: Unknown result type (might be due to invalid IL or missing references)
				//IL_0176: Unknown result type (might be due to invalid IL or missing references)
				//IL_017d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0187: Unknown result type (might be due to invalid IL or missing references)
				//IL_0188: Unknown result type (might be due to invalid IL or missing references)
				//IL_018d: Unknown result type (might be due to invalid IL or missing references)
				//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_019e: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a3: 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: Expected O, but got Unknown
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				//IL_0029: Unknown result type (might be due to invalid IL or missing references)
				//IL_0039: Expected O, but got Unknown
				//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
				//IL_01de: Unknown result type (might be due to invalid IL or missing references)
				if (!RoR2Application.isInSinglePlayer)
				{
					if (NetworkServer.active)
					{
						try
						{
							PlayerCharacterMasterController randomDeadCharacter = GetRandomDeadCharacter();
							if ((Object)(object)randomDeadCharacter == (Object)null)
							{
								Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
								{
									baseToken = "无法获取到死亡玩家信息"
								});
								Reflection.SetFieldValue<bool>((object)self, "waitingForRefresh", true);
								Reflection.SetFieldValue<float>((object)self, "refreshTimer", 0.1f);
								Reflection.SetFieldValue<int>((object)self, "maxPurchaseCount", 999999);
							}
							else
							{
								isDead.Remove(randomDeadCharacter.networkUser);
								randomDeadCharacter.master.Respawn(randomDeadCharacter.master.deathFootPosition, ((Component)randomDeadCharacter.master).transform.rotation, false);
								string baseToken = "<color=#beeca1>" + ((Component)interactor).GetComponent<CharacterBody>().GetUserName() + "</color> resurrected <color=#beeca1>" + randomDeadCharacter.networkUser.userName + "</color>";
								Chat.SendBroadcastChat((ChatMessageBase)new SimpleChatMessage
								{
									baseToken = baseToken
								});
								EffectManager.SpawnEffect(Resources.Load<GameObject>("Prefabs/Effects/HippoRezEffect"), new EffectData
								{
									origin = randomDeadCharacter.master.GetBody().footPosition,
									rotation = ((Component)randomDeadCharacter.master).gameObject.transform.rotation
								}, true);
								Reflection.SetFieldValue<bool>((object)self, "waitingForRefresh", true);
								Reflection.SetFieldValue<float>((object)self, "refreshTimer", 0.1f);
								Reflection.SetFieldValue<int>((object)self, "maxPurchaseCount", 999999);
								EffectManager.SpawnEffect(Resources.Load<GameObject>("Prefabs/Effects/ShrineUseEffect"), new EffectData
								{
									origin = ((Component)self).transform.position,
									rotation = Quaternion.identity,
									scale = 1f,
									color = Color32.op_Implicit(Color.green)
								}, true);
								CharacterBody component2 = ((Component)interactor).GetComponent<CharacterBody>();
								if (UseBalancedMode.Value)
								{
									PurchaseInteraction component3 = ((Component)self).GetComponent<PurchaseInteraction>();
									PurchaseInteraction.CreateItemTakenOrb(component2.corePosition, ((Component)component3).gameObject, Items.ExtraLife.itemIndex);
									component2.inventory.RemoveItem(Items.ExtraLife, 1);
									component2.inventory.GiveItem(Items.ExtraLifeConsumed, 1);
								}
							}
						}
						catch (Exception ex)
						{
							Reflection.SetFieldValue<bool>((object)self, "waitingForRefresh", true);
							Reflection.SetFieldValue<float>((object)self, "refreshTimer", 0.1f);
							Reflection.SetFieldValue<int>((object)self, "maxPurchaseCount", 999999);
							((BaseUnityPlugin)this).Logger.LogError((object)ex);
						}
					}
				}
				else
				{
					orig.Invoke(self, interactor);
				}
			};
			CharacterMaster.OnBodyDeath += (hook_OnBodyDeath)delegate(orig_OnBodyDeath orig, CharacterMaster self, CharacterBody masterbody)
			{
				orig.Invoke(self, masterbody);
				if (!RoR2Application.isInSinglePlayer && NetworkServer.active && masterbody.isPlayerControlled)
				{
					PlayerCharacterMasterController component = ((Component)self).GetComponent<PlayerCharacterMasterController>();
					if (!isDead.Contains(component.networkUser))
					{
						isDead.Add(component.networkUser);
					}
				}
			};
			PurchaseInteraction.CanBeAffordedByInteractor += (hook_CanBeAffordedByInteractor)delegate(orig_CanBeAffordedByInteractor orig, PurchaseInteraction self, Interactor interactor)
			{
				if (RoR2Application.isInSinglePlayer)
				{
					return orig.Invoke(self, interactor);
				}
				if (!self.displayNameToken.Contains("Shrine of Dio") && !self.displayNameToken.Contains("SHRINE_HEALING"))
				{
					return orig.Invoke(self, interactor);
				}
				if (isBalancedMode)
				{
					if (((Component)interactor).GetComponent<CharacterBody>().inventory.GetItemCount(Items.ExtraLife) > 0)
					{
						return IsAnyoneDead();
					}
					return false;
				}
				return IsAnyoneDead() && orig.Invoke(self, interactor);
			};
		}

		private bool HackingMainState_PurchaseInteractionIsValidTarget(orig_PurchaseInteractionIsValidTarget orig, PurchaseInteraction purchaseInteraction)
		{
			if (purchaseInteraction.displayNameToken.Equals("Shrine of Dio"))
			{
				return AllowHacking.Value;
			}
			return orig.Invoke(purchaseInteraction);
		}

		private void OutsideInteractableLocker_LockPurchasable(orig_LockPurchasable orig, OutsideInteractableLocker self, PurchaseInteraction purchaseInteraction)
		{
			if (!AllowDuringTeleporterCharge.Value || (!purchaseInteraction.displayNameToken.Equals("Shrine of Dio") && !purchaseInteraction.displayNameToken.Contains("SHRINE_HEALING")))
			{
				orig.Invoke(self, purchaseInteraction);
			}
		}

		private void InitConfig()
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Expected O, but got Unknown
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Expected O, but got Unknown
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			UseBalancedMode = ((BaseUnityPlugin)this).Config.Bind<bool>("Config", "UseBalancedMode", false, new ConfigDescription("Setting this to true will only allow you to resurrect other players for one of your Dio's Best Friend. Turning this off will allow you to instead use gold.", (AcceptableValueBase)null, Array.Empty<object>()));
			ResurrectionCost = ((BaseUnityPlugin)this).Config.Bind<int>("Config", "ResurrectionCost", 300, new ConfigDescription("[Only active if you set UseBalancedMode to false] Cost for a resurrection. Scales with difficulty but doesn't increase each usage. Regular Chest cost is 25, Golden/Legendary Chest is 400. Default is 300.", (AcceptableValueBase)null, Array.Empty<object>()));
			AllowDuringTeleporterCharge = ((BaseUnityPlugin)this).Config.Bind<bool>("Config", "AllowDuringTeleporterCharge", false, new ConfigDescription("Allows the Shrine of Dio to be used while the teleporter charges/prevents lock.", (AcceptableValueBase)null, Array.Empty<object>()));
			AllowHacking = ((BaseUnityPlugin)this).Config.Bind<bool>("Config", "AllowHacking", true, new ConfigDescription("Allows Captain to hack the Shrine of Dio.", (AcceptableValueBase)null, Array.Empty<object>()));
		}

		private void UpdateShrineDisplay(ShrineHealingBehavior self)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			PurchaseInteraction fieldValue = Reflection.GetFieldValue<PurchaseInteraction>((object)self, "purchaseInteraction");
			if (clientCost == -1)
			{
				fieldValue.costType = (CostTypeIndex)0;
				fieldValue.cost = -1;
				((Component)fieldValue).GetComponent<HologramProjector>().displayDistance = 0f;
				((Component)self).GetComponent<HologramProjector>().displayDistance = 0f;
			}
			else
			{
				fieldValue.costType = (CostTypeIndex)1;
				fieldValue.cost = clientCost;
			}
		}

		private int GetDifficultyScaledCost(int baseCost)
		{
			return (int)((double)baseCost * (double)Mathf.Pow(Run.instance.difficultyCoefficient, 1.25f));
		}

		private PlayerCharacterMasterController GetRandomDeadCharacter()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			List<PlayerCharacterMasterController> list = new List<PlayerCharacterMasterController>();
			foreach (NetworkUser item in isDead)
			{
				if (item.master.playerCharacterMasterController.isConnected && (item.master.IsDeadAndOutOfLivesServer() || (Object)(object)item.master.bodyPrefab != (Object)(object)BodyCatalog.GetBodyPrefab(item.NetworkbodyIndexPreference)))
				{
					list.Add(item.master.playerCharacterMasterController);
				}
			}
			if (list.Count == 0)
			{
				return null;
			}
			int index = new Random().Next(list.Count);
			return list[index];
		}

		private bool IsAnyoneDead()
		{
			foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances)
			{
				if (instance.isConnected && (!Object.op_Implicit((Object)(object)instance.master.GetBody()) || !instance.master.GetBody().healthComponent.alive || isNonSurvivor(instance)))
				{
					return true;
				}
			}
			return false;
		}

		private bool isNonSurvivor(PlayerCharacterMasterController enumerator)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			GameObject bodyPrefab = BodyCatalog.GetBodyPrefab(enumerator.networkUser.NetworkbodyIndexPreference);
			if ((Object)(object)bodyPrefab == (Object)null)
			{
				return false;
			}
			if (enumerator.master.hasBody)
			{
				return !((Object)enumerator.networkUser.GetCurrentBody()).name.Split(new char[1] { '(' })[0].Equals(((Object)bodyPrefab).name);
			}
			return false;
		}

		public void SpawnShrineOfDio(SceneDirector self)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Expected O, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			Xoroshiro128Plus val = new Xoroshiro128Plus(Reflection.GetFieldValue<Xoroshiro128Plus>((object)self, "rng").nextUlong);
			if (SceneInfo.instance.countsAsStage)
			{
				SpawnCard val2 = Resources.Load<SpawnCard>("SpawnCards/InteractableSpawnCard/iscShrineHealing");
				GameObject val3 = DirectorCore.instance.TrySpawnObject(new DirectorSpawnRequest(val2, new DirectorPlacementRule
				{
					placementMode = (PlacementMode)4
				}, val));
				if (!UseBalancedMode.Value)
				{
					val3.GetComponent<PurchaseInteraction>().Networkcost = GetDifficultyScaledCost(ResurrectionCost.Value);
				}
			}
		}
	}
}