Decompiled source of Survival Mode v0.1.0

localpcnerd.SurvivalMode.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.Security;
using System.Security.Permissions;
using Atlas.MappingComponents.Sandbox;
using BepInEx;
using BepInEx.Logging;
using FistVR;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Sodalite.Api;
using Sodalite.Utilities;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using localpcnerd.SurvivalMode;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyCompany("localpcnerd")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Survival, a wave-based gamemode for H3VR.")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("localpcnerd.SurvivalMode")]
[assembly: AssemblyTitle("Survival Mode")]
[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 BepInEx
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class BepInAutoPluginAttribute : Attribute
	{
		public BepInAutoPluginAttribute(string id = null, string name = null, string version = null)
		{
		}
	}
}
namespace BepInEx.Preloader.Core.Patching
{
	[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	[Conditional("CodeGeneration")]
	internal sealed class PatcherAutoPluginAttribute : Attribute
	{
		public PatcherAutoPluginAttribute(string id = null, string name = null, string version = null)
		{
		}
	}
}
namespace Gamemodes
{
	public class AmmoSupply : MonoBehaviour
	{
		private SurvivalShop ss;

		public void Start()
		{
			ss = ((Component)this).GetComponent<SurvivalShop>();
		}

		public void SupplyPlayerWithAmmo()
		{
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			if (SurvivalManager.Instance.currentMoney < ss.ammoRefilPrice)
			{
				return;
			}
			Debug.Log((object)"starting ammo buy.");
			Debug.Log((object)("empty hand " + HasEmptyHand()));
			Debug.Log((object)("gun in hand " + HasGunInHand()));
			if (CanPlayerBeSupplied())
			{
				if ((Object)(object)SurvivalManager.Instance.ObjectBoughtSound != (Object)null)
				{
					SurvivalManager.Instance.source.PlayOneShot(SurvivalManager.Instance.ObjectBoughtSound);
				}
				SurvivalManager.Instance.currentMoney -= ss.ammoRefilPrice;
				FVRViveHand val = ((IEnumerable<FVRViveHand>)GM.CurrentMovementManager.Hands).FirstOrDefault((Func<FVRViveHand, bool>)((FVRViveHand o) => (Object)(object)o.CurrentInteractable == (Object)null));
				FVRInteractiveObject currentInteractable = ((IEnumerable<FVRViveHand>)GM.CurrentMovementManager.Hands).FirstOrDefault((Func<FVRViveHand, bool>)((FVRViveHand o) => (Object)(object)o.CurrentInteractable != (Object)null)).CurrentInteractable;
				FVRPhysicalObject val2 = (FVRPhysicalObject)(object)((currentInteractable is FVRPhysicalObject) ? currentInteractable : null);
				Debug.Log((object)val2);
				FVRPhysicalObject val3 = SpawnAmmoObjectForGun(val2, ((Component)val).transform.position, ((Component)val).transform.rotation);
				if (!((Object)(object)val3 == (Object)null))
				{
					val.RetrieveObject(val3);
				}
			}
		}

		private bool CanPlayerBeSupplied()
		{
			return HasEmptyHand() && HasGunInHand();
		}

		private bool HasEmptyHand()
		{
			return GM.CurrentMovementManager.Hands.Any((FVRViveHand o) => (Object)(object)o.CurrentInteractable == (Object)null);
		}

		private bool HasGunInHand()
		{
			return GM.CurrentMovementManager.Hands.Any((FVRViveHand o) => o.CurrentInteractable is FVRFireArm);
		}

		private FVRPhysicalObject SpawnAmmoObjectForGun(FVRPhysicalObject firearm, Vector3 spawnPosition, Quaternion spawnRotation)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			FVRObject ammoObject = GetAmmoObject(firearm.ObjectWrapper);
			Debug.Log((object)ammoObject);
			if ((Object)(object)ammoObject == (Object)null)
			{
				Debug.Log((object)"RETURNING NULL");
				return null;
			}
			return Object.Instantiate<GameObject>(((AnvilAsset)ammoObject).GetGameObject(), spawnPosition, spawnRotation).GetComponent<FVRPhysicalObject>();
		}

		private FVRObject GetAmmoObject(FVRObject fvrObject)
		{
			if (fvrObject.CompatibleMagazines.Count > 0)
			{
				foreach (FVRObject compatibleMagazine in fvrObject.CompatibleMagazines)
				{
					Debug.Log((object)compatibleMagazine);
				}
				return SodaliteUtils.GetRandom<FVRObject>((IList<FVRObject>)fvrObject.CompatibleMagazines);
			}
			if (fvrObject.CompatibleClips.Count > 0)
			{
				foreach (FVRObject compatibleClip in fvrObject.CompatibleClips)
				{
					Debug.Log((object)compatibleClip);
				}
				return SodaliteUtils.GetRandom<FVRObject>((IList<FVRObject>)fvrObject.CompatibleClips);
			}
			if (fvrObject.CompatibleSpeedLoaders.Count > 0)
			{
				foreach (FVRObject compatibleSpeedLoader in fvrObject.CompatibleSpeedLoaders)
				{
					Debug.Log((object)compatibleSpeedLoader);
				}
				return SodaliteUtils.GetRandom<FVRObject>((IList<FVRObject>)fvrObject.CompatibleSpeedLoaders);
			}
			if (fvrObject.CompatibleSingleRounds.Count > 0)
			{
				foreach (FVRObject compatibleSingleRound in fvrObject.CompatibleSingleRounds)
				{
					Debug.Log((object)compatibleSingleRound);
				}
				return SodaliteUtils.GetRandom<FVRObject>((IList<FVRObject>)fvrObject.CompatibleSingleRounds);
			}
			return null;
		}
	}
}
namespace localpcnerd.SurvivalMode
{
	[BepInProcess("h3vr.exe")]
	[BepInPlugin("localpcnerd.SurvivalMode", "Survival Mode", "1.0.0")]
	public class SurvivalModePlugin : BaseUnityPlugin
	{
		public const string Id = "localpcnerd.SurvivalMode";

		internal static ManualLogSource Logger { get; private set; }

		public static string Name => "Survival Mode";

		public static string Version => "1.0.0";

		private void Awake()
		{
			Logger = ((BaseUnityPlugin)this).Logger;
			Logger.LogMessage((object)("Survival mode plugin loaded. Currently installed version: " + Version));
		}
	}
	public class SurvivalItemID : MonoBehaviour
	{
		[Header("Primary ID")]
		[Tooltip("The id of the wanted object. Find these via MetaRipper.")]
		public string id;

		[Tooltip("The display name for the item.")]
		public string itemName;

		public int price;

		public Text buttonText;

		[Header("Optional IDs (for mags, extras, etc)")]
		[Tooltip("The secondary ID, usually associated with a mag, clip, single round, or speedloader.")]
		public string secondaryId;

		[Tooltip("Number of times to spawn secondary (ex. set to 3 to spawn 3 mags, if that's your secondary.)")]
		public int timesToSpawnSecondary;

		[Tooltip("An expandable list of IDs to spawn with your primary ID.")]
		public string[] tertiaryIds;

		private SurvivalShop sshop;

		private void Update()
		{
			if ((Object)(object)sshop == (Object)null)
			{
				sshop = ((Component)this).GetComponentInParent<SurvivalShop>();
			}
			buttonText.text = itemName + " - $" + price;
		}

		public void Purchase()
		{
			if (SurvivalManager.Instance.currentMoney < price)
			{
				return;
			}
			SurvivalManager.Instance.currentMoney -= price;
			if ((Object)(object)SurvivalManager.Instance.ObjectBoughtSound != (Object)null)
			{
				SurvivalManager.Instance.source.PlayOneShot(SurvivalManager.Instance.ObjectBoughtSound);
			}
			sshop.primarySpawnPoint.ObjectId = id;
			sshop.primarySpawnPoint.Spawn();
			if (secondaryId != null)
			{
				sshop.secondarySpawnPoint.ObjectId = secondaryId;
				for (int i = 0; i < timesToSpawnSecondary; i++)
				{
					sshop.secondarySpawnPoint.Spawn();
				}
			}
			if (tertiaryIds != null)
			{
				for (int j = 0; j < tertiaryIds.Length; j++)
				{
					sshop.tertiarySpawnPoint.ObjectId = tertiaryIds[j];
					sshop.tertiarySpawnPoint.Spawn();
				}
			}
		}
	}
	public class SurvivalManager : MonoBehaviour
	{
		public enum SosigAttackBehaviour
		{
			directlyTargetPlayer,
			useAttackPoints
		}

		public enum SosigSpawnMethod
		{
			allAtOnce,
			trickleIn
		}

		public enum difficulty
		{
			easy,
			med,
			hard
		}

		public static SurvivalManager Instance;

		[Header("Hover Over Variables To Read The Tooltips!!!")]
		[Tooltip("The name your map will be saved as in PlayerPrefs, so you can keep scores separate from map to map.")]
		public string mapName;

		[Header("Player Spawning")]
		[Tooltip("ex. for trigger from box collider on manager object. if using UI, set to false and assign StartGame() via unity event")]
		public bool usePhysicalTrigger;

		[Tooltip("The tag on the physical trigger object. Ignore if using UI.")]
		public string physicalTriggerTag;

		[Tooltip("Teleport to a specified location on start.")]
		public bool doTeleport;

		[Tooltip("The point you teleport to on start, if DoTeleport is enabled.")]
		public Transform teleportPoint;

		[Header("Player Starting Gear")]
		public string primaryItem;

		public ObjectSpawnPoint primarySpawnPoint;

		public string primaryAmmo;

		public ObjectSpawnPoint primaryAmmoSpawnPoint;

		public int primaryAmmoAmount;

		public string[] secondaryItems;

		public ObjectSpawnPoint[] secondarySpawnPoints;

		[Header("Sosigs")]
		[Tooltip("Possible spawn points for sosigs. Should be as many as possible to increase randomization and ensure they always have a valid point no matter where the player is.")]
		public Transform[] SpawnPoints;

		[Tooltip("Early round sosigs. Should be killable by small calibers.")]
		public SosigEnemyID[] lowTierSosigs;

		[Tooltip("Med tier sosigs. Should be killable by small-med calibers.")]
		public SosigEnemyID[] medTierSosigs;

		[Tooltip("Endgame/Boss sosigs. Should be a challenge to kill.")]
		public SosigEnemyID[] highTierSosigs;

		[Tooltip("Max number of sosigs spawned at any time for performance reasons. Rounds can contain as many sosigs as you want, but this is as many as can be actively spawned at one time.")]
		public int maxSosigsSpawnable = 10;

		[Tooltip("The base amount of sosigs spawned before the round multiplier is applied. Recommended to leave at default.")]
		public int baseSosigsEasy = 4;

		[Tooltip("The base amount of sosigs spawned before the round multiplier is applied. Recommended to leave at default.")]
		public int baseSosigsMed = 5;

		[Tooltip("The base amount of sosigs spawned before the round multiplier is applied. Recommended to leave at default.")]
		public int baseSosigsHard = 6;

		[Tooltip("To prevent sosigs from spawning directly in front of the player, they must be this far away from the players current position.")]
		public float SpawnpointDisableDistance = 12f;

		[Header("Sosig Attack Behaviour")]
		[Tooltip("DirectTargetPlayer: Sosigs will directly funnel to the players active position instead of going to a preset point. Ideal for larger or more complex maps, but can potentially overwhelm player easier. AttackPoints: The points that sosigs will attack unless the player is seen. Should generally funnel to the center of the action to avoid lost sosigs. Best for small or non-complex maps.")]
		public SosigAttackBehaviour AttackBehaviour;

		[Tooltip("The points that sosigs will attack unless the player is seen. Should generally funnel to the center of the action to avoid lost sosigs. Best for small or non-complex maps.")]
		public Transform[] attackPoints;

		[Header("Sosig Spawn Method")]
		[Tooltip("AllAtOnce: Spawns all possible sosigs at once. Better for large maps or if trying to overwhelm players. TrickleIn: Slowly spawn sosigs over time. More manageable but leads to slow spawn rates for med-large maps.")]
		public SosigSpawnMethod spawnMethod;

		[Tooltip("The time in between sosig spawns when trickle spawning is enabled.")]
		public float TrickleRate = 1f;

		[Header("Rounds")]
		[Tooltip("IMPORTANT: DO NOT TOUCH. Used to determine how far into the game player is, and what enemies to spawn per round. Visible mostly for debug purposes.")]
		[HideInInspector]
		public float roundMultiplier = 1f;

		[Tooltip("The time before rounds will start, in seconds.")]
		public float timeBeforeRounds = 3f;

		[Tooltip("The time between rounds, in seconds. (90 = 1m 30s, for example)")]
		public float timeBetweenRounds = 20f;

		[Tooltip("Money gets multiplied the faster a round is completed. This is the time threshold for how quickly you need to beat a round. This scales with the number of sosigs spawned.")]
		public float quickRoundThreshold;

		[Header("Shop + Money")]
		public int currentMoney;

		public int moneyForRoundBeat = 500;

		public int moneyforKilledSosig = 100;

		[Header("Recyclers")]
		[HideInInspector]
		public bool isLimitedAmmo = true;

		public SurvivalRecycler[] recyclers;

		[Header("UI")]
		public Text[] moneyTexts;

		public Text[] roundTexts;

		[Header("SFX")]
		public AudioSource source;

		public AudioClip startSound;

		public AudioClip endSound;

		public AudioClip roundWonSound;

		public AudioClip roundStartSound;

		public AudioClip ObjectBoughtSound;

		[Header("Endgame")]
		public Transform endgameTeleportPoint;

		public Text highscoreRound;

		[Header("Extras + Bits for mapmakers")]
		[Tooltip("Used for Debug mode.")]
		public GameObject itemSpawner;

		[HideInInspector]
		public bool debugMode = false;

		public UnityEvent OnRoundEnd = new UnityEvent();

		public UnityEvent OnRoundStarted = new UnityEvent();

		public UnityEvent OnGameStarted = new UnityEvent();

		public UnityEvent OnGameEnd = new UnityEvent();

		[HideInInspector]
		public bool gameRunning;

		[HideInInspector]
		public int kills;

		[HideInInspector]
		public int currentRound;

		[HideInInspector]
		public float score;

		private int sosigsamount;

		private int sosigsinround;

		private int sosigsinroundtotal;

		private int sosigsrounded;

		private bool aresosigsspawnedandadded;

		private bool tryspawnsosigs = false;

		[HideInInspector]
		public int bosssosigrounded = 2;

		[HideInInspector]
		public bool isbossround = false;

		[HideInInspector]
		public difficulty _diff;

		[HideInInspector]
		public List<SurvivalSosigTracker> currentspawnedsosigs = new List<SurvivalSosigTracker>();

		private Vector3 lastKnownPos = Vector3.zero;

		private readonly SpawnOptions _spawnOptions = new SpawnOptions
		{
			SpawnState = (SosigOrder)7,
			SpawnActivated = true,
			EquipmentMode = (EquipmentSlots)7,
			SpawnWithFullAmmo = true,
			IFF = 1
		};

		public void Start()
		{
			Instance = this;
			((MonoBehaviour)this).StartCoroutine(UpdateAttackPos());
			itemSpawner.SetActive(false);
		}

		private void Update()
		{
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			switch (_diff)
			{
			case difficulty.easy:
				sosigsamount = baseSosigsEasy;
				break;
			case difficulty.med:
				sosigsamount = baseSosigsMed;
				break;
			case difficulty.hard:
				sosigsamount = baseSosigsHard;
				break;
			}
			foreach (SurvivalSosigTracker currentspawnedsosig in currentspawnedsosigs)
			{
				if (currentspawnedsosig.isDead)
				{
					currentspawnedsosig.sosig.ClearSosig();
					currentspawnedsosigs.Remove(currentspawnedsosig);
					currentMoney += moneyforKilledSosig;
					break;
				}
			}
			if (gameRunning)
			{
				if (currentspawnedsosigs.Count <= 0 && aresosigsspawnedandadded)
				{
					Debug.Log((object)"0 or fewer currentspawnedsosigs detected, calling EndRound.");
					aresosigsspawnedandadded = false;
					EndRound();
					gameRunning = false;
				}
				Text[] array = moneyTexts;
				foreach (Text val in array)
				{
					val.text = "$: " + currentMoney;
				}
				Text[] array2 = roundTexts;
				foreach (Text val2 in array2)
				{
					val2.text = "Round: " + currentRound;
				}
				if (GM.CurrentPlayerBody.GetPlayerHealth() <= 0f)
				{
					GM.CurrentSceneSettings.DeathResetPoint = endgameTeleportPoint;
					EndGame();
				}
				if (AttackBehaviour == SosigAttackBehaviour.directlyTargetPlayer && currentspawnedsosigs.Count > 0)
				{
					foreach (SurvivalSosigTracker currentspawnedsosig2 in currentspawnedsosigs)
					{
						currentspawnedsosig2.sosig.UpdateAssaultPoint(lastKnownPos);
					}
				}
				float num = 0f;
				num += Time.deltaTime;
				if (tryspawnsosigs && spawnMethod == SosigSpawnMethod.allAtOnce && currentspawnedsosigs.Count < maxSosigsSpawnable)
				{
					if (isbossround)
					{
						DoSpawns(highTierSosigs, GetViableSpawnPoint());
						Debug.Log((object)"trying to call spawns");
					}
					else if (roundMultiplier >= 2.5f)
					{
						DoSpawns(medTierSosigs, GetViableSpawnPoint());
						Debug.Log((object)"trying to call spawns");
					}
					else
					{
						DoSpawns(lowTierSosigs, GetViableSpawnPoint());
						Debug.Log((object)"trying to call spawns");
					}
				}
			}
			if (isLimitedAmmo)
			{
				GM.CurrentSceneSettings.IsSpawnLockingEnabled = false;
				SurvivalRecycler[] array3 = recyclers;
				foreach (SurvivalRecycler survivalRecycler in array3)
				{
					survivalRecycler.isEnabled = true;
					survivalRecycler.particleSystem.Play();
					survivalRecycler.canSellMagazines = true;
					survivalRecycler.canSellMelee = true;
					survivalRecycler.canSellWeapons = true;
				}
			}
			else
			{
				GM.CurrentSceneSettings.IsSpawnLockingEnabled = true;
				SurvivalRecycler[] array4 = recyclers;
				foreach (SurvivalRecycler survivalRecycler2 in array4)
				{
					survivalRecycler2.isEnabled = true;
					survivalRecycler2.canSellMagazines = false;
					survivalRecycler2.canSellMelee = true;
					survivalRecycler2.canSellWeapons = true;
				}
			}
		}

		public Transform GetViableSpawnPoint()
		{
			//IL_001f: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			List<Transform> list = new List<Transform>();
			for (int i = 0; i < SpawnPoints.Length; i++)
			{
				Debug.Log((object)"Trying to find viable spawn point");
				if (Distance2D(GM.CurrentPlayerBody.headPositionFiltered, SpawnPoints[i].position) >= SpawnpointDisableDistance && Physics.Linecast(GM.CurrentPlayerBody.Head.forward, SpawnPoints[i].position))
				{
					Debug.Log((object)("Spawnpoint " + ((Object)SpawnPoints[i]).name + " has just passed both spawn checks. Adding to potential list."));
					list.Add(SpawnPoints[i]);
				}
				else
				{
					Debug.Log((object)"No usable Spawnpoints found");
				}
			}
			return SodaliteUtils.GetRandom<Transform>((IList<Transform>)list);
		}

		public static float Distance2D(Vector3 a, Vector3 b)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			Vector2 val = default(Vector2);
			((Vector2)(ref val))..ctor(a.x, a.z);
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(b.x, b.z);
			return Vector2.Distance(val, val2);
		}

		private void OnTriggerEnter(Collider other)
		{
			if (usePhysicalTrigger && ((Component)other).tag == physicalTriggerTag)
			{
				StartGame();
			}
		}

		public void SetDifficulty(int dif)
		{
			switch (dif)
			{
			case 0:
				_diff = difficulty.easy;
				break;
			case 1:
				_diff = difficulty.med;
				break;
			case 2:
				_diff = difficulty.hard;
				break;
			default:
				_diff = difficulty.easy;
				break;
			}
		}

		public void SetHealth(int hp)
		{
			switch (hp)
			{
			case 0:
				GM.CurrentPlayerBody.SetHealthThreshold(100f);
				GM.CurrentPlayerBody.ResetHealth();
				break;
			case 1:
				GM.CurrentPlayerBody.SetHealthThreshold(1000f);
				GM.CurrentPlayerBody.ResetHealth();
				break;
			case 2:
				GM.CurrentPlayerBody.SetHealthThreshold(5000f);
				GM.CurrentPlayerBody.ResetHealth();
				break;
			case 3:
				GM.CurrentPlayerBody.SetHealthThreshold(10000f);
				GM.CurrentPlayerBody.ResetHealth();
				break;
			default:
				GM.CurrentPlayerBody.SetHealthThreshold(100f);
				GM.CurrentPlayerBody.ResetHealth();
				break;
			}
		}

		public void StartGame()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			if (doTeleport)
			{
				GM.CurrentMovementManager.TeleportToPoint(teleportPoint.position, true, teleportPoint.forward);
			}
			primarySpawnPoint.ObjectId = primaryItem;
			primarySpawnPoint.Spawn();
			primaryAmmoSpawnPoint.ObjectId = primaryAmmo;
			for (int i = 0; i < primaryAmmoAmount; i++)
			{
				primaryAmmoSpawnPoint.Spawn();
			}
			for (int j = 0; j < secondaryItems.Length; j++)
			{
				secondarySpawnPoints[j].ObjectId = secondaryItems[j];
				secondarySpawnPoints[j].Spawn();
			}
			((MonoBehaviour)this).StartCoroutine(StartGameDelay());
			Debug.Log((object)"start game");
			if ((Object)(object)startSound != (Object)null)
			{
				source.PlayOneShot(startSound);
			}
			if (OnGameStarted != null)
			{
				OnGameStarted.Invoke();
			}
			if (debugMode)
			{
				itemSpawner.SetActive(true);
			}
			else
			{
				itemSpawner.SetActive(false);
			}
		}

		private int CalculateSosigs()
		{
			float num = (float)sosigsamount * roundMultiplier;
			sosigsrounded = (int)Math.Round(num, 0);
			return sosigsrounded;
		}

		private int CalculateBossSosigs()
		{
			float num = 1f + roundMultiplier;
			bosssosigrounded = (int)Math.Round(num, 0);
			return bosssosigrounded;
		}

		public IEnumerator StartGameDelay()
		{
			yield return (object)new WaitForSeconds(10f);
			((MonoBehaviour)this).StartCoroutine(StartRound());
		}

		public IEnumerator StartRound()
		{
			yield return (object)new WaitForSeconds(timeBeforeRounds);
			gameRunning = true;
			isbossround = false;
			sosigsinroundtotal = 0;
			CalculateSosigs();
			BeginSpawns(sosigsrounded);
		}

		public IEnumerator StartBossRound()
		{
			yield return (object)new WaitForSeconds(timeBeforeRounds);
			isbossround = true;
			sosigsinroundtotal = 0;
			CalculateBossSosigs();
			BeginSpawns(bosssosigrounded);
			gameRunning = true;
		}

		public void BeginSpawns(int amount)
		{
			sosigsinround = amount;
			gameRunning = true;
			Debug.Log((object)"enabling spawn calling for this round");
			tryspawnsosigs = true;
			if (spawnMethod == SosigSpawnMethod.trickleIn)
			{
				((MonoBehaviour)this).StartCoroutine(RunTrickleSpawns());
			}
		}

		public IEnumerator RunTrickleSpawns()
		{
			while (tryspawnsosigs)
			{
				yield return (object)new WaitForSeconds(TrickleRate);
				if (currentspawnedsosigs.Count < maxSosigsSpawnable)
				{
					if (isbossround)
					{
						DoSpawns(highTierSosigs, GetViableSpawnPoint());
						Debug.Log((object)"trying to call spawns");
					}
					else if (roundMultiplier >= 2.5f)
					{
						DoSpawns(medTierSosigs, GetViableSpawnPoint());
						Debug.Log((object)"trying to call spawns");
					}
					else
					{
						DoSpawns(lowTierSosigs, GetViableSpawnPoint());
						Debug.Log((object)"trying to call spawns");
					}
				}
			}
		}

		public void DoSpawns(SosigEnemyID[] ids, Transform point)
		{
			//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_004b: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			if (sosigsinround <= sosigsinroundtotal)
			{
				tryspawnsosigs = false;
				return;
			}
			SosigEnemyID random = SodaliteUtils.GetRandom<SosigEnemyID>((IList<SosigEnemyID>)ids);
			if (AttackBehaviour == SosigAttackBehaviour.useAttackPoints)
			{
				_spawnOptions.SosigTargetPosition = SodaliteUtils.GetRandom<Transform>((IList<Transform>)attackPoints).position;
			}
			else if (AttackBehaviour == SosigAttackBehaviour.directlyTargetPlayer)
			{
				_spawnOptions.SosigTargetPosition = GM.CurrentMovementManager.CurNeckPos;
			}
			Debug.Log((object)"Do Spawns");
			Sosig val = SosigAPI.Spawn(ManagerSingleton<IM>.Instance.odicSosigObjsByID[random], _spawnOptions, point.position, point.rotation);
			SurvivalSosigTracker item = ((Component)val).gameObject.AddComponent<SurvivalSosigTracker>();
			currentspawnedsosigs.Add(item);
			sosigsinroundtotal++;
			aresosigsspawnedandadded = true;
		}

		public void EndRound()
		{
			gameRunning = false;
			if (currentspawnedsosigs.Count <= 0)
			{
				currentspawnedsosigs.Clear();
			}
			roundMultiplier *= 1.15f;
			AddMoney();
			Debug.Log((object)"End Round");
			if ((Object)(object)roundWonSound != (Object)null)
			{
				source.PlayOneShot(roundWonSound);
			}
			if (OnRoundEnd != null)
			{
				OnRoundEnd.Invoke();
			}
			((MonoBehaviour)this).StartCoroutine(NextRound());
		}

		public IEnumerator NextRound()
		{
			yield return (object)new WaitForSeconds(timeBetweenRounds);
			currentRound++;
			if (currentRound % 5 == 0)
			{
				((MonoBehaviour)this).StartCoroutine(StartBossRound());
				Debug.Log((object)"start boss round");
			}
			else
			{
				((MonoBehaviour)this).StartCoroutine(StartRound());
				Debug.Log((object)"start regular round");
			}
			if ((Object)(object)roundStartSound != (Object)null)
			{
				source.PlayOneShot(roundStartSound);
			}
			if (OnRoundStarted != null)
			{
				OnRoundStarted.Invoke();
			}
		}

		public void AddMoney()
		{
			float num = (float)currentspawnedsosigs.Count / 6f;
			float num2 = quickRoundThreshold * num;
			int num3 = moneyForRoundBeat + Mathf.RoundToInt(num2);
			currentMoney += num3;
		}

		public void EndGame()
		{
			gameRunning = false;
			foreach (SurvivalSosigTracker currentspawnedsosig in currentspawnedsosigs)
			{
				if ((Object)(object)currentspawnedsosig != (Object)null)
				{
					currentspawnedsosig.sosig.ClearSosig();
				}
			}
			currentspawnedsosigs.Clear();
			if ((Object)(object)endSound != (Object)null)
			{
				source.PlayOneShot(endSound, 0.75f);
			}
			if (OnGameEnd != null)
			{
				OnGameEnd.Invoke();
			}
			if (debugMode)
			{
				return;
			}
			string text = "SurvivalHighscore_" + mapName;
			if (PlayerPrefs.HasKey(text))
			{
				if (PlayerPrefs.GetInt(text) <= currentRound)
				{
					PlayerPrefs.SetInt(text, currentRound);
				}
			}
			else
			{
				PlayerPrefs.SetInt(text, currentRound);
			}
			highscoreRound.text = "Highest Round: " + PlayerPrefs.GetInt(text);
			PlayerPrefs.Save();
		}

		public void ToggleAmmoMode(Text text)
		{
			if (isLimitedAmmo)
			{
				isLimitedAmmo = false;
				text.text = "Enabled - Mag Recycling Disabled";
			}
			else
			{
				isLimitedAmmo = true;
				text.text = "Limited Ammo - Recyclers Enabled";
			}
		}

		public void ToggleDebugMode(GameObject checkbox)
		{
			if (debugMode)
			{
				debugMode = false;
				checkbox.SetActive(false);
			}
			else
			{
				debugMode = true;
				checkbox.SetActive(true);
			}
		}

		public IEnumerator UpdateAttackPos()
		{
			yield return (object)new WaitForSeconds(10f);
			lastKnownPos = GM.CurrentPlayerRoot.position - Vector3.down;
			((MonoBehaviour)this).StartCoroutine(UpdateAttackPos());
		}

		public void ResetGame()
		{
			//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)
			Scene activeScene = SceneManager.GetActiveScene();
			SteamVR_LoadLevel.Begin(((Scene)(ref activeScene)).name, false, 0.5f, 0f, 0f, 0f, 1f);
		}
	}
	public class SurvivalRecycler : MonoBehaviour
	{
		[Tooltip("The recycler will destroy all items placed within, this just decides if you get compensated for recycling.")]
		[HideInInspector]
		public bool canSellWeapons = true;

		[Tooltip("The sell price of weapons with a TagFirearmSize of pocket or pistol. (ex. Glock, 1911, etc)")]
		public int pistolSellPrice = 300;

		[Tooltip("The sell price of weapons with a TagFirearmSize of compact. (ex. Uzi, MP7, etc)")]
		public int compactSellPrice = 600;

		[Tooltip("The sell price of weapons with a TagFirearmSize of carbine or fullSize. (ex. M4A1, AKs, etc)")]
		public int fullSizeSellPrice = 1000;

		[Tooltip("The sell price of weapons with a TagFirearmSize of bulky. (ex. MG42, RPD, etc)")]
		public int bulkySellPrice = 1200;

		[Tooltip("The sell price of weapons with a TagFirearmSize of oversize. (ex. that one massive pistol from the Arizona Range)")]
		public int oversizeSellPrice = 1600;

		[Tooltip("The recycler will destroy all items placed within, this just decides if you get compensated for recycling.")]
		[HideInInspector]
		public bool canSellMagazines = true;

		[Tooltip("Magazines are sold at a flat rate, there is no way to determine size.")]
		public int magazineSellPrice;

		[Tooltip("The recycler will destroy all items placed within, this just decides if you get compensated for recycling.")]
		[HideInInspector]
		public bool canSellMelee = true;

		[Tooltip("Melees are sold at a flat rate, there is no way to determine size.")]
		public int meleeSellPrice;

		[Header("Optional")]
		public ParticleSystem particleSystem;

		public Light realtimeLight;

		public AudioSource source;

		[Tooltip("The sound played when successfully recycling and getting refunded.")]
		public AudioClip recyleClip;

		[Tooltip("The sound played when successfully recycling but not getting refunded (ex. during spawnlocked mode or for non-sellable items).")]
		public AudioClip destroyClip;

		[HideInInspector]
		public bool isEnabled;

		private bool canRecycle;

		private void Start()
		{
			CollectionExtensions.AddItem<SurvivalRecycler>((IEnumerable<SurvivalRecycler>)SurvivalManager.Instance.recyclers, this);
			canRecycle = true;
		}

		public void Update()
		{
			if ((Object)(object)realtimeLight != (Object)null)
			{
				((Behaviour)realtimeLight).enabled = isEnabled;
			}
			if ((Object)(object)particleSystem != (Object)null)
			{
				((Component)particleSystem).gameObject.SetActive(isEnabled);
			}
		}

		private void OnTriggerEnter(Collider other)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected I4, but got Unknown
			if (Object.op_Implicit((Object)(object)((Component)other).GetComponentInParent<FVRFireArm>()) && canSellWeapons && isEnabled)
			{
				FVRFireArm componentInParent = ((Component)other).GetComponentInParent<FVRFireArm>();
				OTagFirearmSize tagFirearmSize = ((FVRPhysicalObject)componentInParent).ObjectWrapper.TagFirearmSize;
				OTagFirearmSize val = tagFirearmSize;
				switch ((int)val)
				{
				case 1:
					DestroyItem(((Component)componentInParent).gameObject, wasRecycle: true, pistolSellPrice);
					break;
				case 2:
					DestroyItem(((Component)componentInParent).gameObject, wasRecycle: true, pistolSellPrice);
					break;
				case 3:
					DestroyItem(((Component)componentInParent).gameObject, wasRecycle: true, compactSellPrice);
					break;
				case 4:
					DestroyItem(((Component)componentInParent).gameObject, wasRecycle: true, fullSizeSellPrice);
					break;
				case 5:
					DestroyItem(((Component)componentInParent).gameObject, wasRecycle: true, fullSizeSellPrice);
					break;
				case 6:
					DestroyItem(((Component)componentInParent).gameObject, wasRecycle: true, bulkySellPrice);
					break;
				case 7:
					DestroyItem(((Component)componentInParent).gameObject, wasRecycle: true, oversizeSellPrice);
					break;
				case 0:
					Debug.LogWarning((object)"Could not find the OTagFirearmSize for this weapon, no refund can be made.");
					DestroyItem(((Component)componentInParent).gameObject, wasRecycle: false, 0);
					break;
				}
			}
			else if (Object.op_Implicit((Object)(object)((Component)other).GetComponentInParent<FVRFireArmMagazine>()) && canSellMagazines && isEnabled)
			{
				FVRFireArmMagazine componentInParent2 = ((Component)other).GetComponentInParent<FVRFireArmMagazine>();
				DestroyItem(((Component)componentInParent2).gameObject, wasRecycle: true, magazineSellPrice);
			}
			else if (Object.op_Implicit((Object)(object)((Component)other).GetComponentInParent<FVRMeleeWeapon>()) && canSellMelee && isEnabled)
			{
				FVRMeleeWeapon componentInParent3 = ((Component)other).GetComponentInParent<FVRMeleeWeapon>();
				DestroyItem(((Component)componentInParent3).gameObject, wasRecycle: true, meleeSellPrice);
			}
			else if (Object.op_Implicit((Object)(object)((Component)other).GetComponent<FVRFireArmAttachment>()) || Object.op_Implicit((Object)(object)((Component)other).GetComponent<FVRGrenade>()))
			{
				DestroyItem(((Component)other).gameObject, wasRecycle: false, 0);
			}
			else
			{
				Debug.Log((object)"object does not have any sellable compoonents or FIOs, not destroying.");
			}
		}

		public void DestroyItem(GameObject item, bool wasRecycle, int price)
		{
			DI(item, wasRecycle, price);
			((MonoBehaviour)this).StartCoroutine(StupidRecyclerDelayFix());
		}

		private void DI(GameObject item, bool wasRecycle, int price)
		{
			if (!canRecycle)
			{
				return;
			}
			FVRInteractiveObject component = item.GetComponent<FVRInteractiveObject>();
			if ((Object)(object)component != (Object)null)
			{
				component.ForceBreakInteraction();
			}
			Object.Destroy((Object)(object)item.gameObject);
			SurvivalManager.Instance.currentMoney += price;
			if (wasRecycle)
			{
				if ((Object)(object)recyleClip != (Object)null)
				{
					source.PlayOneShot(recyleClip);
				}
			}
			else if ((Object)(object)destroyClip != (Object)null)
			{
				source.PlayOneShot(destroyClip);
			}
		}

		public IEnumerator StupidRecyclerDelayFix()
		{
			canRecycle = false;
			yield return (object)new WaitForSeconds(0.25f);
			canRecycle = true;
		}
	}
	public class SurvivalShop : MonoBehaviour
	{
		[Tooltip("The layout group managers objects childed to the category buttons. Should be named 'options', in the example.")]
		public GameObject[] layoutGroupManagers;

		public ObjectSpawnPoint primarySpawnPoint;

		public ObjectSpawnPoint secondarySpawnPoint;

		public ObjectSpawnPoint tertiarySpawnPoint;

		[Tooltip("all itemId scripts associated with this shop added to an array. Used primarily for spawning a random item.")]
		public SurvivalItemID[] items;

		[Header("Random Item Spawner - Leave Empty If Unwanted")]
		public int randomItemPrice;

		[Header("Refill Ammo Button - Leave Empty If Unwanted")]
		public int ammoRefilPrice;

		[Header("UI Text Indicators")]
		public Text currentMoneyText;

		public Text randomItemText;

		public Text ammoRefilText;

		public void Awake()
		{
			GameObject[] array = layoutGroupManagers;
			foreach (GameObject val in array)
			{
				val.SetActive(false);
			}
			primarySpawnPoint.ObjectId = "";
			primarySpawnPoint.SpawnOnStart = false;
			secondarySpawnPoint.ObjectId = "";
			secondarySpawnPoint.SpawnOnStart = false;
			tertiarySpawnPoint.ObjectId = "";
			tertiarySpawnPoint.SpawnOnStart = false;
			if ((Object)(object)randomItemText != (Object)null)
			{
				randomItemText.text = "Random Item - $" + randomItemPrice;
			}
			if ((Object)(object)ammoRefilText != (Object)null)
			{
				ammoRefilText.text = "Ammo - $" + ammoRefilPrice;
			}
		}

		private void Update()
		{
			currentMoneyText.text = "$" + SurvivalManager.Instance.currentMoney;
		}

		public void OnCategorySelect(int id)
		{
			GameObject[] array = layoutGroupManagers;
			foreach (GameObject val in array)
			{
				val.SetActive(false);
			}
			layoutGroupManagers[id].SetActive(true);
		}

		public void SpawnRandomID()
		{
			int num = Random.Range(0, items.Count());
			if (SurvivalManager.Instance.currentMoney < randomItemPrice)
			{
				return;
			}
			SurvivalManager.Instance.currentMoney -= randomItemPrice;
			if ((Object)(object)SurvivalManager.Instance.ObjectBoughtSound != (Object)null)
			{
				SurvivalManager.Instance.source.PlayOneShot(SurvivalManager.Instance.ObjectBoughtSound);
			}
			primarySpawnPoint.ObjectId = items[num].id;
			primarySpawnPoint.Spawn();
			if (items[num].secondaryId != null)
			{
				Debug.Log((object)"SecondaryID found");
				secondarySpawnPoint.ObjectId = items[num].secondaryId;
				for (int i = 0; i < items[num].timesToSpawnSecondary; i++)
				{
					secondarySpawnPoint.Spawn();
				}
			}
			if (items[num].tertiaryIds != null)
			{
				for (int j = 0; j < items[num].tertiaryIds.Length; j++)
				{
					tertiarySpawnPoint.ObjectId = items[num].tertiaryIds[j];
					tertiarySpawnPoint.Spawn();
				}
			}
		}
	}
	public class SurvivalSosigTracker : MonoBehaviour
	{
		public Sosig sosig;

		public bool isDead = false;

		public void Awake()
		{
			sosig = ((Component)this).GetComponent<Sosig>();
		}

		public void Update()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			if ((int)sosig.BodyState == 3)
			{
				((MonoBehaviour)this).StartCoroutine(UpdateSosigState());
			}
		}

		public IEnumerator UpdateSosigState()
		{
			yield return (object)new WaitForSeconds(5f);
			isDead = true;
		}
	}
}