Decompiled source of BetterEXP v2.5.2

LCBetterEXP.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using LCBetterEXP.patches;
using Newtonsoft.Json;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("LCBetterEXP")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LCBetterEXP")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("3d1909e4-ce70-48f2-a2d1-28b67cea8eee")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace LCBetterEXP
{
	internal class JobTrackingManager
	{
		public class JobLog
		{
			public int scrapCollected = 0;

			public int totalAvailableScrap = 0;

			public string scrapGrade = "F";

			public string moon = "?? Unknown";

			public string weather = "Clear";

			public int levelInteriorType = 0;

			public float dayLengthInSeconds = 0f;

			public int jobPlayedTime = 0;

			public int randomMapSeed = -1;

			public string singleScrapItemDay = null;

			public string enemyRushName = null;

			public JobLogMeteorInfo meteorShowerActive = null;

			public VisualEXPPatch.BetterEXPLog betterExpGained;

			public JobLogPlayer[] players;

			public void CalculateScrapGrade()
			{
				float num = (float)scrapCollected / (float)totalAvailableScrap;
				if (num >= 1f)
				{
					scrapGrade = "S";
				}
				else if (num >= 0.6f)
				{
					scrapGrade = "A";
				}
				else if (num >= 0.3f)
				{
					scrapGrade = "B";
				}
				else if (num >= 0.1f)
				{
					scrapGrade = "C";
				}
				else
				{
					scrapGrade = "D";
				}
			}
		}

		public class JobLogMeteorInfo
		{
			public float normalizedTimeAtStart = 0f;

			public string normalizedTimeAtStartFormatted = "";
		}

		public class JobLogPlayer
		{
			public JobLogPlayerStats statistics;

			public string[] playerNotes;

			public string playerName = "????????";

			public bool disconnected = false;

			public JobLogPlayerDeathInformation deathInformation = null;

			public ulong steamID = 0uL;

			public bool isLocalPlayer = false;
		}

		public class JobLogPlayerDeathInformation
		{
			public string formattedCauseOfDeath;

			public CauseOfDeath causeOfDeath;

			public string formattedDayTimeOfDeath;

			public float normalizedTimeOfDeath;

			public float realLifeTimeOfDeathInSeconds;
		}

		public class JobLogPlayerStats
		{
			public int damageTaken = 0;

			public int stepsTaken = 0;

			public int scrapDelivered = 0;

			public int objectsDelivered = 0;

			public int turns = 0;

			public float indoorTime = 0f;

			public float outdoorTime = 0f;

			public float shipTime = 0f;

			public int jumps = 0;

			public int scrapFound = 0;

			public int scrapFoundDeliveredToShip = 0;

			public int enemyKills = 0;

			public JobLogPlayerStats FillFromVanillaStats(PlayerStats stats)
			{
				damageTaken = stats.damageTaken;
				stepsTaken = stats.stepsTaken;
				scrapDelivered = stats.profitable;
				turns = stats.turnAmount;
				return this;
			}

			public JobLogPlayerStats FillFromCustomStats(NotesPatch.CustomPlayerStat stats)
			{
				indoorTime = stats.indoorTime;
				outdoorTime = stats.outdoorTime;
				shipTime = stats.shipTime;
				jumps = stats.jumps;
				objectsDelivered = stats.objectsDelivered;
				scrapFound = stats.scrapFound;
				scrapFoundDeliveredToShip = stats.scrapFoundDeliveredToShip;
				return this;
			}
		}

		public static float timeAtStartOfDay = 0f;

		public static float timeAtEndOfDay = 0f;

		public static string singleScrapDayItemName = null;

		public static string enemyRushDayEnemyName = null;

		public static float meteorShowerAtTime = -1f;

		public static void LogJobUsingContext(int scrapCollected, VisualEXPPatch.BetterEXPLog log)
		{
			VisualEXPPatch.scrapCollectedOnServer = scrapCollected;
			if (!BetterEXPPlugin.EnableDayLogging.Value)
			{
				return;
			}
			JobLog jobLog = new JobLog
			{
				scrapCollected = VisualEXPPatch.scrapCollectedOnServer,
				totalAvailableScrap = (int)RoundManager.Instance.totalScrapValueInLevel,
				moon = RoundManager.Instance.currentLevel.PlanetName,
				weather = ((object)(LevelWeatherType)(ref TimeOfDay.Instance.currentLevelWeather)).ToString().Replace("None", "Clear"),
				levelInteriorType = RoundManager.Instance.currentDungeonType,
				dayLengthInSeconds = Math.Max(0f, timeAtEndOfDay - timeAtStartOfDay),
				betterExpGained = log,
				singleScrapItemDay = singleScrapDayItemName,
				enemyRushName = enemyRushDayEnemyName,
				randomMapSeed = StartOfRound.Instance.randomMapSeed,
				jobPlayedTime = GetUnixTimestamp(DateTime.UtcNow)
			};
			jobLog.CalculateScrapGrade();
			if (meteorShowerAtTime != -1f)
			{
				jobLog.meteorShowerActive = new JobLogMeteorInfo
				{
					normalizedTimeAtStart = meteorShowerAtTime,
					normalizedTimeAtStartFormatted = PlayerControllerBPatch.GetFormattedTimeFromNormalizedTime(meteorShowerAtTime, TimeOfDay.Instance.numberOfHours)
				};
				meteorShowerAtTime = -1f;
			}
			List<JobLogPlayer> list = new List<JobLogPlayer>();
			for (int i = 0; i < StartOfRound.Instance.allPlayerScripts.Length; i++)
			{
				PlayerControllerB val = StartOfRound.Instance.allPlayerScripts[i];
				if ((Object)(object)val == (Object)null || (!val.isPlayerDead && !val.isPlayerControlled && !val.disconnectedMidGame))
				{
					continue;
				}
				JobLogPlayer jobLogPlayer = new JobLogPlayer
				{
					disconnected = val.disconnectedMidGame,
					playerName = val.playerUsername,
					steamID = val.playerSteamId,
					isLocalPlayer = ((Object)(object)val == (Object)(object)GameNetworkManager.Instance.localPlayerController)
				};
				List<string> list2 = new List<string>();
				foreach (StartOfRoundPatch.PlayerNote item in StartOfRoundPatch.notesToAdd)
				{
					if (item.id == i)
					{
						list2.Add(item.unstyledNote ?? item.note);
					}
				}
				if (val.isPlayerDead && PlayerControllerBPatch.PlayerDeathInformation.ContainsKey(i))
				{
					jobLogPlayer.deathInformation = PlayerControllerBPatch.PlayerDeathInformation[i];
				}
				JobLogPlayerStats jobLogPlayerStats = new JobLogPlayerStats();
				jobLogPlayerStats.FillFromVanillaStats(StartOfRound.Instance.gameStats.allPlayerStats[i]);
				if (NotesPatch.CustomPlayerStats.ContainsKey(i))
				{
					jobLogPlayerStats.FillFromCustomStats(NotesPatch.CustomPlayerStats[i]);
				}
				if (EnemyAIPatch.playerEnemyKills.ContainsKey(i))
				{
					jobLogPlayerStats.enemyKills = EnemyAIPatch.playerEnemyKills[i];
				}
				jobLogPlayer.statistics = jobLogPlayerStats;
				jobLogPlayer.playerNotes = list2.ToArray();
				list.Add(jobLogPlayer);
			}
			jobLog.players = list.ToArray();
			Saving.SaveJobToDisk(jobLog);
		}

		public static int GetUnixTimestamp(DateTime time)
		{
			return (int)time.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
		}
	}
	[BepInPlugin("Swaggies.BetterEXP", "BetterEXP", "2.5.2")]
	public class BetterEXPPlugin : BaseUnityPlugin
	{
		public enum CollectedDisplayOptionSettings
		{
			[Description("No display")]
			NONE,
			[Description("Display below name")]
			BELOW_NAME,
			[Description("Display next to name")]
			BESIDE_NAME
		}

		public enum DisplayEnemyKillOptionSettings
		{
			[Description("Hide kill notifications")]
			NONE,
			[Description("Show notifications for enemies you kill")]
			FROM_SELF,
			[Description("Show notifications for enemies any player kills")]
			FROM_ANY_PLAYER
		}

		private const string _GUID = "Swaggies.BetterEXP";

		private const string _NAME = "BetterEXP";

		private const string _VER = "2.5.2";

		private readonly Harmony harmony = new Harmony("Swaggies.BetterEXP");

		private static BetterEXPPlugin Instance;

		public static ManualLogSource logr;

		public static ConfigEntry<DisplayEnemyKillOptionSettings> showEnemyKillNotifs;

		public static ConfigEntry<bool> showRoundSummary;

		public static ConfigEntry<bool> showRankInMenu;

		public static ConfigEntry<CollectedDisplayOptionSettings> collectedDisplayOption;

		public static ConfigEntry<bool> EnableDayLogging;

		public static ConfigEntry<bool> PerformanceReportStyling;

		public static ConfigEntry<bool> PerformanceReportStats;

		public static ConfigEntry<bool> NegativeNotes;

		public static ConfigEntry<bool> MostActiveNote;

		public static ConfigEntry<bool> LeastProfitableNote;

		public static ConfigEntry<bool> LethalNote;

		public static ConfigEntry<bool> JumpingNote;

		public static ConfigEntry<bool> BraveryNote;

		public static ConfigEntry<bool> ShipDutyNote;

		public static ConfigEntry<bool> ScavengerNote;

		public static bool hasLoadedV2;

		private void Awake()
		{
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Expected O, but got Unknown
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Expected O, but got Unknown
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Expected O, but got Unknown
			//IL_0208: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Expected O, but got Unknown
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Expected O, but got Unknown
			//IL_025e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0268: Expected O, but got Unknown
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Expected O, but got Unknown
			//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_02be: Expected O, but got Unknown
			//IL_02df: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Expected O, but got Unknown
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Expected O, but got Unknown
			//IL_0335: Unknown result type (might be due to invalid IL or missing references)
			//IL_033f: Expected O, but got Unknown
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			logr = Logger.CreateLogSource("Swaggies.BetterEXP");
			harmony.PatchAll(typeof(BetterEXPPlugin));
			harmony.PatchAll(typeof(EnemyAIPatch));
			harmony.PatchAll(typeof(VisualEXPPatch));
			harmony.PatchAll(typeof(StartOfRoundPatch));
			harmony.PatchAll(typeof(WeatherPatch));
			harmony.PatchAll(typeof(PauseDisplayPatch));
			harmony.PatchAll(typeof(NotesPatch));
			harmony.PatchAll(typeof(PlayerControllerBPatch));
			logr.LogInfo((object)"BetterEXP up and running.");
			Saving.Load();
			showEnemyKillNotifs = ((BaseUnityPlugin)this).Config.Bind<DisplayEnemyKillOptionSettings>("General", "ShowEnemyKillNotifications", DisplayEnemyKillOptionSettings.NONE, "Whether you should receive a notification about your BXP gain when an enemy dies. This may spoil gameplay.\nFROM_SELF: only shows for enemies YOU kill.\nFROM_ANY_PLAYER: shows for enemies any player kills.");
			showRoundSummary = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowRoundSummary", true, "Whether to show a breakdown of your BXP gains at the end of each day. Doesn't affect gameplay.");
			showRankInMenu = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowRankInPauseMenu", true, "Whether to show your current BXP rank in the pause menu. Doesn't affect gameplay, but could conflict or overlap with other elements from other mods.");
			collectedDisplayOption = ((BaseUnityPlugin)this).Config.Bind<CollectedDisplayOptionSettings>("General", "ScrapCollectedDisplayType", CollectedDisplayOptionSettings.BELOW_NAME, new ConfigDescription("Where to show how much scrap a player collected on the Performance Report screen.", (AcceptableValueBase)null, Array.Empty<object>()));
			EnableDayLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable Day Logging", false, "[BETA] Saves each day's performance report, including statistics for each player, into a local JSON file that may be viewed or used later. No data will be collected/uploaded anywhere. Useful for developers who'd want to make something cool involving this.");
			PerformanceReportStyling = ((BaseUnityPlugin)this).Config.Bind<bool>("Performance Report", "Performance Report Styling", true, new ConfigDescription("Whether or not to style notes on the Performance Report with colors.", (AcceptableValueBase)null, Array.Empty<object>()));
			PerformanceReportStats = ((BaseUnityPlugin)this).Config.Bind<bool>("Performance Report", "Performance Report Stats", true, new ConfigDescription("Whether or not to show the exact statistic for each note. (such as showing \"(1234 steps)\" for the most active employee)", (AcceptableValueBase)null, Array.Empty<object>()));
			NegativeNotes = ((BaseUnityPlugin)this).Config.Bind<bool>("Performance Report", "Negative Notes", true, new ConfigDescription("Whether or not to enable negative notes (employees with the LEAST of something), such as Least Profitable or The Laziest.", (AcceptableValueBase)null, Array.Empty<object>()));
			MostActiveNote = ((BaseUnityPlugin)this).Config.Bind<bool>("Performance Report", "Custom Note: Most Active", true, new ConfigDescription("Enables the Most Active note, given to players with the most amount of steps taken.", (AcceptableValueBase)null, Array.Empty<object>()));
			LeastProfitableNote = ((BaseUnityPlugin)this).Config.Bind<bool>("Performance Report", "Custom Note: Least Profitable", true, new ConfigDescription("Enables the Least Profitable note, given to players with the least amount of scrap collected.", (AcceptableValueBase)null, Array.Empty<object>()));
			LethalNote = ((BaseUnityPlugin)this).Config.Bind<bool>("Performance Report", "Custom Note: Lethality", true, new ConfigDescription("Enables the Most Lethal and The Pacifist notes, given to players with the most amount of entity kills and players whom are the only crewmate with zero kills.", (AcceptableValueBase)null, Array.Empty<object>()));
			JumpingNote = ((BaseUnityPlugin)this).Config.Bind<bool>("Performance Report", "Custom Note: Jumpy", false, new ConfigDescription("Enables the Most Jumpy and Most Grounded notes, given to players with the most and least amount of jumps in a day.", (AcceptableValueBase)null, Array.Empty<object>()));
			BraveryNote = ((BaseUnityPlugin)this).Config.Bind<bool>("Performance Report", "Custom Note: Bravery", false, new ConfigDescription("Enables The Bravest and Most Outdoors notes, given to players whom spend the longest inside and outside respectively.", (AcceptableValueBase)null, Array.Empty<object>()));
			ShipDutyNote = ((BaseUnityPlugin)this).Config.Bind<bool>("Performance Report", "Custom Note: Ship Guy", false, new ConfigDescription("Enables the Ship Guy note, given to the employee who spends the most time in the ship.", (AcceptableValueBase)null, Array.Empty<object>()));
			ScavengerNote = ((BaseUnityPlugin)this).Config.Bind<bool>("Performance Report", "Custom Note: The Scavenger", true, new ConfigDescription("Enables the Number 1 Scavenger, Empty-Handed, and Team Backbone notes, given to the employees who find the most or zero scrap inside the facility respectively, and the team member(s) whom had the most found scrap returned to ship.", (AcceptableValueBase)null, Array.Empty<object>()));
		}

		public static void AssignInitialRank(int currentPlayerVanillaEXP)
		{
			if (hasLoadedV2)
			{
				return;
			}
			int betterXP = 0;
			Dictionary<int, int> dictionary = new Dictionary<int, int>
			{
				{ 4500, 2500 },
				{ 3000, 2000 },
				{ 2500, 1600 },
				{ 2000, 1300 },
				{ 1500, 1000 },
				{ 1000, 700 },
				{ 500, 350 },
				{ 175, 150 },
				{ 75, 75 },
				{ 25, 25 },
				{ 0, 0 }
			};
			foreach (KeyValuePair<int, int> item in dictionary)
			{
				if (currentPlayerVanillaEXP >= item.Key)
				{
					betterXP = item.Value;
					break;
				}
			}
			hasLoadedV2 = true;
			XPPatch.SetBetterXP(betterXP);
			Saving.Save();
		}

		[HarmonyPatch(typeof(HUDManager), "SetSavedValues")]
		[HarmonyPostfix]
		private static void OnHudStart()
		{
			if (!hasLoadedV2)
			{
				AssignInitialRank(HUDManager.Instance.localPlayerXP);
				logr.LogMessage((object)$"Vanilla XP: {HUDManager.Instance.localPlayerXP} -> BetterXP: {XPPatch.betterXp}");
			}
		}
	}
}
namespace LCBetterEXP.patches
{
	[HarmonyPatch(typeof(EnemyAI))]
	public class EnemyAIPatch
	{
		public class EnemyKillBonus
		{
			public int experience = 0;

			public string name = "";

			public EnemyKillBonus(string enemyName, int expGain)
			{
				experience = expGain;
				name = enemyName;
			}
		}

		public class EnemyTarget
		{
			public int player;

			public float lastHitTime;
		}

		public static int totalXpFromEnemyKills = 0;

		public static int highestXpFromEnemyKills = 0;

		public static Dictionary<int, int> playerEnemyKills = new Dictionary<int, int>();

		public static Dictionary<ulong, EnemyTarget> enemyLastHitTargets = new Dictionary<ulong, EnemyTarget>();

		public static void ResetAllEnemyKills()
		{
			playerEnemyKills.Clear();
			enemyLastHitTargets.Clear();
			highestXpFromEnemyKills = 0;
			totalXpFromEnemyKills = 0;
		}

		private static EnemyKillBonus GetXpFromEnemy(EnemyAI enemy)
		{
			if (enemy is ForestGiantAI)
			{
				return new EnemyKillBonus("a Forest Giant", 16);
			}
			if (enemy is BushWolfEnemy)
			{
				return new EnemyKillBonus("a Kidnapper Fox", 14);
			}
			if (enemy is CaveDwellerAI)
			{
				return new EnemyKillBonus("a Maneater", 14);
			}
			if (enemy is MouthDogAI)
			{
				return new EnemyKillBonus("an Eyeless Dog", 12);
			}
			if (enemy is BaboonBirdAI)
			{
				return new EnemyKillBonus("a Baboon Hawk", 8);
			}
			if (enemy is FlowermanAI)
			{
				return new EnemyKillBonus("a Bracken", 8);
			}
			if (enemy is NutcrackerEnemyAI)
			{
				return new EnemyKillBonus("a Nutcracker", 8);
			}
			if (enemy is ButlerEnemyAI)
			{
				return new EnemyKillBonus("a Butler", 8);
			}
			if (enemy is MaskedPlayerEnemy)
			{
				return new EnemyKillBonus("a Masked", 6);
			}
			if (enemy is CrawlerAI)
			{
				return new EnemyKillBonus("a Thumper", 6);
			}
			if (enemy is SandSpiderAI)
			{
				return new EnemyKillBonus("a Bunker Spider", 6);
			}
			if (enemy is HoarderBugAI)
			{
				return new EnemyKillBonus("a Hoarding Bug", 4);
			}
			if (enemy is CentipedeAI)
			{
				return new EnemyKillBonus("a Snare Flea", 4);
			}
			if (enemy is DoublewingAI)
			{
				return new EnemyKillBonus("a Manticoil", 2);
			}
			if (enemy is FlowerSnakeEnemy)
			{
				return new EnemyKillBonus("a Tulip Snake", 1);
			}
			if (enemy is LassoManAI)
			{
				return new EnemyKillBonus("a Lasso", 1);
			}
			return new EnemyKillBonus("an Enemy", 3);
		}

		[HarmonyPatch("HitEnemy")]
		[HarmonyPrefix]
		private static void DamageEnemyKillCheck(ref EnemyAI __instance, ref PlayerControllerB playerWhoHit)
		{
			if (!((Object)(object)playerWhoHit == (Object)null) && __instance.enemyType.canDie)
			{
				SetNewEnemyTarget(__instance, (int)playerWhoHit.playerClientId);
			}
		}

		[HarmonyPatch("HitEnemyOnLocalClient")]
		[HarmonyPrefix]
		private static void DamageEnemySelfCheck(ref EnemyAI __instance, ref PlayerControllerB playerWhoHit)
		{
			if (!((Object)(object)playerWhoHit == (Object)null) && __instance.enemyType.canDie)
			{
				SetNewEnemyTarget(__instance, (int)playerWhoHit.playerClientId);
			}
		}

		[HarmonyPatch("HitEnemyServerRpc")]
		[HarmonyPrefix]
		private static void DamageEnemyServerCheck(ref EnemyAI __instance, ref int playerWhoHit)
		{
			if (playerWhoHit != -1 && __instance.enemyType.canDie)
			{
				SetNewEnemyTarget(__instance, playerWhoHit);
			}
		}

		[HarmonyPatch("KillEnemy")]
		[HarmonyPostfix]
		private static void KillEnemyPatch(ref EnemyAI __instance)
		{
			if (__instance.enemyType.canDie)
			{
				EnemyAI enemy = __instance;
				((MonoBehaviour)RoundManager.Instance).StartCoroutine(DelayedEnemyKillPatch(enemy));
			}
		}

		private static IEnumerator DelayedEnemyKillPatch(EnemyAI enemy)
		{
			if (enemyLastHitTargets.ContainsKey(((NetworkBehaviour)enemy).NetworkObjectId) && !(Time.realtimeSinceStartup - enemyLastHitTargets[((NetworkBehaviour)enemy).NetworkObjectId].lastHitTime > 5f))
			{
				yield return (object)new WaitForSeconds(0.4f);
				KillEnemyForXp(enemy, StartOfRound.Instance.allPlayerScripts[enemyLastHitTargets[((NetworkBehaviour)enemy).NetworkObjectId].player]);
			}
		}

		private static void SetNewEnemyTarget(EnemyAI enemy, int target)
		{
			if (target >= 0)
			{
				ulong networkObjectId = ((NetworkBehaviour)enemy).NetworkObjectId;
				if (enemyLastHitTargets.ContainsKey(networkObjectId))
				{
					enemyLastHitTargets[networkObjectId] = new EnemyTarget
					{
						player = target,
						lastHitTime = Time.realtimeSinceStartup
					};
				}
				else
				{
					enemyLastHitTargets.Add(networkObjectId, new EnemyTarget
					{
						player = target,
						lastHitTime = Time.realtimeSinceStartup
					});
				}
			}
		}

		private static void KillEnemyForXp(EnemyAI enemy, PlayerControllerB player = null)
		{
			if ((Object)(object)player == (Object)null)
			{
				return;
			}
			string playerUsername = player.playerUsername;
			int key = (int)player.playerClientId;
			bool flag = (Object)(object)player == (Object)(object)GameNetworkManager.Instance.localPlayerController;
			EnemyKillBonus xpFromEnemy = GetXpFromEnemy(enemy);
			if (playerEnemyKills.ContainsKey(key))
			{
				playerEnemyKills[key]++;
			}
			else
			{
				playerEnemyKills.Add(key, 1);
			}
			if (!flag)
			{
				if (BetterEXPPlugin.showEnemyKillNotifs.Value == BetterEXPPlugin.DisplayEnemyKillOptionSettings.FROM_ANY_PLAYER)
				{
					Helpers.DisplayGlobalMessage(playerUsername + " killed " + xpFromEnemy.name + "!");
				}
				return;
			}
			int xpFromKilledEnemies = GetXpFromKilledEnemies();
			if (xpFromEnemy.experience > highestXpFromEnemyKills)
			{
				highestXpFromEnemyKills = xpFromEnemy.experience;
			}
			totalXpFromEnemyKills += xpFromEnemy.experience;
			if (BetterEXPPlugin.showEnemyKillNotifs.Value != 0)
			{
				int num = GetXpFromKilledEnemies() - xpFromKilledEnemies;
				Helpers.DisplayGlobalMessage("You killed " + xpFromEnemy.name + "!" + ((num > 0) ? $"\n<color=#00ff00ff>Got {num} BXP</color>" : ""));
			}
		}

		public static int GetXpFromKilledEnemies()
		{
			int num = highestXpFromEnemyKills;
			int num2 = totalXpFromEnemyKills - highestXpFromEnemyKills;
			double a = Math.Sqrt(Math.Pow(num2, 1.25) + (double)num2);
			return num + (int)Math.Ceiling(a);
		}
	}
	internal class Helpers
	{
		public static void DisplayGlobalMessage(string msg)
		{
			HUDManager.Instance.globalNotificationAnimator.SetTrigger("TriggerNotif");
			((TMP_Text)HUDManager.Instance.globalNotificationText).text = msg;
			HUDManager.Instance.UIAudio.PlayOneShot(HUDManager.Instance.globalNotificationSFX);
		}

		public static double NumBetween(double value, double min, double max, bool clamp = true)
		{
			double num = max - min;
			double num2 = value - min;
			if (!clamp)
			{
				return num2;
			}
			return Mathf.Clamp01((float)(num2 / num));
		}

		public static string FormatTime(int timeInSeconds)
		{
			int num = (int)((float)timeInSeconds / 60f);
			int num2 = timeInSeconds % 60;
			return $"{num:00}:{num2:00}";
		}
	}
	public class NotesPatch
	{
		public class CustomPlayerStat
		{
			public int playerID;

			public float indoorTime = 0f;

			public float outdoorTime = 0f;

			public float shipTime = 0f;

			public int jumps = 0;

			public int scrapFound = 0;

			public int scrapFoundDeliveredToShip = 0;

			public int objectsDelivered = 0;
		}

		public class BXPScrap
		{
			public int foundBy = -1;

			public bool deliveredToShip = false;
		}

		public static Dictionary<int, CustomPlayerStat> CustomPlayerStats = new Dictionary<int, CustomPlayerStat>();

		public static Dictionary<GrabbableObject, BXPScrap> ThisMoonObjects = new Dictionary<GrabbableObject, BXPScrap>();

		public static List<GrabbableObject> BlacklistedMoonObjects = new List<GrabbableObject>();

		public static void TryCreateCustomPlayerStat(int playerID)
		{
			if (!CustomPlayerStats.ContainsKey(playerID))
			{
				CustomPlayerStats.Add(playerID, new CustomPlayerStat
				{
					playerID = playerID
				});
			}
		}

		[HarmonyPatch(typeof(RoundManager), "SetLevelObjectVariables")]
		[HarmonyPostfix]
		private static void ResetNotesAtStartOfGame()
		{
			CustomPlayerStats.Clear();
			EnemyAIPatch.ResetAllEnemyKills();
		}

		[HarmonyPatch(typeof(PlayerControllerB), "PlayJumpAudio")]
		[HarmonyPrefix]
		private static void PlayerJumpSelf(ref PlayerControllerB __instance)
		{
			if (!__instance.isPlayerDead && __instance.isPlayerControlled && !__instance.disconnectedMidGame && !StartOfRound.Instance.inShipPhase && !StartOfRound.Instance.shipIsLeaving)
			{
				TryCreateCustomPlayerStat((int)__instance.playerClientId);
				CustomPlayerStats[(int)__instance.playerClientId].jumps++;
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "Update")]
		[HarmonyPostfix]
		private static void PlayerUpdate(ref PlayerControllerB __instance)
		{
			if (!__instance.isPlayerDead && __instance.isPlayerControlled && !__instance.disconnectedMidGame && !StartOfRound.Instance.inShipPhase && !StartOfRound.Instance.shipIsLeaving)
			{
				TryCreateCustomPlayerStat((int)__instance.playerClientId);
				if (__instance.isInsideFactory)
				{
					CustomPlayerStats[(int)__instance.playerClientId].indoorTime += Time.deltaTime;
				}
				else
				{
					CustomPlayerStats[(int)__instance.playerClientId].outdoorTime += Time.deltaTime;
				}
				if (__instance.isInHangarShipRoom)
				{
					CustomPlayerStats[(int)__instance.playerClientId].shipTime += Time.deltaTime;
				}
			}
		}

		[HarmonyPatch(typeof(StartMatchLever), "PullLeverAnim")]
		[HarmonyPrefix]
		private static void StartGamePatch(ref bool leverPulled)
		{
			if (leverPulled)
			{
				ThisMoonObjects.Clear();
				BlacklistedMoonObjects.Clear();
				GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
				GrabbableObject[] array2 = array;
				foreach (GrabbableObject item in array2)
				{
					BlacklistedMoonObjects.Add(item);
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "GrabObjectClientRpc")]
		[HarmonyPostfix]
		private static void PlayerGrabObject(ref PlayerControllerB __instance, ref bool grabValidated, ref NetworkObjectReference grabbedObject)
		{
			NetworkObject val = default(NetworkObject);
			if (!grabValidated || !((NetworkObjectReference)(ref grabbedObject)).TryGet(ref val, (NetworkManager)null))
			{
				return;
			}
			GrabbableObject componentInChildren = ((Component)val).gameObject.GetComponentInChildren<GrabbableObject>();
			if (componentInChildren.itemProperties.isScrap && !BlacklistedMoonObjects.Contains(componentInChildren))
			{
				if (!ThisMoonObjects.ContainsKey(componentInChildren))
				{
					ThisMoonObjects.Add(componentInChildren, new BXPScrap());
				}
				int num = (int)__instance.playerClientId;
				if (ThisMoonObjects[componentInChildren].foundBy == -1)
				{
					TryCreateCustomPlayerStat(num);
					CustomPlayerStats[num].scrapFound += componentInChildren.scrapValue;
					ThisMoonObjects[componentInChildren].foundBy = num;
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "SetItemInElevator")]
		[HarmonyPostfix]
		private static void SetObjectInShip(ref bool droppedInShipRoom, ref GrabbableObject gObject)
		{
			if (ThisMoonObjects.ContainsKey(gObject) && droppedInShipRoom != ThisMoonObjects[gObject].deliveredToShip)
			{
				ThisMoonObjects[gObject].deliveredToShip = droppedInShipRoom;
				if (ThisMoonObjects[gObject].foundBy != -1)
				{
					TryCreateCustomPlayerStat(ThisMoonObjects[gObject].foundBy);
					CustomPlayerStats[ThisMoonObjects[gObject].foundBy].scrapFoundDeliveredToShip += (droppedInShipRoom ? gObject.scrapValue : (-gObject.scrapValue));
					CustomPlayerStats[ThisMoonObjects[gObject].foundBy].objectsDelivered += (droppedInShipRoom ? 1 : (-1));
				}
			}
		}
	}
	internal class PauseDisplayPatch
	{
		private static TextMeshProUGUI vanillaXPText;

		private static TextMeshProUGUI bxpText;

		private static TextMeshProUGUI rankText;

		private static TextMeshProUGUI progressText;

		private static GameObject displayObject;

		private static GameObject bxpProgress;

		[HarmonyPatch(typeof(QuickMenuManager), "OpenQuickMenu")]
		[HarmonyPostfix]
		private static void PauseMenuPatch(QuickMenuManager __instance)
		{
			if (__instance.isMenuOpen)
			{
				if (!Object.op_Implicit((Object)(object)displayObject) || !Object.op_Implicit((Object)(object)bxpProgress))
				{
					CreateRankDisplayObject();
				}
				displayObject.SetActive(true);
				bxpProgress.SetActive(true);
			}
		}

		[HarmonyPatch(typeof(QuickMenuManager), "Update")]
		[HarmonyPostfix]
		private static void PauseMenuUpdatePatch(QuickMenuManager __instance)
		{
			if ((Object)(object)displayObject == (Object)null)
			{
				return;
			}
			if (!BetterEXPPlugin.showRankInMenu.Value || !__instance.isMenuOpen)
			{
				displayObject.SetActive(false);
				bxpProgress.SetActive(false);
				((Component)rankText).gameObject.SetActive(false);
				((Component)bxpText).gameObject.SetActive(false);
				((Component)vanillaXPText).gameObject.SetActive(false);
				((Component)progressText).gameObject.SetActive(false);
				return;
			}
			displayObject.SetActive(__instance.mainButtonsPanel.activeSelf);
			bxpProgress.SetActive(__instance.mainButtonsPanel.activeSelf);
			((Component)rankText).gameObject.SetActive(__instance.mainButtonsPanel.activeSelf);
			((Component)bxpText).gameObject.SetActive(__instance.mainButtonsPanel.activeSelf);
			((Component)progressText).gameObject.SetActive(__instance.mainButtonsPanel.activeSelf);
			((Component)vanillaXPText).gameObject.SetActive(__instance.mainButtonsPanel.activeSelf);
			if (__instance.mainButtonsPanel.activeSelf)
			{
				XPPatch.BetterLevel playerBetterLevel = XPPatch.GetPlayerBetterLevel(XPPatch.betterXp);
				int num = XPPatch.betterXp - playerBetterLevel.xp;
				int num2 = playerBetterLevel.xpEnd - playerBetterLevel.xp;
				((TMP_Text)bxpText).text = $"<color=#ffff00>{XPPatch.betterXp} BXP</color>";
				((TMP_Text)rankText).text = XPPatch.GetPlayerBetterLevel(XPPatch.betterXp).name;
				((TMP_Text)progressText).text = $"{num}/{num2}";
				bxpProgress.GetComponent<Image>().fillAmount = XPPatch.GetRankProgress(XPPatch.betterXp);
				((TMP_Text)bxpText).outlineWidth = 0f;
				((TMP_Text)rankText).outlineWidth = 0f;
				((TMP_Text)rankText).enableWordWrapping = false;
				((TMP_Text)vanillaXPText).text = $"$ Vanilla EXP: {HUDManager.Instance.localPlayerXP}";
			}
		}

		public static void CreateRankDisplayObject()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: 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_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0276: Unknown result type (might be due to invalid IL or missing references)
			//IL_029a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_0365: Unknown result type (might be due to invalid IL or missing references)
			//IL_0417: Unknown result type (might be due to invalid IL or missing references)
			//IL_043b: Unknown result type (might be due to invalid IL or missing references)
			//IL_045a: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = GameObject.Find("/Systems/UI/Canvas/QuickMenu");
			if (!Object.op_Implicit((Object)(object)displayObject))
			{
				displayObject = Object.Instantiate<GameObject>(GameObject.Find("/Systems/UI/Canvas/EndgameStats/LevelUp/LevelUpBox"));
				((Object)displayObject).name = "BXPDisplay";
				displayObject.transform.SetParent(val.transform, false);
				displayObject.transform.localScale = new Vector3(0.75f, 0.75f, 0.75f);
				displayObject.transform.localPosition = new Vector3(224f, -194f, 0f);
				bxpProgress = Object.Instantiate<GameObject>(GameObject.Find("/Systems/UI/Canvas/EndgameStats/LevelUp/LevelUpMeter"));
				((Object)bxpProgress).name = "BXPBarProgress";
				bxpProgress.transform.SetParent(displayObject.transform, false);
				bxpProgress.transform.localScale = new Vector3(0.597f, 5.21f, 1f);
				bxpProgress.transform.localPosition = new Vector3(0f, 0f, 0f);
				bxpText = Object.Instantiate<GameObject>(GameObject.Find("/Systems/UI/Canvas/EndgameStats/LevelUp/Total")).GetComponent<TextMeshProUGUI>();
				((Object)bxpText).name = "BXPText";
				((TMP_Text)bxpText).alignment = (TextAlignmentOptions)516;
				((TMP_Text)bxpText).fontSize = 32f;
				((TMP_Text)bxpText).font = ((TMP_Text)HUDManager.Instance.clockNumber).font;
				((TMP_Text)bxpText).transform.SetParent(displayObject.transform, false);
				((TMP_Text)bxpText).transform.localScale = new Vector3(1f, 1f, 1f);
				((TMP_Text)bxpText).transform.localPosition = new Vector3(36f, -25f, 55f);
				rankText = Object.Instantiate<GameObject>(GameObject.Find("/Systems/UI/Canvas/EndgameStats/LevelUp/Total")).GetComponent<TextMeshProUGUI>();
				((Object)rankText).name = "BXPRankText";
				((TMP_Text)rankText).alignment = (TextAlignmentOptions)513;
				((TMP_Text)rankText).font = ((TMP_Text)HUDManager.Instance.clockNumber).font;
				((TMP_Text)rankText).transform.SetParent(displayObject.transform, false);
				((TMP_Text)rankText).transform.localScale = new Vector3(1f, 1f, 1f);
				((TMP_Text)rankText).transform.localPosition = new Vector3(12f, 17f, 55f);
				vanillaXPText = Object.Instantiate<GameObject>(GameObject.Find("/Systems/UI/Canvas/EndgameStats/LevelUp/Total")).GetComponent<TextMeshProUGUI>();
				((Object)vanillaXPText).name = "BXPVanillaRankText";
				((TMP_Text)vanillaXPText).alignment = (TextAlignmentOptions)513;
				((TMP_Text)vanillaXPText).fontSize = 16f;
				((TMP_Text)vanillaXPText).transform.SetParent(displayObject.transform, false);
				((TMP_Text)vanillaXPText).transform.localScale = new Vector3(1f, 1f, 1f);
				((TMP_Text)vanillaXPText).transform.localPosition = new Vector3(12f, -64f, 55f);
				((Graphic)vanillaXPText).color = new Color(0.5f, 0.5f, 0.5f);
				((TMP_Text)vanillaXPText).alpha = 0.7f;
				progressText = Object.Instantiate<GameObject>(GameObject.Find("/Systems/UI/Canvas/EndgameStats/LevelUp/Total")).GetComponent<TextMeshProUGUI>();
				((Object)progressText).name = "BXPRankProgressText";
				((TMP_Text)progressText).alignment = (TextAlignmentOptions)257;
				((TMP_Text)progressText).fontSize = 21f;
				((TMP_Text)progressText).transform.SetParent(displayObject.transform, false);
				((TMP_Text)progressText).font = ((TMP_Text)HUDManager.Instance.clockNumber).font;
				((TMP_Text)progressText).transform.localScale = new Vector3(1f, 1f, 1f);
				((TMP_Text)progressText).transform.localPosition = new Vector3(16f, -17f, 55f);
				((Graphic)progressText).color = new Color(0.8f, 0.2f, 1f);
				((TMP_Text)progressText).alpha = 0.7f;
			}
		}
	}
	internal class PlayerControllerBPatch
	{
		public static Dictionary<int, JobTrackingManager.JobLogPlayerDeathInformation> PlayerDeathInformation = new Dictionary<int, JobTrackingManager.JobLogPlayerDeathInformation>();

		public static void TryCreateDeathInfo(int playerID)
		{
			if (!PlayerDeathInformation.ContainsKey(playerID))
			{
				PlayerDeathInformation.Add(playerID, null);
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "SyncShipUnlockablesClientRpc")]
		[HarmonyPostfix]
		private static void CollectAllAlreadyCollectedItems()
		{
			if (!NetworkManager.Singleton.IsHost)
			{
				GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
				GrabbableObject[] array2 = array;
				foreach (GrabbableObject val in array2)
				{
					GameNetworkManager.Instance.localPlayerController.SetItemInElevator(true, true, val);
				}
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")]
		[HarmonyPrefix]
		private static void KillLocalPlayerPatch(ref PlayerControllerB __instance, ref CauseOfDeath causeOfDeath)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			if (((NetworkBehaviour)__instance).IsOwner && !__instance.isPlayerDead && __instance.AllowPlayerDeath())
			{
				TryCreateDeathInfo((int)__instance.playerClientId);
				PlayerDeathInformation[(int)__instance.playerClientId] = new JobTrackingManager.JobLogPlayerDeathInformation
				{
					causeOfDeath = causeOfDeath,
					formattedCauseOfDeath = ((object)(CauseOfDeath)(ref causeOfDeath)).ToString(),
					realLifeTimeOfDeathInSeconds = Math.Max(0f, Time.realtimeSinceStartup - JobTrackingManager.timeAtStartOfDay),
					normalizedTimeOfDeath = TimeOfDay.Instance.currentDayTime / TimeOfDay.Instance.totalTime,
					formattedDayTimeOfDeath = GetFormattedTimeFromNormalizedTime(TimeOfDay.Instance.normalizedTimeOfDay, TimeOfDay.Instance.numberOfHours)
				};
			}
		}

		[HarmonyPatch(typeof(PlayerControllerB), "KillPlayerClientRpc")]
		[HarmonyPrefix]
		private static void KillNonLocalPlayerPatch(ref PlayerControllerB __instance, ref int playerId, ref int causeOfDeath)
		{
			//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)
			if (!((NetworkBehaviour)__instance).IsOwner && playerId != (int)GameNetworkManager.Instance.localPlayerController.playerClientId)
			{
				TryCreateDeathInfo((int)__instance.playerClientId);
				Dictionary<int, JobTrackingManager.JobLogPlayerDeathInformation> playerDeathInformation = PlayerDeathInformation;
				int key = (int)__instance.playerClientId;
				JobTrackingManager.JobLogPlayerDeathInformation obj = new JobTrackingManager.JobLogPlayerDeathInformation
				{
					causeOfDeath = (CauseOfDeath)causeOfDeath
				};
				CauseOfDeath val = (CauseOfDeath)causeOfDeath;
				obj.formattedCauseOfDeath = ((object)(CauseOfDeath)(ref val)).ToString();
				obj.realLifeTimeOfDeathInSeconds = Math.Max(0f, Time.realtimeSinceStartup - JobTrackingManager.timeAtStartOfDay);
				obj.normalizedTimeOfDeath = TimeOfDay.Instance.currentDayTime / TimeOfDay.Instance.totalTime;
				obj.formattedDayTimeOfDeath = GetFormattedTimeFromNormalizedTime(TimeOfDay.Instance.normalizedTimeOfDay, TimeOfDay.Instance.numberOfHours);
				playerDeathInformation[key] = obj;
			}
		}

		public static string GetFormattedTimeFromNormalizedTime(float timeNormalized, float numberOfHours)
		{
			int num = (int)(timeNormalized * (60f * numberOfHours)) + 360;
			int num2 = (int)Mathf.Floor((float)num / 60f);
			if (num2 >= 24)
			{
				return "12:00 AM";
			}
			string arg = ((num2 >= 12) ? "PM" : "AM");
			if (num2 > 12)
			{
				num2 %= 12;
			}
			int num3 = num % 60;
			return $"{num2:00}:{num3:00} {arg}";
		}
	}
	internal class Saving
	{
		public static readonly string bxpJobsFileLocation = GetSavePathLocation() + "/Jobs";

		public static string bxpJobsSessionLocation = bxpJobsFileLocation + "/session_unknown";

		public static string GetSavePathLocation()
		{
			return Application.persistentDataPath + "/swaggies/BetterEXP";
		}

		public static void Save()
		{
			BetterEXPPlugin.logr.LogInfo((object)"Saving data...");
			ES3.Save<int>("BetterXP", XPPatch.betterXp, "BetterEXP");
		}

		public static int Load()
		{
			BetterEXPPlugin.logr.LogMessage((object)"Attempting to load...");
			bxpJobsSessionLocation = $"{bxpJobsFileLocation}/session_{JobTrackingManager.GetUnixTimestamp(DateTime.UtcNow)}";
			int num = ES3.Load<int>("BetterXP", "BetterEXP", -1);
			if (num > -1)
			{
				XPPatch.betterXp = num;
				XPPatch.level = XPPatch.GetPlayerBetterLevelIndex(XPPatch.betterXp);
				BetterEXPPlugin.hasLoadedV2 = true;
				BetterEXPPlugin.logr.LogMessage((object)$"(V2.3.0) Loaded {XPPatch.betterXp} BXP - rank {XPPatch.GetPlayerBetterLevel(XPPatch.betterXp).name}.");
				return 3;
			}
			return -1;
		}

		public static void SaveJobToDisk(JobTrackingManager.JobLog job)
		{
			if (!Directory.Exists(bxpJobsFileLocation))
			{
				Directory.CreateDirectory(bxpJobsFileLocation);
			}
			if (!Directory.Exists(bxpJobsSessionLocation))
			{
				Directory.CreateDirectory(bxpJobsSessionLocation);
			}
			string text = bxpJobsSessionLocation + $"/{job.jobPlayedTime}" + "_" + job.moon + $"_{job.scrapCollected}" + $"-{job.totalAvailableScrap}" + ".json";
			File.WriteAllText(text, JsonConvert.SerializeObject((object)job));
			BetterEXPPlugin.logr.LogMessage((object)("successfully saved today's stats to " + text + "."));
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	internal class StartOfRoundPatch
	{
		public class NotesComparer
		{
			public List<int> players = new List<int>();

			public int stat = 0;

			public NotesComparer(int initialStat)
			{
				stat = initialStat;
			}
		}

		public class PlayerNote
		{
			public int id;

			public string note;

			public string value;

			public string color;

			public string unstyledNote;
		}

		public static List<PlayerNote> notesToAdd = new List<PlayerNote>();

		[HarmonyPatch("WritePlayerNotes")]
		[HarmonyPrefix]
		private static bool NotesOverride()
		{
			EndOfGameStats gameStats = StartOfRound.Instance.gameStats;
			int connectedPlayersAmount = StartOfRound.Instance.connectedPlayersAmount;
			PlayerStats[] allPlayerStats = gameStats.allPlayerStats;
			notesToAdd = new List<PlayerNote>();
			List<int> list = new List<int>();
			for (int i = 0; i < gameStats.allPlayerStats.Length; i++)
			{
				if (StartOfRound.Instance.gameStats.allPlayerStats[i] != null)
				{
					StartOfRound.Instance.gameStats.allPlayerStats[i].isActivePlayer = StartOfRound.Instance.allPlayerScripts[i].isPlayerDead || StartOfRound.Instance.allPlayerScripts[i].isPlayerControlled;
					if (StartOfRound.Instance.allPlayerScripts[i].disconnectedMidGame)
					{
						list.Add(i);
					}
				}
			}
			NotesComparer notesComparer = new NotesComparer(int.MaxValue);
			NotesComparer notesComparer2 = new NotesComparer(0);
			NotesComparer notesComparer3 = new NotesComparer(0);
			NotesComparer notesComparer4 = new NotesComparer(0);
			NotesComparer notesComparer5 = new NotesComparer(0);
			NotesComparer notesComparer6 = new NotesComparer(int.MaxValue);
			NotesComparer notesComparer7 = new NotesComparer(0);
			NotesComparer notesComparer8 = new NotesComparer(int.MaxValue);
			NotesComparer notesComparer9 = new NotesComparer(0);
			NotesComparer notesComparer10 = new NotesComparer(int.MaxValue);
			NotesComparer notesComparer11 = new NotesComparer(0);
			NotesComparer notesComparer12 = new NotesComparer(0);
			NotesComparer notesComparer13 = new NotesComparer(0);
			NotesComparer notesComparer14 = new NotesComparer(0);
			NotesComparer notesComparer15 = new NotesComparer(int.MaxValue);
			NotesComparer notesComparer16 = new NotesComparer(0);
			for (int j = 0; j < allPlayerStats.Length; j++)
			{
				PlayerStats val = allPlayerStats[j];
				int num = 0;
				if (EnemyAIPatch.playerEnemyKills.ContainsKey(j))
				{
					num = EnemyAIPatch.playerEnemyKills[j];
				}
				if (!val.isActivePlayer || list.Contains(j))
				{
					continue;
				}
				if (val.stepsTaken == notesComparer.stat)
				{
					notesComparer.players.Add(j);
				}
				else if (val.stepsTaken < notesComparer.stat)
				{
					notesComparer.players = new List<int> { j };
					notesComparer.stat = val.stepsTaken;
				}
				if (val.stepsTaken == notesComparer2.stat)
				{
					notesComparer2.players.Add(j);
				}
				else if (val.stepsTaken > notesComparer2.stat)
				{
					notesComparer2.players = new List<int> { j };
					notesComparer2.stat = val.stepsTaken;
				}
				if (val.turnAmount == notesComparer3.stat)
				{
					notesComparer3.players.Add(j);
				}
				else if (val.turnAmount > notesComparer3.stat)
				{
					notesComparer3.players = new List<int> { j };
					notesComparer3.stat = val.turnAmount;
				}
				if (val.damageTaken == notesComparer4.stat)
				{
					notesComparer4.players.Add(j);
				}
				else if (val.damageTaken > notesComparer4.stat)
				{
					notesComparer4.players = new List<int> { j };
					notesComparer4.stat = val.damageTaken;
				}
				if (val.profitable == notesComparer5.stat)
				{
					notesComparer5.players.Add(j);
				}
				else if (val.profitable > notesComparer5.stat)
				{
					notesComparer5.players = new List<int> { j };
					notesComparer5.stat = val.profitable;
				}
				if (val.profitable == notesComparer6.stat)
				{
					notesComparer6.players.Add(j);
				}
				else if (val.profitable < notesComparer6.stat)
				{
					notesComparer6.players = new List<int> { j };
					notesComparer6.stat = val.profitable;
				}
				if (num == notesComparer7.stat)
				{
					notesComparer7.players.Add(j);
				}
				else if (num > notesComparer7.stat)
				{
					notesComparer7.players = new List<int> { j };
					notesComparer7.stat = num;
				}
				if (num == notesComparer8.stat)
				{
					notesComparer8.players.Add(j);
				}
				else if (num < notesComparer8.stat)
				{
					notesComparer8.players = new List<int> { j };
					notesComparer8.stat = num;
				}
				if (NotesPatch.CustomPlayerStats.ContainsKey(j))
				{
					NotesPatch.CustomPlayerStat customPlayerStat = NotesPatch.CustomPlayerStats[j];
					int scrapFound = customPlayerStat.scrapFound;
					if (scrapFound == notesComparer14.stat)
					{
						notesComparer14.players.Add(j);
					}
					else if (scrapFound > notesComparer14.stat)
					{
						notesComparer14.players = new List<int> { j };
						notesComparer14.stat = scrapFound;
					}
					if (scrapFound == notesComparer15.stat)
					{
						notesComparer15.players.Add(j);
					}
					else if (scrapFound < notesComparer15.stat)
					{
						notesComparer15.players = new List<int> { j };
						notesComparer15.stat = scrapFound;
					}
					if (customPlayerStat.scrapFoundDeliveredToShip == notesComparer16.stat)
					{
						notesComparer16.players.Add(j);
					}
					else if (customPlayerStat.scrapFoundDeliveredToShip > notesComparer16.stat)
					{
						notesComparer16.players = new List<int> { j };
						notesComparer16.stat = customPlayerStat.scrapFoundDeliveredToShip;
					}
					if (customPlayerStat.indoorTime % 1f >= 0.9f)
					{
						customPlayerStat.indoorTime += 1f;
					}
					if (customPlayerStat.outdoorTime % 1f >= 0.9f)
					{
						customPlayerStat.outdoorTime += 1f;
					}
					if (customPlayerStat.shipTime % 1f >= 0.9f)
					{
						customPlayerStat.shipTime += 1f;
					}
					int num2 = (int)customPlayerStat.indoorTime;
					int num3 = (int)customPlayerStat.outdoorTime;
					int num4 = (int)customPlayerStat.shipTime;
					if (customPlayerStat.jumps == notesComparer9.stat)
					{
						notesComparer9.players.Add(j);
					}
					else if (customPlayerStat.jumps > notesComparer9.stat)
					{
						notesComparer9.players = new List<int> { j };
						notesComparer9.stat = customPlayerStat.jumps;
					}
					if (customPlayerStat.jumps == notesComparer10.stat)
					{
						notesComparer10.players.Add(j);
					}
					else if (customPlayerStat.jumps < notesComparer10.stat)
					{
						notesComparer10.players = new List<int> { j };
						notesComparer10.stat = customPlayerStat.jumps;
					}
					if (num2 == notesComparer11.stat)
					{
						notesComparer11.players.Add(j);
					}
					else if (num2 > notesComparer11.stat)
					{
						notesComparer11.players = new List<int> { j };
						notesComparer11.stat = num2;
					}
					if (num3 == notesComparer12.stat)
					{
						notesComparer12.players.Add(j);
					}
					else if (num3 > notesComparer12.stat)
					{
						notesComparer12.players = new List<int> { j };
						notesComparer12.stat = num3;
					}
					if (num4 == notesComparer13.stat)
					{
						notesComparer13.players.Add(j);
					}
					else if (num4 > notesComparer13.stat)
					{
						notesComparer13.players = new List<int> { j };
						notesComparer13.stat = num4;
					}
				}
			}
			bool flag = connectedPlayersAmount > 0;
			for (int k = 0; k < allPlayerStats.Length; k++)
			{
				PlayerStats val2 = allPlayerStats[k];
				if (val2.isActivePlayer)
				{
					if (flag && notesComparer5.stat > 0 && notesComparer5.players.Contains(k))
					{
						AddNote(k, BetterEXPPlugin.PerformanceReportStyling.Value ? "* <size=120%>Most Profitable!</size>" : "* Most Profitable!", $"${notesComparer5.stat}", "#00ff69", "* Most Profitable!");
					}
					if (notesComparer14.stat > 0 && notesComparer14.players.Contains(k) && BetterEXPPlugin.ScavengerNote.Value)
					{
						AddNote(k, BetterEXPPlugin.PerformanceReportStyling.Value ? "* <size=110%>#1 Scavenger</size>" : "* #1 Scavenger", $"${notesComparer14.stat} found", "#36ff36", "* #1 Scavenger");
					}
					if (notesComparer16.stat > 0 && notesComparer14.players.Contains(k) && BetterEXPPlugin.ScavengerNote.Value)
					{
						AddNote(k, BetterEXPPlugin.PerformanceReportStyling.Value ? "* <size=105%>Team Backbone</size>" : "* Team Backbone", $"${notesComparer16.stat} returned", "#f5b207", "* Team Backbone");
					}
					if (notesComparer7.stat > 0 && notesComparer7.players.Contains(k) && BetterEXPPlugin.LethalNote.Value)
					{
						string arg = ((notesComparer7.stat == 1) ? "kill" : "kills");
						AddNote(k, "* Most Lethal", $"{notesComparer7.stat} {arg}", "#ff00ea");
					}
					if (flag && notesComparer11.stat > 0 && notesComparer11.players.Contains(k) && BetterEXPPlugin.BraveryNote.Value)
					{
						AddNote(k, "* The Bravest", Helpers.FormatTime(notesComparer11.stat) + " inside", "#a5fc03");
					}
					if (notesComparer2.stat > 0 && notesComparer2.players.Contains(k) && BetterEXPPlugin.MostActiveNote.Value)
					{
						AddNote(k, "* Most Active", $"{notesComparer2.stat} steps", "#eeee36");
					}
					if (notesComparer15.stat == 0 && notesComparer15.players.Contains(k) && BetterEXPPlugin.ScavengerNote.Value && BetterEXPPlugin.NegativeNotes.Value)
					{
						AddNote(k, "* Empty-Handed", $"${notesComparer15.stat} found", "#094d85");
					}
					if (notesComparer4.stat > 0 && notesComparer4.players.Contains(k))
					{
						AddNote(k, "* Most Injured", $"{notesComparer4.stat} damage", "#ee7726");
					}
					if (notesComparer3.stat > 0 && flag && notesComparer3.players.Contains(k) && BetterEXPPlugin.NegativeNotes.Value)
					{
						AddNote(k, "* Most Paranoid", $"{notesComparer3.stat} turns", "#ff4269");
					}
					if (flag && notesComparer9.stat > 0 && notesComparer9.players.Contains(k) && BetterEXPPlugin.JumpingNote.Value)
					{
						AddNote(k, "* Most Jumpy", $"{notesComparer9.stat} jumps", "#3cb4fa");
					}
					if (flag && notesComparer8.stat == 0 && notesComparer8.players.Contains(k) && notesComparer8.players.Count == 1 && BetterEXPPlugin.LethalNote.Value && BetterEXPPlugin.NegativeNotes.Value)
					{
						AddNote(k, "* The Pacifist", $"{notesComparer8.stat} kills", "#93bfa2");
					}
					if (flag && notesComparer.players.Contains(k) && BetterEXPPlugin.NegativeNotes.Value)
					{
						AddNote(k, "* The Laziest", $"{notesComparer.stat} steps", "#4296ee");
					}
					if (flag && notesComparer13.stat > 0 && notesComparer13.players.Contains(k) && BetterEXPPlugin.ShipDutyNote.Value)
					{
						AddNote(k, "* The Ship Guy", Helpers.FormatTime(notesComparer13.stat) + " on ship", "#babed1");
					}
					if (flag && notesComparer10.players.Contains(k) && BetterEXPPlugin.JumpingNote.Value && BetterEXPPlugin.NegativeNotes.Value)
					{
						AddNote(k, "* Most Grounded", $"{notesComparer10.stat} jumps", "#1b7a4f");
					}
					if (flag && notesComparer6.players.Contains(k) && BetterEXPPlugin.NegativeNotes.Value && BetterEXPPlugin.LeastProfitableNote.Value)
					{
						AddNote(k, "* Least Profitable", $"${notesComparer6.stat}", "#6926cc");
					}
					if (flag && notesComparer12.stat > 0 && notesComparer12.players.Contains(k) && BetterEXPPlugin.BraveryNote.Value && BetterEXPPlugin.NegativeNotes.Value)
					{
						AddNote(k, "* Most Outdoors", Helpers.FormatTime(notesComparer12.stat) + " outside", "#80c484");
					}
				}
			}
			int num5 = (int)GameNetworkManager.Instance.localPlayerController.playerClientId;
			XPPatch.profitable = allPlayerStats[num5].profitable;
			XPPatch.isMostProfitable = notesComparer5.players.Contains(num5);
			return false;
		}

		[HarmonyPatch("openingDoorsSequence")]
		[HarmonyPrefix]
		private static void SetTimeAtStartOfDay()
		{
			JobTrackingManager.timeAtStartOfDay = Time.realtimeSinceStartup;
			JobTrackingManager.meteorShowerAtTime = -1f;
		}

		[HarmonyPatch("ShipHasLeft")]
		[HarmonyPrefix]
		private static void SetTimeAtEndOfDay()
		{
			JobTrackingManager.timeAtEndOfDay = Time.realtimeSinceStartup;
		}

		[HarmonyPatch(typeof(RoundManager), "SyncScrapValuesClientRpc")]
		[HarmonyPostfix]
		private static void CheckForSingleScrapDay(ref NetworkObjectReference[] spawnedScrap)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			string text = "";
			GrabbableObject val = null;
			NetworkObjectReference[] array = spawnedScrap;
			NetworkObject val3 = default(NetworkObject);
			for (int i = 0; i < array.Length; i++)
			{
				NetworkObjectReference val2 = array[i];
				if (!((NetworkObjectReference)(ref val2)).TryGet(ref val3, (NetworkManager)null))
				{
					continue;
				}
				GrabbableObject component = ((Component)val3).GetComponent<GrabbableObject>();
				if (!((Object)(object)component == (Object)null) && !((Object)(object)component.itemProperties == (Object)null) && !(component is KnifeItem) && !(component is ShotgunItem) && !(component is LungProp) && component.itemProperties.isScrap)
				{
					BetterEXPPlugin.logr.LogMessage((object)("item: " + component.itemProperties.itemName + " / " + text));
					if (string.IsNullOrEmpty(text))
					{
						text = component.itemProperties.itemName;
						val = component;
					}
					if (component.itemProperties.itemName != text)
					{
						JobTrackingManager.singleScrapDayItemName = null;
						BetterEXPPlugin.logr.LogMessage((object)"womp.");
						return;
					}
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				JobTrackingManager.singleScrapDayItemName = null;
				BetterEXPPlugin.logr.LogMessage((object)"womp2.");
				return;
			}
			BetterEXPPlugin.logr.LogMessage((object)("success! - " + val.itemProperties.itemName));
			ScanNodeProperties componentInChildren = ((Component)val).GetComponentInChildren<ScanNodeProperties>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				JobTrackingManager.singleScrapDayItemName = componentInChildren.headerText;
			}
			else
			{
				JobTrackingManager.singleScrapDayItemName = val.itemProperties.itemName;
			}
		}

		[HarmonyPatch(typeof(RoundManager), "RefreshEnemiesList")]
		[HarmonyPostfix]
		private static void CheckForEnemyRush(ref RoundManager __instance)
		{
			int value = Traverse.Create((object)__instance).Field("enemyRushIndex").GetValue<int>();
			if (value == -1)
			{
				JobTrackingManager.enemyRushDayEnemyName = null;
			}
			else if (__instance.currentLevel.Enemies[value] == null)
			{
				JobTrackingManager.enemyRushDayEnemyName = null;
			}
			else
			{
				JobTrackingManager.enemyRushDayEnemyName = __instance.currentLevel.Enemies[value].enemyType.enemyName;
			}
		}

		[HarmonyPatch(typeof(HUDManager), "MeteorShowerWarningHUD")]
		[HarmonyPostfix]
		private static void MeteorShower()
		{
			JobTrackingManager.meteorShowerAtTime = TimeOfDay.Instance.normalizedTimeOfDay;
		}

		[HarmonyPatch(typeof(HUDManager), "FillEndGameStats")]
		[HarmonyPostfix]
		private static void CompleteNotes(ref HUDManager __instance, ref int scrapCollected)
		{
			foreach (PlayerNote item in notesToAdd)
			{
				if (item.id >= __instance.statsUIElements.playerNotesText.Length)
				{
					continue;
				}
				TextMeshProUGUI val = __instance.statsUIElements.playerNotesText[item.id];
				string text = (BetterEXPPlugin.PerformanceReportStyling.Value ? ("<color=" + item.color + ">" + item.note + "</color>") : item.note);
				((TMP_Text)val).text = ((TMP_Text)val).text + text;
				if (BetterEXPPlugin.PerformanceReportStats.Value)
				{
					if (BetterEXPPlugin.PerformanceReportStyling.Value)
					{
						((TMP_Text)val).text = ((TMP_Text)val).text + " <size=75%><color=#ff96bb>(" + item.value + ")</color></size>";
					}
					else
					{
						((TMP_Text)val).text = ((TMP_Text)val).text + " <size=75%>(" + item.value + ")</size>";
					}
				}
				((TMP_Text)val).text = ((TMP_Text)val).text + "\n";
			}
			for (int i = 0; i < StartOfRound.Instance.gameStats.allPlayerStats.Length; i++)
			{
				PlayerStats val2 = StartOfRound.Instance.gameStats.allPlayerStats[i];
				TextMeshProUGUI val3 = __instance.statsUIElements.playerNamesText[i];
				if (!val2.isActivePlayer)
				{
					string text2 = ((TMP_Text)val3).text;
					if (!(text2 == "") && !(text2 == " "))
					{
						((TMP_Text)val3).text = "<color=#969696><s>" + text2 + "</s></color>";
						if (BetterEXPPlugin.collectedDisplayOption.Value == BetterEXPPlugin.CollectedDisplayOptionSettings.BELOW_NAME)
						{
							((TMP_Text)val3).text = ((TMP_Text)val3).text + "<size=85%>\n<color=#bbbbbb><i>Disconnected.</i></color></size>\n";
						}
					}
				}
				else if (BetterEXPPlugin.collectedDisplayOption.Value == BetterEXPPlugin.CollectedDisplayOptionSettings.BELOW_NAME)
				{
					((TMP_Text)val3).text = ((TMP_Text)val3).text + $"<size=85%>\n<color=#ff96bb>Collected: ${val2.profitable}</color></size>\n";
				}
				else if (BetterEXPPlugin.collectedDisplayOption.Value == BetterEXPPlugin.CollectedDisplayOptionSettings.BESIDE_NAME)
				{
					((TMP_Text)val3).text = ((TMP_Text)val3).text + $"<size=75%><color=#ff96bb>  ${val2.profitable}</color></size>\n";
				}
			}
			VisualEXPPatch.BetterEXPLog betterEXPLog = VisualEXPPatch.CalculateBXPGain(XPPatch.betterXp, scrapCollected, (int)RoundManager.Instance.totalScrapValueInLevel, GameNetworkManager.Instance.localPlayerController.isPlayerDead, StartOfRound.Instance.allPlayersDead, XPPatch.isMostProfitable);
			XPPatch.SetBetterXP(betterEXPLog.newBXP);
			JobTrackingManager.LogJobUsingContext(scrapCollected, betterEXPLog);
			notesToAdd.Clear();
		}

		private static void AddNote(int id, string note, string value, string color, string unstyledNote = null)
		{
			notesToAdd.Add(new PlayerNote
			{
				id = id,
				note = note,
				value = value,
				color = color,
				unstyledNote = unstyledNote
			});
		}

		[HarmonyPatch("ResetStats")]
		[HarmonyPrefix]
		private static bool ResetStatsFix()
		{
			for (int i = 0; i < StartOfRound.Instance.gameStats.allPlayerStats.Length; i++)
			{
				StartOfRound.Instance.gameStats.allPlayerStats[i].damageTaken = 0;
				StartOfRound.Instance.gameStats.allPlayerStats[i].jumps = 0;
				StartOfRound.Instance.gameStats.allPlayerStats[i].stepsTaken = 0;
				StartOfRound.Instance.gameStats.allPlayerStats[i].profitable = 0;
				StartOfRound.Instance.gameStats.allPlayerStats[i].turnAmount = 0;
				StartOfRound.Instance.gameStats.allPlayerStats[i].playerNotes.Clear();
			}
			NotesPatch.CustomPlayerStats.Clear();
			NotesPatch.ThisMoonObjects.Clear();
			PlayerControllerBPatch.PlayerDeathInformation.Clear();
			EnemyAIPatch.ResetAllEnemyKills();
			return false;
		}
	}
	internal class VisualEXPPatch
	{
		private enum RankChangeDirection
		{
			UP,
			DOWN,
			NONE
		}

		public class BetterEXPLog
		{
			public bool mostProfitable = false;

			public int scrapXp = 0;

			public int contributionXp = 0;

			public int scavengerXp = 0;

			public int enemyKillXp = 0;

			public int deathPenalty = 0;

			public int weatherBonusXp = 0;

			public int totalGain = 0;

			public int oldBXP = 0;

			public int newBXP = 0;

			public float weatherBonusAmount = 0f;
		}

		public static int scrapCollectedOnServer = 0;

		public static BetterEXPLog gainedBetterEXPData = new BetterEXPLog();

		[HarmonyPatch(typeof(HUDManager), "SetPlayerLevelSmoothly")]
		[HarmonyPrefix]
		private static bool SetPlayerLevelSmoothlyPatch(int XPGain)
		{
			return false;
		}

		private static IEnumerator EXPProcess(BetterEXPLog data)
		{
			bool hasReachedTargetXP = false;
			int changingPlayerLevel = XPPatch.GetPlayerBetterLevelIndex(data.oldBXP);
			int amountToChange = Math.Abs(data.totalGain);
			float changingPlayerXP = data.oldBXP;
			if (data.totalGain < 0)
			{
				HUDManager.Instance.LevellingAudio.clip = HUDManager.Instance.decreaseXPSFX;
			}
			else
			{
				HUDManager.Instance.LevellingAudio.clip = HUDManager.Instance.increaseXPSFX;
			}
			HUDManager.Instance.LevellingAudio.Play();
			RankChangeDirection rankChangeDirection = RankChangeDirection.NONE;
			float timeAtStart = Time.realtimeSinceStartup;
			while (!hasReachedTargetXP)
			{
				if (Time.realtimeSinceStartup - timeAtStart > 2.5f)
				{
					FinishEXPProcess(data.newBXP, rankChangeDirection);
					yield break;
				}
				if (data.totalGain < 0)
				{
					changingPlayerXP -= (float)amountToChange * Time.deltaTime / 1.05f;
					if (changingPlayerXP <= (float)data.newBXP)
					{
						hasReachedTargetXP = true;
						changingPlayerXP = data.newBXP;
					}
					if (changingPlayerLevel - 1 >= 0 && changingPlayerXP < (float)XPPatch.betterLevels[changingPlayerLevel].xp)
					{
						changingPlayerLevel--;
						HUDManager.Instance.UIAudio.PlayOneShot(HUDManager.Instance.levelDecreaseSFX);
						HUDManager.Instance.playerLevelBoxAnimator.SetTrigger("Shake");
						rankChangeDirection = RankChangeDirection.DOWN;
					}
				}
				else
				{
					changingPlayerXP += (float)amountToChange * Time.deltaTime / 1.95f;
					if (changingPlayerXP >= (float)data.newBXP)
					{
						hasReachedTargetXP = true;
						changingPlayerXP = data.newBXP;
					}
					if (changingPlayerLevel + 1 < XPPatch.betterLevels.Length && changingPlayerXP >= (float)XPPatch.betterLevels[changingPlayerLevel].xpEnd)
					{
						changingPlayerLevel++;
						HUDManager.Instance.UIAudio.PlayOneShot(HUDManager.Instance.levelIncreaseSFX);
						HUDManager.Instance.playerLevelBoxAnimator.SetTrigger("Shake");
						rankChangeDirection = RankChangeDirection.UP;
					}
				}
				HUDManager.Instance.playerLevelMeter.fillAmount = (changingPlayerXP - (float)XPPatch.betterLevels[changingPlayerLevel].xp) / (float)(XPPatch.betterLevels[changingPlayerLevel].xpEnd - XPPatch.betterLevels[changingPlayerLevel].xp);
				((TMP_Text)HUDManager.Instance.playerLevelText).text = XPPatch.betterLevels[changingPlayerLevel].name;
				((TMP_Text)HUDManager.Instance.playerLevelXPCounter).text = $"<color=#ffff00>{(int)changingPlayerXP} BXP</color>";
				switch (rankChangeDirection)
				{
				case RankChangeDirection.UP:
					((TMP_Text)HUDManager.Instance.playerLevelText).text = "<color=#ffff00>" + XPPatch.betterLevels[changingPlayerLevel].name + "</color>";
					break;
				default:
					((TMP_Text)HUDManager.Instance.playerLevelText).text = "<color=#6969ff>" + XPPatch.betterLevels[changingPlayerLevel].name + "</color>";
					break;
				case RankChangeDirection.NONE:
					break;
				}
				yield return null;
			}
			FinishEXPProcess(data.newBXP, rankChangeDirection);
		}

		private static void FinishEXPProcess(int targetXPLevel, RankChangeDirection rankChangeDirection)
		{
			HUDManager.Instance.LevellingAudio.Stop();
			XPPatch.BetterLevel playerBetterLevel = XPPatch.GetPlayerBetterLevel(targetXPLevel);
			((TMP_Text)HUDManager.Instance.playerLevelText).text = playerBetterLevel.name;
			switch (rankChangeDirection)
			{
			case RankChangeDirection.UP:
				((TMP_Text)HUDManager.Instance.playerLevelText).text = "<color=#ffff00>" + playerBetterLevel.name + "</color>";
				break;
			default:
				((TMP_Text)HUDManager.Instance.playerLevelText).text = "<color=#6969ff>" + playerBetterLevel.name + "</color>";
				break;
			case RankChangeDirection.NONE:
				break;
			}
			((TMP_Text)HUDManager.Instance.playerLevelXPCounter).text = $"<color=#ffff00>{targetXPLevel} BXP</color>";
		}

		private static void HandleOldLevelling(bool isDead, bool mostProfitable, bool allPlayersDead)
		{
			int num = (isDead ? (-3) : 10);
			if (mostProfitable)
			{
				num += 15;
			}
			if (allPlayersDead)
			{
				num -= 5;
			}
			if (num > 0)
			{
				float num2 = Mathf.Clamp((float)RoundManager.Instance.scrapCollectedInLevel, 0f, RoundManager.Instance.totalScrapValueInLevel) / Math.Max(1f, RoundManager.Instance.totalScrapValueInLevel);
				num = (int)((float)num * num2);
			}
			HUDManager instance = HUDManager.Instance;
			instance.localPlayerXP += num;
			int localPlayerLevel = 0;
			for (int i = 0; i < HUDManager.Instance.playerLevels.Length; i++)
			{
				if (i == HUDManager.Instance.playerLevels.Length - 1)
				{
					localPlayerLevel = i;
					break;
				}
				if (HUDManager.Instance.localPlayerXP >= HUDManager.Instance.playerLevels[i].XPMin && HUDManager.Instance.localPlayerXP < HUDManager.Instance.playerLevels[i].XPMax)
				{
					localPlayerLevel = i;
					break;
				}
			}
			HUDManager.Instance.localPlayerLevel = localPlayerLevel;
		}

		[HarmonyPatch(typeof(HUDManager), "SetPlayerLevel")]
		[HarmonyPrefix]
		private static bool CancelOGExp(ref bool isDead, ref bool allPlayersDead)
		{
			ReplaceEXP(isDead, allPlayersDead);
			return false;
		}

		private static float GetWeatherModifier()
		{
			//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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: 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_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected I4, but got Unknown
			LevelWeatherType currentWeather = WeatherPatch.currentWeather;
			LevelWeatherType val = currentWeather;
			return (val - -1) switch
			{
				0 => 0f, 
				2 => 0.1f, 
				4 => 0.15f, 
				5 => 0.2f, 
				3 => 0.25f, 
				6 => 0.3f, 
				_ => 0f, 
			};
		}

		private static int GetDeathXp(int currentXp, bool dead, bool allPlayersDead, int scrapXp, int contributionXp, int enemyKillXp)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Invalid comparison between Unknown and I4
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Invalid comparison between Unknown and I4
			if (!dead)
			{
				return 0;
			}
			if ((int)GameNetworkManager.Instance.localPlayerController.causeOfDeath == 1)
			{
				return -1;
			}
			float num = Mathf.Clamp((float)Math.Sqrt(currentXp) / 3f, 0f, 50f);
			if (allPlayersDead)
			{
				num = Mathf.Clamp(num * 1.2f, 0f, 60f);
			}
			if ((int)GameNetworkManager.Instance.localPlayerController.causeOfDeath == 10)
			{
				return (int)Math.Max(0f - num, -10f);
			}
			return (int)Math.Ceiling(num) * -1;
		}

		private static double GetMoonMaxXp(int scrapTotal)
		{
			double num = 0.0;
			num += Helpers.NumBetween(scrapTotal, 0.0, 300.0) * 7.0;
			num += Helpers.NumBetween(scrapTotal, 300.0, 500.0) * 8.0;
			num += Helpers.NumBetween(scrapTotal, 500.0, 700.0) * 10.0;
			num += Helpers.NumBetween(scrapTotal, 700.0, 1000.0) * 12.0;
			num += Helpers.NumBetween(scrapTotal, 1000.0, 2500.0) * 43.0;
			return num + Helpers.NumBetween(scrapTotal, 2500.0, 9999.0) * 20.0;
		}

		private static int GetScrapXp(int scrapCollected, int scrapTotal)
		{
			double moonMaxXp = GetMoonMaxXp(scrapTotal);
			double value = Mathf.Clamp(Mathf.Clamp((float)scrapCollected, 0f, 9999f) / Mathf.Clamp((float)scrapTotal, 1f, 9999f), 0f, 1f);
			double num = 0.0;
			num += Helpers.NumBetween(value, 0.0, 0.2) * 0.2;
			num += Helpers.NumBetween(value, 0.2, 0.4) * 0.28;
			num += Helpers.NumBetween(value, 0.4, 0.6) * 0.22;
			num += Helpers.NumBetween(value, 0.6, 0.8) * 0.16;
			num += Helpers.NumBetween(value, 0.8, 1.0) * 0.14;
			return (int)Math.Ceiling(moonMaxXp * num);
		}

		private static int GetMVPScrapBonusXp(int originalXp, int selfProfits, int scrapTotal)
		{
			return (int)((float)originalXp * Mathf.Clamp(0.2f * (float)selfProfits / Math.Max(scrapTotal, 1f), 0f, 0.2f));
		}

		private static int GetWeatherBonusXp(int totalXp)
		{
			return (int)((float)totalXp * GetWeatherModifier());
		}

		private static int GetScavengerBonusXp(int totalAvailableScrap)
		{
			float num = 0f;
			int key = (int)GameNetworkManager.Instance.localPlayerController.playerClientId;
			if (!NotesPatch.CustomPlayerStats.ContainsKey(key))
			{
				return 0;
			}
			num += (float)NotesPatch.CustomPlayerStats[key].scrapFoundDeliveredToShip;
			num += 0.25f * (float)(NotesPatch.CustomPlayerStats[key].scrapFound - NotesPatch.CustomPlayerStats[key].scrapFoundDeliveredToShip);
			return (int)(GetMoonMaxXp(totalAvailableScrap) * (double)Mathf.Clamp01(num / (float)Math.Max(1, totalAvailableScrap)));
		}

		public static BetterEXPLog CalculateBXPGain(int currentXP, int scrapCollected, int scrapTotal, bool localPlayerDead, bool allPlayersDead, bool isMostProfitable)
		{
			int scrapXp = GetScrapXp(scrapCollected, scrapTotal);
			int mVPScrapBonusXp = GetMVPScrapBonusXp(scrapXp, XPPatch.profitable, scrapTotal);
			int scavengerBonusXp = GetScavengerBonusXp(scrapTotal);
			int xpFromKilledEnemies = EnemyAIPatch.GetXpFromKilledEnemies();
			int deathXp = GetDeathXp(currentXP, localPlayerDead, allPlayersDead, scrapXp, mVPScrapBonusXp, xpFromKilledEnemies);
			int weatherBonusXp = GetWeatherBonusXp(scrapXp + mVPScrapBonusXp + xpFromKilledEnemies + deathXp);
			int num = scrapXp + mVPScrapBonusXp + scavengerBonusXp + xpFromKilledEnemies + deathXp + weatherBonusXp;
			gainedBetterEXPData = new BetterEXPLog
			{
				mostProfitable = isMostProfitable,
				scrapXp = scrapXp,
				contributionXp = mVPScrapBonusXp,
				scavengerXp = scavengerBonusXp,
				enemyKillXp = xpFromKilledEnemies,
				deathPenalty = deathXp,
				weatherBonusXp = weatherBonusXp,
				totalGain = num,
				oldBXP = XPPatch.betterXp,
				newBXP = Mathf.Clamp(XPPatch.betterXp + num, 0, XPPatch.maxBetterXp),
				weatherBonusAmount = GetWeatherModifier()
			};
			return gainedBetterEXPData;
		}

		public static void ReplaceEXP(bool isDead, bool allPlayersDead)
		{
			HandleOldLevelling(isDead, XPPatch.isMostProfitable, allPlayersDead);
			EnemyAIPatch.ResetAllEnemyKills();
			if (gainedBetterEXPData.totalGain == 0)
			{
				FinishEXPProcess(gainedBetterEXPData.newBXP, RankChangeDirection.NONE);
			}
			else
			{
				((MonoBehaviour)StartOfRound.Instance).StartCoroutine(EXPProcess(gainedBetterEXPData));
			}
		}

		[HarmonyPatch(typeof(StartOfRound), "PassTimeToNextDay")]
		[HarmonyPostfix]
		private static void BeginShowExpGains()
		{
			Saving.Save();
			if (StartOfRound.Instance.currentLevel.planetHasTime)
			{
				((MonoBehaviour)HUDManager.Instance).StartCoroutine(ShowExpGains(gainedBetterEXPData));
			}
		}

		private static IEnumerator ShowExpGains(BetterEXPLog log)
		{
			if (BetterEXPPlugin.showRoundSummary.Value)
			{
				string badcolor = "#000096";
				string neutralcolor = "#424242";
				string goodcoloralt = "#ff00ff";
				string goodcolor = "#6900ff";
				string color = ((log.totalGain > 0) ? goodcolor : ((log.totalGain == 0) ? neutralcolor : badcolor));
				if (log.totalGain >= 100)
				{
					color = goodcoloralt;
				}
				string roundExperience = $"Today's Results: <color={color}>{log.totalGain} BXP</color>";
				int profitXp = log.scrapXp + log.contributionXp;
				string scrapColor = ((profitXp == 0) ? neutralcolor : goodcolor);
				string weatherColor = ((log.weatherBonusXp > 0) ? goodcoloralt : ((log.weatherBonusXp == 0) ? neutralcolor : badcolor));
				string weatherSign = ((log.weatherBonusXp < 0) ? "-" : " ");
				string weatherString = $"{weatherSign}{Math.Abs(log.weatherBonusXp)} BXP";
				string deathPenalty = $"Death Penalty . . . . <color={badcolor}>-{Math.Abs(log.deathPenalty)} BXP</color>\n";
				string scrapFinal = $"Scrap Delivered . . . <color={scrapColor}> {profitXp} BXP</color>\n";
				string scavenger = $"Scrap You Found . . . <color={scrapColor}> {log.scavengerXp} BXP</color>\n";
				string enemyKills = $"Lethality Bonus . . . <color={goodcoloralt}> {log.enemyKillXp} BXP</color>\n";
				string weather = "Weather Bonus . . . . <color=" + weatherColor + ">" + weatherString + "</color>";
				string deathFinal = ((log.deathPenalty == 0) ? "" : deathPenalty);
				string scavengerFinal = ((log.scavengerXp > 0) ? scavenger : "");
				string enemyFinal = ((log.enemyKillXp > 0) ? enemyKills : "");
				string weatherFinal = ((log.weatherBonusAmount != 0f) ? weather : "");
				yield return (object)new WaitForSeconds(3f);
				HUDManager.Instance.DisplayTip(roundExperience, "<size=90%>" + deathFinal + scrapFinal + scavengerFinal + enemyFinal + weatherFinal + "</size>", false, false, "LC_Tip1");
			}
		}
	}
	internal class WeatherPatch
	{
		public static LevelWeatherType currentWeather = (LevelWeatherType)(-1);

		public static bool currentPlanetHasSnow = false;

		[HarmonyPatch(typeof(StartOfRound), "OnShipLandedMiscEvents")]
		[HarmonyPostfix]
		private static void SetWeatherType()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			currentWeather = TimeOfDay.Instance.currentLevelWeather;
			currentPlanetHasSnow = TimeOfDay.Instance.currentLevel.levelIncludesSnowFootprints;
		}
	}
	internal class XPPatch
	{
		public enum VanillaRank
		{
			Intern,
			PartTimer,
			Employee,
			Leader,
			Boss
		}

		public class BetterLevel
		{
			public string name;

			public int xp;

			public int xpEnd;

			public BetterLevel(string levelName, int startXp, int endXp)
			{
				name = levelName;
				xp = startXp;
				xpEnd = endXp;
			}
		}

		public static int level = -1;

		public static int betterXp = 0;

		public static int profitable = 0;

		public static bool isMostProfitable = false;

		private static readonly Dictionary<int, VanillaRank> betterExpToVanillaRank = new Dictionary<int, VanillaRank>
		{
			{
				1000,
				VanillaRank.Boss
			},
			{
				400,
				VanillaRank.Leader
			},
			{
				200,
				VanillaRank.Employee
			},
			{
				50,
				VanillaRank.PartTimer
			},
			{
				0,
				VanillaRank.Intern
			}
		};

		public static readonly int maxBetterXp = 999999999;

		public static BetterLevel[] betterLevels = new BetterLevel[69]
		{
			new BetterLevel("Intern", 0, 25),
			new BetterLevel("Trainee", 25, 50),
			new BetterLevel("Apprentice", 50, 100),
			new BetterLevel("Part-Timer", 100, 200),
			new BetterLevel("Full-Timer", 200, 300),
			new BetterLevel("Employee", 300, 400),
			new BetterLevel("Leader", 400, 600),
			new BetterLevel("Manager", 600, 800),
			new BetterLevel("Sr. Manager", 800, 1000),
			new BetterLevel("3rd Boss", 1000, 1300),
			new BetterLevel("2nd Boss", 1300, 1600),
			new BetterLevel("1st Boss", 1600, 2000),
			new BetterLevel("3rd Vice President", 2000, 2300),
			new BetterLevel("2nd Vice President", 2300, 2600),
			new BetterLevel("1st Vice President", 2600, 3000),
			new BetterLevel("3rd Executive V.P.", 3000, 3300),
			new BetterLevel("2nd Executive V.P.", 3300, 3600),
			new BetterLevel("1st Executive V.P.", 3600, 4000),
			new BetterLevel("3rd Deputy President", 4000, 4300),
			new BetterLevel("2nd Deputy President", 4300, 4600),
			new BetterLevel("1st Deputy President", 4600, 5000),
			new BetterLevel("President", 5000, 5500),
			new BetterLevel("Sr. President", 5500, 6000),
			new BetterLevel("Vice Chairman", 6000, 6500),
			new BetterLevel("Chairman", 6500, 7500),
			new BetterLevel("First-Class Asset", 7500, 8500),
			new BetterLevel("Co-Founder", 8500, 10000),
			new BetterLevel("Founder", 10000, 11000),
			new BetterLevel("Greatest Asset", 11000, 12000),
			new BetterLevel("Greatest Asset II", 12000, 13000),
			new BetterLevel("Greatest Asset III", 13000, 14000),
			new BetterLevel("Greatest Asset IV", 14000, 15000),
			new BetterLevel("Greatest Asset V", 15000, 16000),
			new BetterLevel("Greatest Asset VI", 16000, 17500),
			new BetterLevel("Greatest Asset VII", 17500, 19000),
			new BetterLevel("Greatest Asset VIII", 19000, 21000),
			new BetterLevel("Greatest Asset IX", 21000, 23000),
			new BetterLevel("Greatest Asset X", 23000, 25000),
			new BetterLevel("The Company", 25000, 30000),
			new BetterLevel("The Company II", 30000, 35000),
			new BetterLevel("The Company III", 35000, 40000),
			new BetterLevel("The Company IV", 40000, 45000),
			new BetterLevel("The Company V", 45000, 50000),
			new BetterLevel("The Company VI", 50000, 60000),
			new BetterLevel("The Company VII", 60000, 70000),
			new BetterLevel("The Company VIII", 70000, 80000),
			new BetterLevel("The Company IX", 80000, 90000),
			new BetterLevel("The Company X", 90000, 100000),
			new BetterLevel("VIP Employee", 100000, 150000),
			new BetterLevel("VIP Employee II", 150000, 200000),
			new BetterLevel("VIP Employee III", 200000, 250000),
			new BetterLevel("VIP Employee IV", 250000, 300000),
			new BetterLevel("VIP Employee V", 300000, 400000),
			new BetterLevel("VIP Employee VI", 400000, 500000),
			new BetterLevel("VIP Employee VII", 500000, 600000),
			new BetterLevel("VIP Employee VIII", 600000, 700000),
			new BetterLevel("VIP Employee IX", 700000, 850000),
			new BetterLevel("VIP Employee X", 850000, 1000000),
			new BetterLevel("SUPER Employee", 1000000, 1500000),
			new BetterLevel("SUPER Employee II", 1500000, 2000000),
			new BetterLevel("SUPER Employee III", 2000000, 3000000),
			new BetterLevel("SUPER Employee IV", 3000000, 6000000),
			new BetterLevel("SUPER Employee V", 6000000, 10000000),
			new BetterLevel("SUPER Employee VI", 10000000, 20000000),
			new BetterLevel("SUPER Employee VII", 20000000, 50000000),
			new BetterLevel("SUPER Employee VIII", 50000000, 100000000),
			new BetterLevel("SUPER Employee IX", 100000000, 300000000),
			new BetterLevel("SUPER Employee X", 300000000, 600000000),
			new BetterLevel("MOST VALUABLE ASSET", 600000000, maxBetterXp + 1)
		};

		public static int GetPlayerBetterLevelIndex(int bxp)
		{
			for (int i = 0; i < betterLevels.Length; i++)
			{
				if (bxp < betterLevels[i].xpEnd)
				{
					return i;
				}
			}
			return betterLevels.Length - 1;
		}

		public static BetterLevel GetPlayerBetterLevel(int bxp)
		{
			int playerBetterLevelIndex = GetPlayerBetterLevelIndex(bxp);
			return betterLevels[playerBetterLevelIndex];
		}

		public static float GetRankProgress(int bxp)
		{
			BetterLevel playerBetterLevel = GetPlayerBetterLevel(bxp);
			float num = bxp - playerBetterLevel.xp;
			float num2 = playerBetterLevel.xpEnd - playerBetterLevel.xp;
			return num / num2;
		}

		public static void SetBetterXP(int betterXP)
		{
			betterXp = Mathf.Clamp(betterXP, 0, maxBetterXp);
			level = GetPlayerBetterLevelIndex(betterXp);
			if ((Object)(object)GameNetworkManager.Instance == (Object)null || (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null || (Object)(object)HUDManager.Instance == (Object)null)
			{
				return;
			}
			VanillaRank vanillaRank = VanillaRank.Intern;
			foreach (KeyValuePair<int, VanillaRank> item in betterExpToVanillaRank)
			{
				if (betterXp >= item.Key)
				{
					vanillaRank = item.Value;
					break;
				}
			}
			HUDManager.Instance.SyncPlayerLevelServerRpc((int)GameNetworkManager.Instance.localPlayerController.playerClientId, (int)vanillaRank, true);
		}
	}
}