Decompiled source of TeamWars v0.8.79

TeamWars.dll

Decompiled 13 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("TeamWars")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.8.79.0")]
[assembly: AssemblyInformationalVersion("0.8.79+66899d9183ba9330d8b6c499abf2269595378e8c")]
[assembly: AssemblyProduct("TeamWars")]
[assembly: AssemblyTitle("TeamWars")]
[assembly: AssemblyVersion("0.8.79.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 TeamWars
{
	internal static class ConfigSettings
	{
		public static ConfigEntry<float> GoalStartPercent;

		public static ConfigEntry<float> MinTimeBaseMinutes;

		public static ConfigEntry<float> MinTimePerModuleMinutes;

		public static ConfigEntry<float> CloseGraceMinutes;

		public static ConfigEntry<float> ValuableMultiplier;

		public static ConfigEntry<bool> VerboseLogs;

		public static ConfigEntry<bool> RequireCarts;

		public static ConfigEntry<float> CartRadius;

		public static ConfigEntry<bool> BlockRivalTouch;

		public static ConfigEntry<bool> AllowGrabHeldByRival;

		public static ConfigEntry<int> ReviveCostFlat;

		public static ConfigEntry<float> ReviveCostPercent;

		public static ConfigEntry<KeyCode> ReviveKey;

		public static void Bind(ConfigFile config)
		{
			GoalStartPercent = config.Bind<float>("Economy", "GoalStartPercent", 28f, "Starting goal for each team, as percent (0-100) of the level's total value.");
			MinTimeBaseMinutes = config.Bind<float>("Round", "MinTimeBaseMinutes", 10f, "Base minimum round time in minutes.");
			MinTimePerModuleMinutes = config.Bind<float>("Round", "MinTimePerModuleMinutes", 3f, "Extra minimum minutes per level module.");
			CloseGraceMinutes = config.Bind<float>("Round", "CloseGraceMinutes", 5f, "Extra minutes after the minimum time before players outside the truck stop blocking the round close.");
			ValuableMultiplier = config.Bind<float>("Spawning", "ValuableMultiplier", 2f, "How many times more valuables spawn per level (2 = double, one share per team). Only the host's value matters; it applies at level load.");
			VerboseLogs = config.Bind<bool>("Debug", "VerboseLogs", false, "Detailed per-tick logs (haul ticks, tally/roster syncs, blocked damage). Keep off: logging costs performance.");
			RequireCarts = config.Bind<bool>("Extraction", "RequireCarts", true, "Each extraction check needs both teams' main carts inside it to start; without them the button does nothing.");
			CartRadius = config.Bind<float>("Extraction", "CartRadius", 12f, "How close (meters) a main cart must be to the check to count as inside it.");
			BlockRivalTouch = config.Bind<bool>("Protection", "BlockRivalTouch", true, "Whether a team is blocked from grabbing or breaking what the other team owns (carts, claimed items, shop placements).");
			AllowGrabHeldByRival = config.Bind<bool>("Protection", "AllowGrabHeldByRival", false, "Whether a player may grab an object someone from the other team is holding (contested grabs, steals from hands). Off forbids grabbing anything a rival holds, on top of the rival-touch block.");
			ReviveCostFlat = config.Bind<int>("Revive", "CostFlat", 5000, "Flat revive price in dollars, charged to the dead player's team purse. Ignored while CostPercent is over 0.");
			ReviveCostPercent = config.Bind<float>("Revive", "CostPercent", 5f, "Revive price as percent (0-100) of the round-start level total. Over 0 replaces the flat price.");
			ReviveKey = config.Bind<KeyCode>("Revive", "Key", (KeyCode)290, "Key a living player presses to buy back one dead teammate (the vanilla head revive, paid from the team purse).");
		}
	}
	internal static class GameInternals
	{
		private static FieldRef<RunManager, bool> runLevelIsShopField = AccessTools.FieldRefAccess<RunManager, bool>("levelIsShop");

		private static FieldRef<PlayerAvatar, string> playerNameField = AccessTools.FieldRefAccess<PlayerAvatar, string>("playerName");

		private static FieldRef<ValuableObject, float> dollarValueCurrentField = AccessTools.FieldRefAccess<ValuableObject, float>("dollarValueCurrent");

		private static FieldRef<ValuableObject, float> dollarValueOriginalField = AccessTools.FieldRefAccess<ValuableObject, float>("dollarValueOriginal");

		private static FieldRef<PhysGrabObject, List<PhysGrabber>> grabbingListField = AccessTools.FieldRefAccess<PhysGrabObject, List<PhysGrabber>>("playerGrabbing");

		private static FieldRef<PhysGrabObject, PlayerAvatar> lastGrabbingField = AccessTools.FieldRefAccess<PhysGrabObject, PlayerAvatar>("lastPlayerGrabbing");

		private static FieldRef<PhysGrabber, PlayerAvatar> grabberAvatarField = AccessTools.FieldRefAccess<PhysGrabber, PlayerAvatar>("playerAvatar");

		private static FieldRef<PhysGrabber, PhysGrabObject> lookingAtObjectField = AccessTools.FieldRefAccess<PhysGrabber, PhysGrabObject>("currentlyLookingAtPhysGrabObject");

		private static FieldRef<PhysGrabber, ItemAttributes> lookingAtItemField = AccessTools.FieldRefAccess<PhysGrabber, ItemAttributes>("currentlyLookingAtItemAttributes");

		private static FieldRef<RoomVolumeCheck, bool> inTruckField = AccessTools.FieldRefAccess<RoomVolumeCheck, bool>("inTruck");

		private static FieldRef<PlayerAvatar, bool> playerDisabledField = AccessTools.FieldRefAccess<PlayerAvatar, bool>("isDisabled");

		private static FieldRef<PlayerAvatar, PlayerDeathHead> deathHeadField = AccessTools.FieldRefAccess<PlayerAvatar, PlayerDeathHead>("playerDeathHead");

		private static FieldRef<LevelGenerator, int> moduleAmountField = AccessTools.FieldRefAccess<LevelGenerator, int>("ModuleAmount");

		private static FieldRef<StatsManager, SortedDictionary<string, Dictionary<string, int>>> dictionariesField = AccessTools.FieldRefAccess<StatsManager, SortedDictionary<string, Dictionary<string, int>>>("dictionaryOfDictionaries");

		private static FieldRef<RoomVolumeCheck, bool> inExtractionField = AccessTools.FieldRefAccess<RoomVolumeCheck, bool>("inExtractionPoint");

		private static FieldRef<ValuableObject, RoomVolumeCheck> valuableRoomCheckField = AccessTools.FieldRefAccess<ValuableObject, RoomVolumeCheck>("roomVolumeCheck");

		private static FieldRef<RoomVolumeCheck, List<RoomVolume>> currentRoomsField = AccessTools.FieldRefAccess<RoomVolumeCheck, List<RoomVolume>>("CurrentRooms");

		private static FieldRef<RoomVolume, bool> extractionRoomField = AccessTools.FieldRefAccess<RoomVolume, bool>("Extraction");

		private static FieldRef<MenuPlayerListed, PlayerAvatar> listedAvatarField = AccessTools.FieldRefAccess<MenuPlayerListed, PlayerAvatar>("playerAvatar");

		private static FieldInfo escMenuPageField;

		private static FieldInfo pageActiveField;

		private const BindingFlags AnyField = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static FieldRef<ShopManager, List<ItemAttributes>> shoppingListField = AccessTools.FieldRefAccess<ShopManager, List<ItemAttributes>>("shoppingList");

		private static FieldRef<ItemAttributes, RoomVolumeCheck> itemRoomCheckField = AccessTools.FieldRefAccess<ItemAttributes, RoomVolumeCheck>("roomVolumeCheck");

		private static FieldRef<ItemAttributes, string> itemNameField = AccessTools.FieldRefAccess<ItemAttributes, string>("itemName");

		private static FieldRef<ItemAttributes, int> itemValueField = AccessTools.FieldRefAccess<ItemAttributes, int>("value");

		private static FieldRef<ExtractionPoint, int> haulGoalField = AccessTools.FieldRefAccess<ExtractionPoint, int>("haulGoal");

		private static MethodInfo haulGoalSetMethod;

		private static MethodInfo currentCartMethod;

		private static MethodInfo rerollCostMethod;

		private static FieldInfo standStateStartField;

		private static FieldRef<RoundDirector, int> extractionSurplusField;

		private static FieldRef<PhysGrabObject, Vector3> spawnTorqueField;

		private static FieldRef<PhysGrabCart, List<PhysGrabObject>> cartItemsField;

		private static FieldRef<ValuableObject, int> dollarValueOverrideField;

		private static FieldInfo surplusLightActiveField;

		private static FieldInfo surplusLightIntensityField;

		private static FieldInfo surplusLightRangeField;

		private static FieldRef<ExtractionPoint, int> haulCurrentField = AccessTools.FieldRefAccess<ExtractionPoint, int>("haulCurrent");

		private static FieldRef<RoundDirector, int> extractionPointsField = AccessTools.FieldRefAccess<RoundDirector, int>("extractionPoints");

		private static FieldRef<RoundDirector, int> extractionPointsCompletedField = AccessTools.FieldRefAccess<RoundDirector, int>("extractionPointsCompleted");

		private static FieldInfo screenGrabColliderField;

		private static FieldInfo itemPrefabField;

		private static FieldInfo extractionStateField;

		private static MethodInfo extractionStateSetMethod;

		public static SortedDictionary<string, Dictionary<string, int>> SaveDictionaries(StatsManager stats)
		{
			if (!((Object)(object)stats == (Object)null))
			{
				return dictionariesField.Invoke(stats);
			}
			return null;
		}

		public static bool IsInTruck(RoomVolumeCheck check)
		{
			if ((Object)(object)check != (Object)null)
			{
				return inTruckField.Invoke(check);
			}
			return false;
		}

		public static PlayerAvatar ListedAvatar(MenuPlayerListed row)
		{
			if (!((Object)(object)row == (Object)null))
			{
				return listedAvatarField.Invoke(row);
			}
			return null;
		}

		public static bool EscMenuOpen()
		{
			MenuPageEsc instance = MenuPageEsc.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			if (escMenuPageField == null)
			{
				escMenuPageField = typeof(MenuPageEsc).GetField("menuPage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
			object? obj = escMenuPageField?.GetValue(instance);
			MenuPage val = (MenuPage)((obj is MenuPage) ? obj : null);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			if (pageActiveField == null)
			{
				pageActiveField = typeof(MenuPage).GetField("pageActive", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
			if (pageActiveField != null)
			{
				object value = pageActiveField.GetValue(val);
				if (value is bool)
				{
					return (bool)value;
				}
			}
			return ((Component)val).gameObject.activeSelf;
		}

		public static bool IsInExtraction(ValuableObject valuable)
		{
			if ((Object)(object)valuable == (Object)null)
			{
				return false;
			}
			RoomVolumeCheck val = valuableRoomCheckField.Invoke(valuable);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			List<RoomVolume> list = currentRoomsField.Invoke(val);
			if (list == null)
			{
				return false;
			}
			foreach (RoomVolume item in list)
			{
				if ((Object)(object)item != (Object)null && extractionRoomField.Invoke(item))
				{
					return true;
				}
			}
			return false;
		}

		public static bool IsInExtractionPoint(RoomVolumeCheck check)
		{
			if ((Object)(object)check != (Object)null)
			{
				return inExtractionField.Invoke(check);
			}
			return false;
		}

		public static bool IsPlayerDisabled(PlayerAvatar avatar)
		{
			if ((Object)(object)avatar != (Object)null)
			{
				return playerDisabledField.Invoke(avatar);
			}
			return false;
		}

		public static PlayerDeathHead DeathHead(PlayerAvatar avatar)
		{
			if ((Object)(object)avatar == (Object)null)
			{
				return null;
			}
			try
			{
				return deathHeadField.Invoke(avatar);
			}
			catch (Exception)
			{
				return null;
			}
		}

		public static int ModuleCount()
		{
			if (!((Object)(object)LevelGenerator.Instance == (Object)null))
			{
				return moduleAmountField.Invoke(LevelGenerator.Instance);
			}
			return 0;
		}

		public static List<ItemAttributes> ShoppingList(ShopManager shop)
		{
			if (!((Object)(object)shop == (Object)null))
			{
				return shoppingListField.Invoke(shop);
			}
			return null;
		}

		public static RoomVolumeCheck RoomCheck(ItemAttributes item)
		{
			if (!((Object)(object)item == (Object)null))
			{
				return itemRoomCheckField.Invoke(item);
			}
			return null;
		}

		public static string ItemName(ItemAttributes item)
		{
			if (!((Object)(object)item == (Object)null))
			{
				return itemNameField.Invoke(item);
			}
			return null;
		}

		public static int ItemValue(ItemAttributes item)
		{
			if (!((Object)(object)item == (Object)null))
			{
				return itemValueField.Invoke(item);
			}
			return 0;
		}

		public static int RerollCost(UpgradeStand stand)
		{
			if ((Object)(object)stand == (Object)null)
			{
				return 0;
			}
			if (rerollCostMethod == null)
			{
				rerollCostMethod = typeof(UpgradeStand).GetMethod("get_RerollCost", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
			if (rerollCostMethod != null)
			{
				object obj = rerollCostMethod.Invoke(stand, null);
				if (obj is int)
				{
					return (int)obj;
				}
			}
			return 0;
		}

		public static int ExtractionSurplus()
		{
			if ((Object)(object)RoundDirector.instance == (Object)null)
			{
				return 0;
			}
			if (extractionSurplusField == null)
			{
				extractionSurplusField = AccessTools.FieldRefAccess<RoundDirector, int>("extractionPointSurplus");
			}
			return extractionSurplusField.Invoke(RoundDirector.instance);
		}

		public static void ClearExtractionSurplus()
		{
			if (!((Object)(object)RoundDirector.instance == (Object)null))
			{
				if (extractionSurplusField == null)
				{
					extractionSurplusField = AccessTools.FieldRefAccess<RoundDirector, int>("extractionPointSurplus");
				}
				extractionSurplusField.Invoke(RoundDirector.instance) = 0;
			}
		}

		public static void SetSpawnTorque(PhysGrabObject grabObject, Vector3 torque)
		{
			//IL_002b: 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)
			if (!((Object)(object)grabObject == (Object)null))
			{
				if (spawnTorqueField == null)
				{
					spawnTorqueField = AccessTools.FieldRefAccess<PhysGrabObject, Vector3>("spawnTorque");
				}
				spawnTorqueField.Invoke(grabObject) = torque;
			}
		}

		public static List<PhysGrabObject> CartItems(PhysGrabCart cart)
		{
			if ((Object)(object)cart == (Object)null)
			{
				return null;
			}
			if (cartItemsField == null)
			{
				cartItemsField = AccessTools.FieldRefAccess<PhysGrabCart, List<PhysGrabObject>>("itemsInCart");
			}
			return cartItemsField.Invoke(cart);
		}

		public static GameObject SurplusPrefab(int value)
		{
			AssetManager instance = AssetManager.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return null;
			}
			if (value > 10000)
			{
				return instance.surplusValuableBig;
			}
			if (value > 5000)
			{
				return instance.surplusValuableMedium;
			}
			return instance.surplusValuableSmall;
		}

		public static void SetValuableOverride(ValuableObject valuable, int value)
		{
			if (!((Object)(object)valuable == (Object)null))
			{
				if (dollarValueOverrideField == null)
				{
					dollarValueOverrideField = AccessTools.FieldRefAccess<ValuableObject, int>("dollarValueOverride");
				}
				dollarValueOverrideField.Invoke(valuable) = value;
			}
		}

		public static void SurplusLights(ExtractionPoint point)
		{
			if (!((Object)(object)point == (Object)null) && !((Object)(object)point.surplusLight == (Object)null))
			{
				if (surplusLightActiveField == null)
				{
					surplusLightActiveField = AccessTools.Field(typeof(ExtractionPoint), "surplusLightActive");
					surplusLightIntensityField = AccessTools.Field(typeof(ExtractionPoint), "surplusLightIntensity");
					surplusLightRangeField = AccessTools.Field(typeof(ExtractionPoint), "surplusLightRange");
				}
				if (surplusLightActiveField != null)
				{
					surplusLightActiveField.SetValue(point, true);
				}
				point.surplusLight.intensity = ((surplusLightIntensityField != null) ? ((float)surplusLightIntensityField.GetValue(point)) : 1f);
				if (surplusLightRangeField != null)
				{
					point.surplusLight.range = (float)surplusLightRangeField.GetValue(point);
				}
			}
		}

		public static int ButtonGrabberTeam(UpgradeStand stand)
		{
			if (!((Object)(object)stand == (Object)null))
			{
				return ButtonGrabberTeam(stand.buttonGrabObject);
			}
			return -1;
		}

		public static int ButtonGrabberTeam(StaticGrabObject button)
		{
			if ((Object)(object)button == (Object)null || button.playerGrabbing == null)
			{
				return -1;
			}
			int result = -1;
			foreach (PhysGrabber item in button.playerGrabbing)
			{
				if (!((Object)(object)item == (Object)null) && !((Object)(object)item.playerAvatar == (Object)null) && !((Object)(object)item.playerAvatar.photonView == (Object)null))
				{
					int team = TeamState.GetTeam(item.playerAvatar.photonView.OwnerActorNr);
					if (team != -1)
					{
						result = team;
					}
				}
			}
			return result;
		}

		public static bool RerollPressStarted(UpgradeStand stand)
		{
			if ((Object)(object)stand == (Object)null)
			{
				return false;
			}
			if (standStateStartField == null)
			{
				standStateStartField = typeof(UpgradeStand).GetField("stateStart", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
			bool flag = default(bool);
			int num;
			if (standStateStartField != null)
			{
				object value = standStateStartField.GetValue(stand);
				if (value is bool)
				{
					flag = (bool)value;
					num = 1;
				}
				else
				{
					num = 0;
				}
			}
			else
			{
				num = 0;
			}
			return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
		}

		public static PhysGrabCart CurrentCart(ValuableObject valuable)
		{
			if ((Object)(object)valuable == (Object)null)
			{
				return null;
			}
			if (currentCartMethod == null)
			{
				currentCartMethod = typeof(ValuableObject).GetMethod("GetCurrentCart", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
			object? obj = currentCartMethod?.Invoke(valuable, null);
			return (PhysGrabCart)((obj is PhysGrabCart) ? obj : null);
		}

		public static void SetCheckGoal(ExtractionPoint point, int goal)
		{
			if (!((Object)(object)point == (Object)null))
			{
				if (haulGoalSetMethod == null)
				{
					haulGoalSetMethod = typeof(ExtractionPoint).GetMethod("HaulGoalSet", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				haulGoalSetMethod?.Invoke(point, new object[1] { goal });
			}
		}

		public static int CheckGoal(ExtractionPoint point)
		{
			if (!((Object)(object)point == (Object)null))
			{
				return haulGoalField.Invoke(point);
			}
			return 0;
		}

		public static int CheckHaul(ExtractionPoint point)
		{
			if (!((Object)(object)point == (Object)null))
			{
				return haulCurrentField.Invoke(point);
			}
			return 0;
		}

		public static int CompletedCheckCount()
		{
			RoundDirector instance = RoundDirector.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				return extractionPointsCompletedField.Invoke(instance);
			}
			return 0;
		}

		public static bool CheckComplete()
		{
			RoundDirector instance = RoundDirector.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return false;
			}
			int num = extractionPointsField.Invoke(instance);
			if (num > 0 && extractionPointsCompletedField.Invoke(instance) >= num)
			{
				return true;
			}
			ExtractionPoint[] array = Object.FindObjectsOfType<ExtractionPoint>();
			foreach (ExtractionPoint point in array)
			{
				if (CheckGoal(point) > 0 && CheckHaul(point) >= CheckGoal(point))
				{
					return true;
				}
			}
			return false;
		}

		public static void SetCheckGoalLocal(ExtractionPoint point, int goal)
		{
			if ((Object)(object)point != (Object)null)
			{
				haulGoalField.Invoke(point) = goal;
			}
		}

		public static bool IsTruckScreen(GameObject grabbed)
		{
			if ((Object)(object)grabbed == (Object)null || (Object)(object)TruckScreenText.instance == (Object)null)
			{
				return false;
			}
			if (screenGrabColliderField == null)
			{
				screenGrabColliderField = typeof(TruckScreenText).GetField("staticGrabCollider", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
			object? obj = screenGrabColliderField?.GetValue(TruckScreenText.instance);
			GameObject val = (GameObject)((obj is GameObject) ? obj : null);
			if ((Object)(object)val != (Object)null)
			{
				return (Object)(object)val == (Object)(object)grabbed;
			}
			return false;
		}

		public static int DelivererTeam(PhysGrabObject grabObject)
		{
			if ((Object)(object)grabObject == (Object)null)
			{
				return -1;
			}
			PlayerAvatar val = Deliverer(grabObject);
			if ((Object)(object)val == (Object)null || (Object)(object)val.photonView == (Object)null)
			{
				return -1;
			}
			return TeamState.GetTeam(val.photonView.OwnerActorNr);
		}

		public static PhysGrabObject LookingAt(PhysGrabber grabber)
		{
			if (!((Object)(object)grabber == (Object)null))
			{
				return lookingAtObjectField.Invoke(grabber);
			}
			return null;
		}

		public static void ClearLookingAt(PhysGrabber grabber)
		{
			if (!((Object)(object)grabber == (Object)null))
			{
				lookingAtObjectField.Invoke(grabber) = null;
				lookingAtItemField.Invoke(grabber) = null;
			}
		}

		private static object PrefabRefOf(Item item)
		{
			if ((Object)(object)item == (Object)null)
			{
				return null;
			}
			if (itemPrefabField == null)
			{
				itemPrefabField = typeof(Item).GetField("prefab", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
			return itemPrefabField?.GetValue(item);
		}

		public static string ItemResourcePath(Item item)
		{
			return PrefabMember(item, "ResourcePath") as string;
		}

		public static GameObject ItemPrefab(Item item)
		{
			object obj = PrefabMember(item, "Prefab");
			return (GameObject)((obj is GameObject) ? obj : null);
		}

		private static object PrefabMember(Item item, string member)
		{
			object obj = PrefabRefOf(item);
			return obj?.GetType().GetProperty(member, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj);
		}

		public static List<PlayerAvatar> CurrentHolders(PhysGrabObject grabObject)
		{
			List<PlayerAvatar> list = new List<PlayerAvatar>();
			if ((Object)(object)grabObject == (Object)null)
			{
				return list;
			}
			List<PhysGrabber> list2 = grabbingListField.Invoke(grabObject);
			if (list2 == null)
			{
				return list;
			}
			foreach (PhysGrabber item in list2)
			{
				if (!((Object)(object)item == (Object)null))
				{
					PlayerAvatar val = grabberAvatarField.Invoke(item);
					if ((Object)(object)val != (Object)null)
					{
						list.Add(val);
					}
				}
			}
			return list;
		}

		public static PlayerAvatar Deliverer(PhysGrabObject grabObject)
		{
			if ((Object)(object)grabObject == (Object)null)
			{
				return null;
			}
			List<PhysGrabber> list = grabbingListField.Invoke(grabObject);
			if (list != null && list.Count > 0)
			{
				PhysGrabber val = list[list.Count - 1];
				if ((Object)(object)val != (Object)null)
				{
					return grabberAvatarField.Invoke(val);
				}
			}
			return lastGrabbingField.Invoke(grabObject);
		}

		public static float ValuableCurrentValue(ValuableObject valuable)
		{
			return dollarValueCurrentField.Invoke(valuable);
		}

		public static float ValuableOriginalValue(ValuableObject valuable)
		{
			return dollarValueOriginalField.Invoke(valuable);
		}

		public static int RunCurrency()
		{
			return SemiFunc.StatGetRunCurrency();
		}

		public static void SetRunCurrency(int units)
		{
			SemiFunc.StatSetRunCurrency(units);
		}

		public static bool LevelIsShop(RunManager runManager)
		{
			if ((Object)(object)runManager == (Object)null)
			{
				return false;
			}
			return runLevelIsShopField.Invoke(runManager);
		}

		public static string PlayerName(PlayerAvatar avatar)
		{
			if ((Object)(object)avatar == (Object)null)
			{
				return "?";
			}
			return playerNameField.Invoke(avatar);
		}

		public static ExtractionPoint ExtractionOf(Component component)
		{
			if (!((Object)(object)component != (Object)null))
			{
				return null;
			}
			return component.GetComponentInParent<ExtractionPoint>();
		}

		public static string ExtractionStateName(ExtractionPoint point)
		{
			if ((Object)(object)point == (Object)null)
			{
				return null;
			}
			if (extractionStateField == null)
			{
				extractionStateField = typeof(ExtractionPoint).GetField("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			}
			try
			{
				return extractionStateField?.GetValue(point)?.ToString();
			}
			catch (Exception)
			{
				return null;
			}
		}

		public static bool DriveExtraction(ExtractionPoint point, string target)
		{
			if ((Object)(object)point == (Object)null || string.IsNullOrEmpty(target))
			{
				return false;
			}
			try
			{
				if (extractionStateField == null)
				{
					extractionStateField = typeof(ExtractionPoint).GetField("currentState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				if (extractionStateSetMethod == null)
				{
					extractionStateSetMethod = typeof(ExtractionPoint).GetMethod("StateSet", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				}
				Type type = extractionStateField?.FieldType;
				if (type == null || extractionStateSetMethod == null)
				{
					return false;
				}
				object obj = Enum.Parse(type, target);
				extractionStateSetMethod.Invoke(point, new object[1] { obj });
				return true;
			}
			catch (Exception ex)
			{
				Plugin.Log("Extraction drive failed: " + ex.Message);
				return false;
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabObjectImpactDetector), "InCartRPC")]
	internal static class CartClaimPatch
	{
		private static void Postfix(PhysGrabObjectImpactDetector __instance, bool inCartState)
		{
			if (inCartState)
			{
				TeamHaul.MarkIntoTeamCart(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(ExtractionPoint), "StateSet")]
	internal static class CheckCartGatePatch
	{
		private static string lastRefusal;

		private static readonly Dictionary<ExtractionPoint, State> pendingRetries = new Dictionary<ExtractionPoint, State>();

		public static void ClearPending()
		{
			pendingRetries.Clear();
		}

		private static bool Prefix(ExtractionPoint __instance, State newState)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Invalid comparison between Unknown and I4
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			if ((int)newState != 4 && (int)newState != 6 && (int)newState != 7)
			{
				return true;
			}
			if ((Object)(object)RunManager.instance == (Object)null || !SemiFunc.RunIsLevel())
			{
				return true;
			}
			if (ConfigSettings.RequireCarts != null && !ConfigSettings.RequireCarts.Value)
			{
				return true;
			}
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			List<int> list = TeamCarts.CartsMissingAt(__instance);
			list.RemoveAll(TeamRound.TeamWiped);
			if (list.Count == 0)
			{
				lastRefusal = null;
				if (pendingRetries.TryGetValue(__instance, out var value) && value == newState)
				{
					pendingRetries.Remove(__instance);
				}
				Plugin.LogVerbose($"Cart gate: {((Object)__instance).name} -> {newState} allowed (both carts in)");
				return true;
			}
			string arg = string.Join(" y ", list.ConvertAll((int team) => (team != 0) ? "Azul" : "Rojo").ToArray());
			string text = $"{((Object)__instance).name} -> {newState} refused: {arg} cart(s) missing from the check";
			pendingRetries[__instance] = newState;
			if (text != lastRefusal)
			{
				lastRefusal = text;
				Plugin.Log("Extraction held: " + text);
			}
			return false;
		}

		public unsafe static void RetryHeldExtractions()
		{
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Invalid comparison between Unknown and I4
			//IL_0163: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Invalid comparison between Unknown and I4
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Invalid comparison between Unknown and I4
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Invalid comparison between Unknown and I4
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			if (!TeamNetworking.IsMasterSession || (Object)(object)RunManager.instance == (Object)null || !SemiFunc.RunIsLevel())
			{
				return;
			}
			if (ConfigSettings.RequireCarts != null && !ConfigSettings.RequireCarts.Value)
			{
				pendingRetries.Clear();
				return;
			}
			ExtractionPoint[] array = Object.FindObjectsOfType<ExtractionPoint>();
			foreach (ExtractionPoint val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				string text = GameInternals.ExtractionStateName(val);
				if (!(text != "Active") && GameInternals.CheckHaul(val) >= GameInternals.CheckGoal(val))
				{
					List<int> list = TeamCarts.CartsMissingAt(val);
					list.RemoveAll(TeamRound.TeamWiped);
					if (list.Count <= 0)
					{
						Plugin.Log("Extraction kick: " + ((Object)val).name + " full in " + text + " with both carts, driving Warning");
						GameInternals.DriveExtraction(val, "Warning");
					}
				}
			}
			foreach (KeyValuePair<ExtractionPoint, State> item in new List<KeyValuePair<ExtractionPoint, State>>(pendingRetries))
			{
				ExtractionPoint key = item.Key;
				State value = item.Value;
				if ((Object)(object)key == (Object)null)
				{
					pendingRetries.Remove(key);
					continue;
				}
				string text2 = GameInternals.ExtractionStateName(key);
				if (((int)value != 4 || !(text2 == "Active")) && (((int)value == 4 && text2 == "Surplus") || ((int)value == 6 && text2 == "Warning") || ((int)value == 7 && text2 == "Extracting")))
				{
					List<int> list2 = TeamCarts.CartsMissingAt(key);
					list2.RemoveAll(TeamRound.TeamWiped);
					if (list2.Count <= 0)
					{
						Plugin.Log($"Extraction retry: {((Object)key).name} {text2} -> {value} (carts back, completing vanilla's own edge)");
						GameInternals.DriveExtraction(key, ((object)(*(State*)(&value))/*cast due to .constrained prefix*/).ToString());
					}
				}
			}
		}
	}
	[HarmonyPatch(typeof(ExtractionPoint), "HaulGoalSet")]
	internal static class CheckGoalSetPatch
	{
		private static void Prefix(ref int value)
		{
			int num = TeamRound.CheckGoal();
			if (num > 0)
			{
				value = num;
			}
		}
	}
	[HarmonyPatch(typeof(ExtractionPoint), "HaulInternalStatsUpdate")]
	internal static class CheckGoalKeepPatch
	{
		private static void Postfix(ExtractionPoint __instance)
		{
			int num = TeamRound.CheckGoal();
			if (num > 0 && GameInternals.CheckGoal(__instance) != num)
			{
				GameInternals.SetCheckGoalLocal(__instance, num);
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabber), "StartGrabbingPhysObject")]
	internal static class GrabOwnershipPatch
	{
		private static bool Prefix(PhysGrabber __instance, PhysGrabObject _physGrabObject)
		{
			return TeamOwnership.AllowsGrab(_physGrabObject, __instance);
		}
	}
	[HarmonyPatch(typeof(PhysGrabber), "RayCheck")]
	internal static class GrabAimPatch
	{
		private static void Postfix(PhysGrabber __instance)
		{
			PhysGrabObject val = GameInternals.LookingAt(__instance);
			if (!((Object)(object)val == (Object)null) && !TeamOwnership.AllowsGrab(val, __instance))
			{
				GameInternals.ClearLookingAt(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(TruckScreenText), "GotoNextLevel")]
	internal static class LevelClosePatch
	{
		private static bool Prefix()
		{
			if (TeamRound.CanClose(out var reason))
			{
				return true;
			}
			Plugin.Log("Level close not allowed yet: " + reason);
			return false;
		}
	}
	[HarmonyPatch(typeof(StatsManager), "RunStartStats")]
	internal static class RunStartCartPatch
	{
		private const string FreeCartItem = "Item Cart Medium";

		private static void Postfix(StatsManager __instance)
		{
			if (Drop(__instance.itemsPurchased) | Drop(__instance.itemsPurchasedTotal))
			{
				Plugin.Log("Removed the free starter cart (each team gets its own)");
			}
		}

		private static bool Drop(Dictionary<string, int> purchased)
		{
			return purchased?.Remove("Item Cart Medium") ?? false;
		}
	}
	[HarmonyPatch(typeof(StatsManager), "Start")]
	internal static class SaveRegisterPatch
	{
		private static void Postfix()
		{
			TeamSave.Register();
		}
	}
	[HarmonyPatch(typeof(StatsManager), "SaveGame")]
	internal static class SavePushPatch
	{
		private static void Prefix()
		{
			if (TeamState.RoundActive)
			{
				TeamRound.Close();
			}
			TeamSave.Push();
		}
	}
	[HarmonyPatch(typeof(StatsManager), "LoadGame")]
	internal static class LoadClearPatch
	{
		private static void Prefix()
		{
			TeamSave.ClearBeforeLoad();
		}
	}
	[HarmonyPatch(typeof(StatsManager), "LoadGame")]
	internal static class LoadRestorePatch
	{
		private static void Postfix()
		{
			TeamSave.Restore();
		}
	}
	[HarmonyPatch(typeof(StatsManager), "RunStartStats")]
	internal static class RunStartAccountsPatch
	{
		private static void Postfix()
		{
			TeamSave.ClearRun();
		}
	}
	[HarmonyPatch(typeof(StatsManager), "ResetAllStats")]
	internal static class ResetAllAccountsPatch
	{
		private static void Postfix()
		{
			TeamSave.ClearRun();
		}
	}
	[HarmonyPatch(typeof(StaticGrabObject), "GrabStarted")]
	internal static class ScreenFinishPatch
	{
		private static void Prefix(StaticGrabObject __instance)
		{
			if (!((Object)(object)RunManager.instance == (Object)null) && SemiFunc.RunIsLevel() && GameInternals.IsTruckScreen(((Component)__instance).gameObject) && TeamRound.Winner() != -1)
			{
				if (!TeamRound.CanClose(out var reason))
				{
					Plugin.Log("Round finish refused at the truck screen: " + reason);
					return;
				}
				Plugin.Log("Round finish requested at the truck screen");
				TeamNetworking.Instance?.RequestRoundClose();
			}
		}
	}
	[HarmonyPatch(typeof(ShopManager), "ShopCheck")]
	internal static class ShopCheckPatch
	{
		private static void Postfix(ShopManager __instance)
		{
			ShopPurchases.TagItemsInCheck(__instance);
		}
	}
	[HarmonyPatch(typeof(ExtractionPoint), "DestroyTheFirstPhysObjectsInShopList")]
	internal static class ShopTubePurchasePatch
	{
		private static string lastRefusal;

		private static bool Prefix()
		{
			if (!SemiFunc.RunIsShop())
			{
				return true;
			}
			if (!ShopPurchases.AllowTubePurchase(out var reason))
			{
				if (reason != lastRefusal)
				{
					lastRefusal = reason;
					Plugin.Log("Shop purchase refused: " + reason);
				}
				return false;
			}
			lastRefusal = null;
			return true;
		}

		private static void Postfix()
		{
			ShopPurchases.RecordTubePurchase();
		}
	}
	[HarmonyPatch(typeof(ExtractionPoint), "DestroyAllPhysObjectsInShoppingList")]
	internal static class ShopBulkPurchasePatch
	{
		private static bool Prefix()
		{
			if (!SemiFunc.RunIsShop())
			{
				return true;
			}
			ShopPurchases.AllowBulkPurchase();
			return true;
		}

		private static void Postfix()
		{
			if (SemiFunc.RunIsShop())
			{
				ShopPurchases.RecordBulkPurchase();
			}
		}
	}
	[HarmonyPatch(typeof(ExtractionPoint), "SpawnTaxReturn")]
	internal static class SurplusSplitPatch
	{
		private static bool Prefix(ExtractionPoint __instance)
		{
			return TeamSurplus.Spawn(__instance);
		}
	}
	[HarmonyPatch(typeof(UpgradeStand), "StatePressSucceed")]
	internal static class UpgradeStandPatch
	{
		private static void Postfix(UpgradeStand __instance)
		{
			if (GameInternals.RerollPressStarted(__instance))
			{
				ShopPurchases.RecordReroll(__instance);
			}
		}
	}
	[HarmonyPatch(typeof(ValuableObject), "AddToDollarHaulList")]
	internal static class ValuableHaulPatch
	{
		private static void Postfix(ValuableObject __instance)
		{
			TeamController.Instance?.PinDeliverer(__instance);
		}
	}
	[HarmonyPatch(typeof(PhysGrabObjectImpactDetector), "Break")]
	internal static class ValuableProtectionPatch
	{
		private static bool Prefix(PhysGrabObjectImpactDetector __instance)
		{
			return TeamOwnership.AllowsDamage(__instance);
		}
	}
	[HarmonyPatch(typeof(ValuableDirector), "SetupHost")]
	internal static class ValuableSpawnPatch
	{
		private const BindingFlags AnyField = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		private static readonly string[] CurveFields = new string[16]
		{
			"totalMaxValueCurve1", "totalMaxValueCurve2", "tinyMaxAmountCurve1", "tinyMaxAmountCurve2", "smallMaxAmountCurve1", "smallMaxAmountCurve2", "mediumMaxAmountCurve1", "mediumMaxAmountCurve2", "bigMaxAmountCurve1", "bigMaxAmountCurve2",
			"wideMaxAmountCurve1", "wideMaxAmountCurve2", "tallMaxAmountCurve1", "tallMaxAmountCurve2", "veryTallMaxAmountCurve1", "veryTallMaxAmountCurve2"
		};

		private static readonly Dictionary<string, FieldInfo> fields = new Dictionary<string, FieldInfo>();

		private static int snapshotForId;

		private static Dictionary<string, Keyframe[]> snapshotCurves;

		private static int snapshotTotalMaxAmount;

		private static void Prefix(ValuableDirector __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && TeamNetworking.IsMasterSession)
			{
				float num = ((ConfigSettings.ValuableMultiplier != null) ? ConfigSettings.ValuableMultiplier.Value : 2f);
				if (num < 1f)
				{
					num = 1f;
				}
				int instanceID = ((Object)__instance).GetInstanceID();
				if (snapshotCurves == null || snapshotForId != instanceID)
				{
					TakeSnapshot(__instance, instanceID);
				}
				else
				{
					RestoreSnapshot(__instance);
				}
				ApplyMultiplier(__instance, num);
				Plugin.Log($"Valuable spawn x{num}: totalMaxAmount {snapshotTotalMaxAmount} -> {CurrentTotalMaxAmount(__instance)}");
			}
		}

		private static FieldInfo Field(string name)
		{
			if (!fields.TryGetValue(name, out var value))
			{
				value = typeof(ValuableDirector).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
				fields[name] = value;
			}
			return value;
		}

		private static void TakeSnapshot(ValuableDirector director, int id)
		{
			snapshotForId = id;
			snapshotCurves = new Dictionary<string, Keyframe[]>();
			string[] curveFields = CurveFields;
			foreach (string text in curveFields)
			{
				object? obj = Field(text)?.GetValue(director);
				AnimationCurve val = (AnimationCurve)((obj is AnimationCurve) ? obj : null);
				snapshotCurves[text] = ((val != null) ? val.keys : null);
			}
			snapshotTotalMaxAmount = CurrentTotalMaxAmount(director);
		}

		private static void RestoreSnapshot(ValuableDirector director)
		{
			string[] curveFields = CurveFields;
			foreach (string text in curveFields)
			{
				if (snapshotCurves.TryGetValue(text, out var value) && value != null)
				{
					object? obj = Field(text)?.GetValue(director);
					AnimationCurve val = (AnimationCurve)((obj is AnimationCurve) ? obj : null);
					if (val != null)
					{
						val.keys = value;
					}
				}
			}
			Field("totalMaxAmount")?.SetValue(director, snapshotTotalMaxAmount);
		}

		private static void ApplyMultiplier(ValuableDirector director, float multiplier)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			string[] curveFields = CurveFields;
			foreach (string text in curveFields)
			{
				if (snapshotCurves.TryGetValue(text, out var value) && value != null)
				{
					Keyframe[] array = (Keyframe[])(object)new Keyframe[value.Length];
					for (int j = 0; j < value.Length; j++)
					{
						Keyframe val = value[j];
						((Keyframe)(ref val)).value = ((Keyframe)(ref val)).value * multiplier;
						((Keyframe)(ref val)).inTangent = ((Keyframe)(ref val)).inTangent * multiplier;
						((Keyframe)(ref val)).outTangent = ((Keyframe)(ref val)).outTangent * multiplier;
						array[j] = val;
					}
					object? obj = Field(text)?.GetValue(director);
					AnimationCurve val2 = (AnimationCurve)((obj is AnimationCurve) ? obj : null);
					if (val2 != null)
					{
						val2.keys = array;
						num++;
					}
				}
			}
			Field("totalMaxAmount")?.SetValue(director, (int)((float)snapshotTotalMaxAmount * multiplier));
			if (num != CurveFields.Length)
			{
				Plugin.Log($"Valuable spawn: only {num}/{CurveFields.Length} curves found; the value/size caps may not have doubled");
			}
		}

		private static int CurrentTotalMaxAmount(ValuableDirector director)
		{
			object obj = Field("totalMaxAmount")?.GetValue(director);
			if (obj is int)
			{
				return (int)obj;
			}
			return 0;
		}
	}
	[BepInPlugin("cacus.TeamWars", "TeamWars", "0.8.79")]
	[BepInProcess("REPO.exe")]
	public class Plugin : BaseUnityPlugin
	{
		private static ManualLogSource logSource;

		public static Plugin Instance { get; private set; }

		private void Awake()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//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_003f: Expected O, but got Unknown
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			ConfigSettings.Bind(((BaseUnityPlugin)this).Config);
			logSource = Logger.CreateLogSource("TeamWars");
			new Harmony("cacus.TeamWars").PatchAll();
			GameObject val = new GameObject("TeamWars");
			Object.DontDestroyOnLoad((Object)val);
			((Object)val).hideFlags = (HideFlags)61;
			val.AddComponent<TeamController>();
			val.AddComponent<TeamNetworking>();
			val.AddComponent<TeamHud>();
			Log("TeamWars v0.8.79 loaded");
		}

		public static void Log(string message)
		{
			logSource.LogInfo((object)message);
		}

		public static void LogVerbose(string message)
		{
			if (ConfigSettings.VerboseLogs != null && ConfigSettings.VerboseLogs.Value)
			{
				logSource.LogInfo((object)message);
			}
		}
	}
	internal static class PluginInfo
	{
		public const string PLUGIN_GUID = "cacus.TeamWars";

		public const string PLUGIN_NAME = "TeamWars";

		public const string PLUGIN_VERSION = "0.8.79";
	}
	internal static class ShopPurchases
	{
		private sealed class BulkItem
		{
			public readonly ItemAttributes Item;

			public readonly int Team;

			public readonly int Price;

			public readonly string Name;

			public BulkItem(ItemAttributes item, int team, int price, string name)
			{
				Item = item;
				Team = team;
				Price = price;
				Name = name;
			}
		}

		public const int DollarsPerMoneyUnit = 1000;

		private static ItemAttributes pendingItem;

		private static int pendingTeam = -1;

		private static int pendingPrice;

		private static string pendingName;

		private static readonly HashSet<int> shopPinned = new HashSet<int>();

		private static HashSet<int> lastInCheck = new HashSet<int>();

		private static float nextTag;

		private static List<BulkItem> pendingBulk;

		private static List<ItemAttributes> withheldBulk;

		public static void TagItemsInCheck(ShopManager shop)
		{
			if (!TeamNetworking.IsMasterSession || Time.time < nextTag)
			{
				return;
			}
			nextTag = Time.time + 0.5f;
			HashSet<int> hashSet = new HashSet<int>();
			foreach (ItemAttributes item in ItemsInCheck(shop))
			{
				int num = ViewIdOf(item);
				if (num != 0)
				{
					hashSet.Add(num);
					int num2 = HolderTeam(item);
					if (num2 != -1)
					{
						PinShop(item, num, num2);
					}
				}
			}
			ClearLeavers(hashSet);
			lastInCheck = hashSet;
		}

		public static void MirrorPot()
		{
			if (TeamNetworking.IsMasterSession && SemiFunc.RunIsShop())
			{
				int num = (TeamState.Purse(0) + TeamState.Purse(1)) / 1000;
				if (num < 0)
				{
					num = 0;
				}
				int num2 = GameInternals.RunCurrency();
				if (num2 < num)
				{
					GameInternals.SetRunCurrency(num);
					Plugin.Log($"Shop pot mirrored: {num2} -> {num} (team purses)");
				}
			}
		}

		private static void EnsurePot(int units, string what)
		{
			int num = GameInternals.RunCurrency();
			if (num < units)
			{
				GameInternals.SetRunCurrency(units);
				Plugin.Log($"Shop pot topped up: {num} -> {units} to cover {what}");
			}
		}

		public static void ResetAttribution()
		{
			shopPinned.Clear();
			lastInCheck = new HashSet<int>();
		}

		private static void ClearLeavers(HashSet<int> seen)
		{
			foreach (int item in lastInCheck)
			{
				if (!seen.Contains(item) && shopPinned.Remove(item))
				{
					TeamOwnership.RestoreShopTint(item);
					if (!((Object)(object)PhotonView.Find(item) == (Object)null))
					{
						TeamOwnership.Set(item, -1);
						TeamNetworking.Instance?.BroadcastOwnership(new int[2] { item, -1 }, 2);
						Plugin.Log("Shop check: an item left the check; attribution reset");
					}
				}
			}
		}

		private static int UnambiguousTeam()
		{
			int num = -1;
			foreach (int item in TeamState.AllActors())
			{
				int team = TeamState.GetTeam(item);
				if (team == -1)
				{
					return -1;
				}
				if (num == -1)
				{
					num = team;
				}
				else if (num != team)
				{
					return -1;
				}
			}
			return num;
		}

		public static void AllowBulkPurchase()
		{
			pendingBulk = new List<BulkItem>();
			withheldBulk = new List<ItemAttributes>();
			if (!TeamNetworking.IsMasterSession)
			{
				return;
			}
			List<ItemAttributes> list = GameInternals.ShoppingList(ShopManager.instance);
			if (list == null)
			{
				return;
			}
			ItemAttributes[] array = list.ToArray();
			foreach (ItemAttributes val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				int num = Placer(val);
				if (num == -1)
				{
					withheldBulk.Add(val);
					Plugin.Log("Shop bulk withheld: " + ((Object)val).name + " has no team attached yet (grab it again to attribute)");
					continue;
				}
				int num2 = GameInternals.ItemValue(val) * 1000;
				if (TeamState.Purse(num) >= num2)
				{
					pendingBulk.Add(new BulkItem(val, num, num2, GameInternals.ItemName(val)));
					continue;
				}
				withheldBulk.Add(val);
				Plugin.Log($"Shop bulk refused: {TeamLabel(num)} cannot pay {((Object)val).name} ({num2}); purse is {TeamState.Purse(num)} (left in the check)");
			}
			int num3 = 0;
			foreach (BulkItem item in pendingBulk)
			{
				num3 += item.Price / 1000;
			}
			EnsurePot(num3, "the authorized bulk purchase");
			foreach (ItemAttributes item2 in withheldBulk)
			{
				list.Remove(item2);
			}
		}

		public static void RecordBulkPurchase()
		{
			List<BulkItem> list = pendingBulk;
			List<ItemAttributes> list2 = withheldBulk;
			pendingBulk = null;
			withheldBulk = null;
			if (!TeamNetworking.IsMasterSession || list == null)
			{
				return;
			}
			List<ItemAttributes> list3 = GameInternals.ShoppingList(ShopManager.instance);
			if (list3 != null && list2 != null)
			{
				foreach (ItemAttributes item in list2)
				{
					if ((Object)(object)item != (Object)null && !list3.Contains(item))
					{
						list3.Add(item);
					}
				}
			}
			int num = 0;
			foreach (BulkItem item2 in list)
			{
				if ((Object)(object)item2.Item == (Object)null || list3 == null || !list3.Contains(item2.Item))
				{
					TeamState.Spent[item2.Team] += item2.Price;
					TeamState.AddPurchased(item2.Name, item2.Team, 1);
					Plugin.Log($"Shop purchase: {item2.Name} (${item2.Price}) -> {TeamLabel(item2.Team)}");
					num++;
				}
			}
			if (num > 0)
			{
				TeamNetworking.Instance?.BroadcastTally();
			}
		}

		public static bool AllowTubePurchase(out string reason)
		{
			reason = null;
			if (!TeamNetworking.IsMasterSession)
			{
				return true;
			}
			ItemAttributes val = FirstShoppingItem();
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			if ((Object)(object)((Component)val).GetComponentInParent<PhysGrabObject>() == (Object)null)
			{
				return true;
			}
			int num = Placer(val);
			if (num == -1)
			{
				reason = ((Object)val).name + " has no team attached yet (grab it again to attribute)";
				return false;
			}
			int num2 = GameInternals.ItemValue(val) * 1000;
			if (TeamState.Purse(num) >= num2)
			{
				pendingItem = val;
				pendingTeam = num;
				pendingPrice = num2;
				pendingName = GameInternals.ItemName(val);
				EnsurePot(GameInternals.ItemValue(val), ((Object)val).name);
				return true;
			}
			reason = $"{TeamLabel(num)} cannot pay {((Object)val).name} ({num2}); purse is {TeamState.Purse(num)}";
			return false;
		}

		public static void RecordTubePurchase()
		{
			ItemAttributes val = pendingItem;
			int num = pendingTeam;
			int num2 = pendingPrice;
			string text = pendingName;
			pendingItem = null;
			pendingName = null;
			if (TeamNetworking.IsMasterSession && !((Object)(object)val == (Object)null))
			{
				List<ItemAttributes> list = GameInternals.ShoppingList(ShopManager.instance);
				if (list != null && list.Contains(val))
				{
					Plugin.Log("Shop tube: " + text + " was not consumed; not booked");
					return;
				}
				TeamState.Spent[num] += num2;
				TeamState.AddPurchased(text, num, 1);
				Plugin.Log($"Shop purchase: {text} (${num2}) -> {TeamLabel(num)}");
				TeamNetworking.Instance?.BroadcastTally();
			}
		}

		public static void RecordReroll(UpgradeStand stand)
		{
			if (!TeamNetworking.IsMasterSession || (Object)(object)stand == (Object)null)
			{
				return;
			}
			int num = GameInternals.RerollCost(stand) * 1000;
			if (num > 0)
			{
				int num2 = GameInternals.ButtonGrabberTeam(stand);
				if (num2 == -1)
				{
					num2 = UnambiguousTeam();
				}
				if (num2 == -1)
				{
					Plugin.Log($"Shop reroll (${num}) has no presser attached; not booked");
					return;
				}
				TeamState.Spent[num2] += num;
				Plugin.Log($"Shop reroll (${num}) -> {TeamLabel(num2)}");
				TeamNetworking.Instance?.BroadcastTally();
			}
		}

		private static ItemAttributes FirstShoppingItem()
		{
			List<ItemAttributes> list = GameInternals.ShoppingList(ShopManager.instance);
			if (list == null || list.Count == 0)
			{
				return null;
			}
			ItemAttributes val = list[0];
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return val;
		}

		internal static void PinShop(ItemAttributes item, int viewId, int team)
		{
			if (team == -1 || viewId == 0)
			{
				return;
			}
			PhysGrabObject componentInParent = ((Component)item).GetComponentInParent<PhysGrabObject>();
			if (!((Object)(object)componentInParent == (Object)null))
			{
				int num = TeamOwnership.TeamOf(componentInParent);
				if (num == team)
				{
					shopPinned.Add(viewId);
				}
				else if (num == -1 || shopPinned.Contains(viewId))
				{
					TeamOwnership.Set(viewId, team);
					TeamOwnership.TintShop(((Component)componentInParent).gameObject, viewId, team);
					shopPinned.Add(viewId);
					TeamNetworking.Instance?.BroadcastOwnership(new int[2] { viewId, team }, 1);
					Plugin.Log("Shop check: " + ((Object)item).name + " belongs to " + TeamLabel(team) + " (last placed)");
				}
			}
		}

		private static int ViewIdOf(ItemAttributes item)
		{
			PhysGrabObject val = (((Object)(object)item != (Object)null) ? ((Component)item).GetComponentInParent<PhysGrabObject>() : null);
			PhotonView val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<PhotonView>() : null);
			if (!((Object)(object)val2 != (Object)null))
			{
				return 0;
			}
			return val2.ViewID;
		}

		private static int HolderTeam(ItemAttributes item)
		{
			return GameInternals.DelivererTeam(((Object)(object)item != (Object)null) ? ((Component)item).GetComponentInParent<PhysGrabObject>() : null);
		}

		private static int Placer(ItemAttributes item)
		{
			PhysGrabObject componentInParent = ((Component)item).GetComponentInParent<PhysGrabObject>();
			int num = TeamOwnership.TeamOf(componentInParent);
			if (num != -1)
			{
				return num;
			}
			PlayerAvatar val = GameInternals.Deliverer(componentInParent);
			if ((Object)(object)val == (Object)null || (Object)(object)val.photonView == (Object)null)
			{
				return -1;
			}
			return TeamState.GetTeam(val.photonView.OwnerActorNr);
		}

		private static List<ItemAttributes> ItemsInCheck(ShopManager shop)
		{
			List<ItemAttributes> list = new List<ItemAttributes>();
			List<ItemAttributes> list2 = GameInternals.ShoppingList(shop);
			if (list2 == null)
			{
				return list;
			}
			foreach (ItemAttributes item in list2)
			{
				RoomVolumeCheck val = GameInternals.RoomCheck(item);
				if (!((Object)(object)item == (Object)null) && !((Object)(object)val == (Object)null))
				{
					val.CheckSet();
					if (GameInternals.IsInExtractionPoint(val))
					{
						list.Add(item);
					}
				}
			}
			return list;
		}

		private static string TeamLabel(int team)
		{
			return team switch
			{
				1 => "Azul", 
				0 => "Rojo", 
				_ => "sin equipo", 
			};
		}
	}
	internal static class TeamCarts
	{
		private const string CartItemName = "Item Cart Medium";

		private static readonly List<int> cartOwnership = new List<int>();

		private static readonly Dictionary<int, GameObject> cartObjects = new Dictionary<int, GameObject>();

		private static readonly Dictionary<string, bool> lastGateState = new Dictionary<string, bool>();

		private static readonly HashSet<int> wipeSkipLogged = new HashSet<int>();

		public static int[] CartOwnershipSnapshot()
		{
			return cartOwnership.ToArray();
		}

		public static GameObject MainCartObject(int team)
		{
			if (cartObjects.TryGetValue(team, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			for (int i = 0; i + 1 < cartOwnership.Count; i += 2)
			{
				if (cartOwnership[i + 1] == team)
				{
					PhotonView val = PhotonView.Find(cartOwnership[i]);
					if (!((Object)(object)val != (Object)null))
					{
						return null;
					}
					return ((Component)val).gameObject;
				}
			}
			return null;
		}

		public static List<int> CartsMissingAt(ExtractionPoint point)
		{
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			List<int> list = new List<int>();
			if ((Object)(object)point == (Object)null)
			{
				return list;
			}
			float num = ((ConfigSettings.CartRadius != null) ? ConfigSettings.CartRadius.Value : 6f);
			int[] array = new int[2] { 0, 1 };
			for (int i = 0; i < array.Length; i++)
			{
				int num2 = array[i];
				string text = ((num2 == 0) ? "Rojo" : "Azul");
				GameObject val = MainCartObject(num2);
				string text2 = "destroyed or lost";
				bool flag = false;
				if ((Object)(object)val != (Object)null)
				{
					float num3 = Vector3.Distance(val.transform.position, ((Component)point).transform.position);
					RoomVolumeCheck component = val.GetComponent<RoomVolumeCheck>();
					bool flag2 = (Object)(object)component == (Object)null || GameInternals.IsInExtractionPoint(component);
					flag = num3 <= num && flag2;
					text2 = string.Format("{0:F1}m of {1:F0}m, roomZone={2}", num3, num, ((Object)(object)component == (Object)null) ? "n/a" : flag2.ToString());
				}
				string key = ((Object)point).GetInstanceID() + "x" + num2;
				if (lastGateState.TryGetValue(key, out var value) && value != flag)
				{
					Plugin.Log("Cart gate: " + text + " cart " + (flag ? "entered" : "left") + " " + ((Object)point).name + " (" + text2 + ")");
				}
				lastGateState[key] = flag;
				if (!flag)
				{
					list.Add(num2);
				}
			}
			return list;
		}

		public static void SweepCartContents()
		{
			if (!TeamNetworking.IsMasterSession)
			{
				return;
			}
			for (int i = 0; i + 1 < cartOwnership.Count; i += 2)
			{
				PhotonView val = PhotonView.Find(cartOwnership[i]);
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				PhysGrabCart component = ((Component)val).gameObject.GetComponent<PhysGrabCart>();
				if ((Object)(object)component == (Object)null)
				{
					continue;
				}
				List<PhysGrabObject> list = GameInternals.CartItems(component);
				if (list == null)
				{
					continue;
				}
				int num = cartOwnership[i + 1];
				foreach (PhysGrabObject item in list)
				{
					if (!((Object)(object)item == (Object)null) && TeamOwnership.TeamOf(item) == -1)
					{
						TeamHaul.Claim(((Component)item).gameObject, num);
						Plugin.Log("Cart claim (sweep): " + ((Object)item).name + " rides the " + ((num == 0) ? "Rojo" : "Azul") + " cart");
					}
				}
			}
		}

		public static void Spawn()
		{
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			if (!TeamNetworking.IsMasterSession)
			{
				return;
			}
			cartOwnership.Clear();
			cartObjects.Clear();
			wipeSkipLogged.Clear();
			lastGateState.Clear();
			TruckHealer instance = TruckHealer.instance;
			if ((Object)(object)instance == (Object)null)
			{
				Plugin.Log("Team carts: no truck in this level; no team carts spawned");
				return;
			}
			Transform transform = ((Component)instance).transform;
			Item val = FindCartItem();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log("Team carts: 'Item Cart Medium' not found in StatsManager.itemDictionary; no team carts this level");
				return;
			}
			int[] array = new int[2] { 0, 1 };
			int[] array2 = new int[array.Length * 2];
			for (int i = 0; i < array.Length; i++)
			{
				Quaternion rotation;
				Vector3 position = BasePosition(transform, array[i], out rotation);
				GameObject val2 = InstantiateCart(val, position, rotation);
				if ((Object)(object)val2 == (Object)null)
				{
					Plugin.Log("Team carts: failed to spawn the " + ((array[i] == 0) ? "red" : "blue") + " cart");
					continue;
				}
				Plugin.Log(string.Format("Team carts: {0} cart at {1}", (array[i] == 0) ? "red" : "blue", val2.transform.position));
				cartObjects[array[i]] = val2;
				PhotonView component = val2.GetComponent<PhotonView>();
				array2[i * 2] = (((Object)(object)component != (Object)null) ? component.ViewID : 0);
				array2[i * 2 + 1] = array[i];
				if ((Object)(object)component != (Object)null && component.ViewID != 0)
				{
					cartOwnership.Add(component.ViewID);
					cartOwnership.Add(array[i]);
					TeamOwnership.Set(component.ViewID, array[i]);
				}
				else
				{
					Plugin.Log("Team carts: " + ((array[i] == 0) ? "red" : "blue") + " cart has no network view; skipping ownership");
				}
				TeamOwnership.Tint(val2, array[i]);
				LogCartComponents(val2, array[i]);
			}
			if (PhotonNetwork.CurrentRoom != null)
			{
				TeamNetworking.Instance.BroadcastOwnership(array2, 1);
				Plugin.Log($"Team carts spawned at {transform.position}");
			}
		}

		public static void EnsureCarts()
		{
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			if (!TeamNetworking.IsMasterSession || (Object)(object)RunManager.instance == (Object)null || !SemiFunc.RunIsLevel() || !TeamState.RoundActive)
			{
				return;
			}
			int[] array = new int[2] { 0, 1 };
			foreach (int num in array)
			{
				string text = ((num == 0) ? "red" : "blue");
				GameObject val = MainCartObject(num);
				if ((Object)(object)val != (Object)null && val.transform.position.y > -20f)
				{
					continue;
				}
				if (TeamRound.LivingCount(num) <= 0)
				{
					if (wipeSkipLogged.Add(num))
					{
						Plugin.Log("Team carts: " + text + " cart gone but nobody alive on the team, no respawn (gate excused)");
					}
					continue;
				}
				if ((Object)(object)val != (Object)null)
				{
					PhotonView component = val.GetComponent<PhotonView>();
					if ((Object)(object)component != (Object)null && component.ViewID != 0 && SemiFunc.IsMultiplayer())
					{
						PhotonNetwork.Destroy(component);
					}
					else
					{
						Object.Destroy((Object)(object)val);
					}
				}
				Respawn(num);
			}
		}

		private static Vector3 BasePosition(Transform truck, int team, out Quaternion rotation)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			Transform obj = ResolveAnchor(truck);
			Vector3 val = Vector3.Cross(Vector3.up, truck.right);
			val.y = 0f;
			val = ((((Vector3)(ref val)).sqrMagnitude < 0.01f) ? Vector3.right : ((Vector3)(ref val)).normalized);
			rotation = Quaternion.Euler(0f, truck.eulerAngles.y, 0f);
			float num = ((team == 0) ? 1f : (-1f));
			return obj.position + val * (1.5f * num) + Vector3.up * 0.2f;
		}

		private static void Respawn(int team)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			string text = ((team == 0) ? "red" : "blue");
			TruckHealer instance = TruckHealer.instance;
			if ((Object)(object)instance == (Object)null)
			{
				Plugin.Log("Team carts: no truck, cannot respawn the " + text + " cart");
				return;
			}
			Item val = FindCartItem();
			if ((Object)(object)val == (Object)null)
			{
				Plugin.Log("Team carts: 'Item Cart Medium' not found, cannot respawn the " + text + " cart");
				return;
			}
			Quaternion rotation;
			GameObject val2 = InstantiateCart(val, BasePosition(((Component)instance).transform, team, out rotation), rotation);
			if ((Object)(object)val2 == (Object)null)
			{
				Plugin.Log("Team carts: failed to respawn the " + text + " cart");
				return;
			}
			cartObjects[team] = val2;
			PhotonView component = val2.GetComponent<PhotonView>();
			if ((Object)(object)component != (Object)null && component.ViewID != 0)
			{
				bool flag = false;
				for (int i = 0; i + 1 < cartOwnership.Count; i += 2)
				{
					if (cartOwnership[i + 1] == team)
					{
						cartOwnership[i] = component.ViewID;
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					cartOwnership.Add(component.ViewID);
					cartOwnership.Add(team);
				}
				TeamOwnership.Set(component.ViewID, team);
			}
			TeamOwnership.Tint(val2, team);
			TeamNetworking.Instance?.BroadcastOwnership(CartOwnershipSnapshot(), 1);
			Plugin.Log($"Team carts: {text} cart respawned at base ({val2.transform.position})");
		}

		public static void ApplyOwnership(int[] payload)
		{
			if (payload == null || payload.Length < 2)
			{
				return;
			}
			int num = payload[0];
			for (int i = 1; i + 1 < payload.Length; i += 2)
			{
				int num2 = payload[i];
				int team = payload[i + 1];
				TeamOwnership.Set(num2, team);
				switch (num)
				{
				case 1:
				{
					PhotonView val = PhotonView.Find(num2);
					if ((Object)(object)val != (Object)null)
					{
						TeamOwnership.TintShop(((Component)val).gameObject, num2, team);
					}
					break;
				}
				case 2:
					TeamOwnership.RestoreShopTint(num2);
					break;
				}
			}
		}

		private static void LogCartComponents(GameObject cart, int team)
		{
			if (!((Object)(object)cart == (Object)null))
			{
				List<string> list = new List<string>();
				Component[] components = cart.GetComponents<Component>();
				foreach (Component val in components)
				{
					list.Add(((Object)(object)val == (Object)null) ? "null" : ((object)val).GetType().FullName);
				}
				Plugin.LogVerbose("Cart components (" + ((team == 0) ? "Rojo" : "Azul") + "): " + string.Join(", ", list.ToArray()));
			}
		}

		private static GameObject InstantiateCart(Item item, Vector3 position, Quaternion rotation)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: 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)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (SemiFunc.IsMultiplayer())
			{
				string text = GameInternals.ItemResourcePath(item);
				if (string.IsNullOrEmpty(text))
				{
					Plugin.Log("Team carts: the cart item has no resource path");
					return null;
				}
				return PhotonNetwork.InstantiateRoomObject(text, position, rotation, (byte)0, (object[])null);
			}
			GameObject val = GameInternals.ItemPrefab(item);
			if (!((Object)(object)val != (Object)null))
			{
				return null;
			}
			return Object.Instantiate<GameObject>(val, position, rotation);
		}

		private static Transform ResolveAnchor(Transform truck)
		{
			string[] array = new string[3] { "Truck Safety Spawn Point", "Truck Interior", "Truck additional interior" };
			foreach (string text in array)
			{
				GameObject val = GameObject.Find(text);
				if ((Object)(object)val != (Object)null)
				{
					Plugin.Log("Team carts: anchored to '" + text + "'");
					return val.transform;
				}
			}
			Plugin.Log("Team carts: no truck interior anchor found, anchoring to the truck itself");
			return truck;
		}

		private static Item FindCartItem()
		{
			StatsManager instance = StatsManager.instance;
			if ((Object)(object)instance == (Object)null || instance.itemDictionary == null)
			{
				return null;
			}
			if (instance.itemDictionary.TryGetValue("Item Cart Medium", out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			foreach (Item value2 in instance.itemDictionary.Values)
			{
				if ((Object)(object)value2 != (Object)null && ((Object)value2).name == "Item Cart Medium")
				{
					return value2;
				}
			}
			return null;
		}
	}
	internal static class TeamCheckNotice
	{
		private static readonly Dictionary<ExtractionPoint, TextMeshPro> labels = new Dictionary<ExtractionPoint, TextMeshPro>();

		private static readonly Dictionary<ExtractionPoint, string> lastTexts = new Dictionary<ExtractionPoint, string>();

		private static float nextRefresh;

		public static void Poll()
		{
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			foreach (KeyValuePair<ExtractionPoint, TextMeshPro> item in new List<KeyValuePair<ExtractionPoint, TextMeshPro>>(labels))
			{
				if ((Object)(object)item.Key == (Object)null || (Object)(object)item.Value == (Object)null)
				{
					labels.Remove(item.Key);
					lastTexts.Remove(item.Key);
				}
				else
				{
					FaceAway(item.Value);
				}
			}
			if (Time.time < nextRefresh)
			{
				return;
			}
			nextRefresh = Time.time + 0.25f;
			if (!SemiFunc.RunIsLevel())
			{
				Clear();
				return;
			}
			HashSet<ExtractionPoint> hashSet = new HashSet<ExtractionPoint>();
			ExtractionPoint[] array = Object.FindObjectsOfType<ExtractionPoint>();
			foreach (ExtractionPoint val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				hashSet.Add(val);
				List<int> list = TeamCarts.CartsMissingAt(val);
				list.RemoveAll(TeamRound.TeamWiped);
				string text = GameInternals.ExtractionStateName(val);
				int num;
				switch (text)
				{
				default:
					num = ((text == "Extracting") ? 1 : 0);
					break;
				case "Active":
				case "Warning":
				case "Surplus":
					num = 1;
					break;
				}
				bool flag = (byte)num != 0;
				if (list.Count == 0 || GameInternals.CheckHaul(val) <= 0 || !flag)
				{
					Hide(val);
					continue;
				}
				string text2 = string.Join(" Y ", list.ConvertAll((int team) => (team != 0) ? "AZUL" : "ROJO").ToArray());
				string text3 = ((list.Count > 1) ? "FALTAN CARROS " : "FALTA CARRO ") + text2;
				TextMeshPro val2 = Ensure(val);
				val2.transform.position = ((Component)val).transform.position + Vector3.up * 3.2f;
				if (!lastTexts.TryGetValue(val, out var value) || value != text3)
				{
					lastTexts[val] = text3;
					((TMP_Text)val2).text = text3;
				}
				if (!((Component)val2).gameObject.activeSelf)
				{
					((Component)val2).gameObject.SetActive(true);
				}
			}
			foreach (KeyValuePair<ExtractionPoint, TextMeshPro> item2 in new List<KeyValuePair<ExtractionPoint, TextMeshPro>>(labels))
			{
				if (!hashSet.Contains(item2.Key))
				{
					Hide(item2.Key);
				}
			}
		}

		public static void Clear()
		{
			foreach (KeyValuePair<ExtractionPoint, TextMeshPro> label in labels)
			{
				if ((Object)(object)label.Value != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)label.Value).gameObject);
				}
			}
			labels.Clear();
			lastTexts.Clear();
		}

		private static void Hide(ExtractionPoint point)
		{
			if (labels.TryGetValue(point, out var value) && (Object)(object)value != (Object)null && ((Component)value).gameObject.activeSelf)
			{
				((Component)value).gameObject.SetActive(false);
			}
		}

		private static TextMeshPro Ensure(ExtractionPoint point)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			if (labels.TryGetValue(point, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			GameObject val = new GameObject("TeamWarsCheckNotice");
			TextMeshPro val2 = val.AddComponent<TextMeshPro>();
			((TMP_Text)val2).alignment = (TextAlignmentOptions)514;
			((TMP_Text)val2).fontSize = 48f;
			((Graphic)val2).color = new Color(1f, 0.85f, 0.2f);
			val.transform.localScale = Vector3.one * 0.04f;
			val.SetActive(false);
			labels[point] = val2;
			return val2;
		}

		private static void FaceAway(TextMeshPro label)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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)
			if (!((Component)label).gameObject.activeSelf)
			{
				return;
			}
			Vector3? val = TeamReviveTerminal.LocalEyes();
			if (val.HasValue)
			{
				Vector3 val2 = label.transform.position - val.Value;
				if (((Vector3)(ref val2)).sqrMagnitude > 0.001f)
				{
					label.transform.rotation = Quaternion.LookRotation(val2);
				}
				return;
			}
			Camera main = Camera.main;
			if ((Object)(object)main != (Object)null)
			{
				Vector3 val3 = label.transform.position - ((Component)main).transform.position;
				if (((Vector3)(ref val3)).sqrMagnitude > 0.001f)
				{
					label.transform.rotation = Quaternion.LookRotation(val3);
				}
			}
		}
	}
	public class TeamController : MonoBehaviour
	{
		private const float ZoneAutoBalanceSeconds = 20f;

		private Level lastLevel;

		private float lobbyStartTime;

		private float nextAutoBalance;

		private float nextHaulTrack;

		private float nextLevelTotalCheck;

		private float nextExtractionRetry;

		private float nextShopTag;

		private float nextOwnershipReconcile;

		private float nextResync;

		public static TeamController Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
		}

		private void Update()
		{
			RunManager instance = RunManager.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.levelCurrent == (Object)null || (Object)(object)GameDirector.instance == (Object)null)
			{
				return;
			}
			if (InLobby())
			{
				CloseBehind();
				UpdateLobby();
				return;
			}
			lobbyStartTime = 0f;
			if (SemiFunc.RunIsLevel())
			{
				UpdateLevel(instance);
				return;
			}
			CloseBehind();
			if (!SemiFunc.RunIsShop())
			{
				return;
			}
			PeriodicResync();
			if (Time.time >= nextShopTag)
			{
				nextShopTag = Time.time + 1f;
				if ((Object)(object)ShopManager.instance != (Object)null)
				{
					ShopPurchases.TagItemsInCheck(ShopManager.instance);
				}
				ShopPurchases.MirrorPot();
			}
		}

		private void CloseBehind()
		{
			if (!((Object)(object)lastLevel == (Object)null))
			{
				if (TeamState.RoundActive)
				{
					TeamRound.Close();
				}
				lastLevel = null;
				TeamState.RoundActive = false;
				TeamHaul.Reset();
				TeamOwnership.Reset();
				ShopPurchases.ResetAttribution();
			}
		}

		private void UpdateLobby()
		{
			PeriodicResync();
			if (Time.time >= nextOwnershipReconcile)
			{
				nextOwnershipReconcile = Time.time + 5f;
				TeamOwnership.ReconcilePurchases();
			}
			if (lobbyStartTime <= 0f)
			{
				lobbyStartTime = Time.time;
				Plugin.Log("Lobby entered: players define teams from the lobby panel");
			}
			if (TeamNetworking.IsMasterSession && !(Time.time - lobbyStartTime < 20f) && !(Time.time < nextAutoBalance))
			{
				nextAutoBalance = Time.time + 3f;
				IReadOnlyList<int> readOnlyList = TeamState.AutoBalanceUnassigned();
				if (readOnlyList.Count > 0)
				{
					Plugin.Log($"Lobby auto-balance assigned {readOnlyList.Count} player(s)");
					TeamNetworking.Instance.BroadcastRoster();
				}
			}
		}

		private void UpdateLevel(RunManager runManager)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Invalid comparison between Unknown and I4
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Invalid comparison between Unknown and I4
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Invalid comparison between Unknown and I4
			PeriodicResync();
			TeamRevive.PollKey();
			TeamReviveTerminal.Ensure();
			gameState currentState = GameDirector.instance.currentState;
			if ((int)currentState == 5 || (int)currentState == 3 || (int)currentState == 4)
			{
				if (TeamState.RoundActive && (Object)(object)lastLevel == (Object)(object)runManager.levelCurrent)
				{
					TeamRound.Close();
				}
			}
			else if ((int)currentState == 1 || (int)currentState == 2)
			{
				if ((Object)(object)runManager.levelCurrent != (Object)(object)lastLevel)
				{
					lastLevel = runManager.levelCurrent;
					SetupRound();
				}
				if (Time.time >= nextHaulTrack)
				{
					nextHaulTrack = Time.time + 0.5f;
					TeamHaul.Track();
					TeamCarts.SweepCartContents();
				}
				if (Time.time >= nextExtractionRetry)
				{
					nextExtractionRetry = Time.time + 2f;
					CheckCartGatePatch.RetryHeldExtractions();
					TeamCarts.EnsureCarts();
				}
				TeamCheckNotice.Poll();
				if (Time.time >= nextLevelTotalCheck)
				{
					nextLevelTotalCheck = Time.time + 10f;
					EnsureLevelTotal();
				}
				if (Time.time >= nextOwnershipReconcile)
				{
					nextOwnershipReconcile = Time.time + 5f;
					TeamOwnership.ReconcilePurchases();
				}
			}
		}

		private void PeriodicResync()
		{
			if (!(Time.time < nextResync))
			{
				nextResync = Time.time + 10f;
				TeamNetworking.Instance?.BroadcastRoster();
				TeamNetworking.Instance?.BroadcastOwnership(TeamOwnership.Snapshot(), 0);
				int[] array = TeamCarts.CartOwnershipSnapshot();
				if (array.Length != 0)
				{
					TeamNetworking.Instance?.BroadcastOwnership(array, 1);
				}
				TeamNetworking.Instance?.BroadcastTally();
			}
		}

		private void SetupRound()
		{
			TeamHaul.Reset();
			TeamOwnership.Reset();
			CheckCartGatePatch.ClearPending();
			TeamCheckNotice.Clear();
			ShopPurchases.ResetAttribution();
			TeamMapFilter.Discover();
			TeamMapFilter.ScanChecks();
			TeamState.LevelTotal = ComputeLevelTotal();
			TeamState.ResetRoundTallies();
			TeamState.RoundActive = true;
			TeamRound.Arm();
			if (TeamNetworking.IsMasterSession)
			{
				IReadOnlyList<int> readOnlyList = TeamState.AutoBalanceUnassigned();
				if (readOnlyList.Count > 0)
				{
					Plugin.Log($"Level start: {readOnlyList.Count} unassigned player(s) auto-assigned");
				}
				TeamState.StartPlayers[0] = TeamState.TeamCount(0);
				TeamState.StartPlayers[1] = TeamState.TeamCount(1);
				TeamState.RoundStartTotal = TeamState.LevelTotal;
				TeamNetworking.Instance.BroadcastRoster();
				TeamNetworking.Instance.BroadcastTally();
				TeamCarts.Spawn();
			}
			Plugin.Log($"Round setup: level total value {TeamState.LevelTotal}");
		}

		public void PinDeliverer(ValuableObject valuable)
		{
			TeamHaul.Pin(valuable);
		}

		private static int ComputeLevelTotal()
		{
			float num = 0f;
			ValuableObject[] array = Object.FindObjectsOfType<ValuableObject>();
			foreach (ValuableObject valuable in array)
			{
				num += GameInternals.ValuableOriginalValue(valuable);
			}
			return (int)num;
		}

		private static void EnsureLevelTotal()
		{
			if (TeamNetworking.IsMasterSession)
			{
				int num = ComputeLevelTotal();
				if (num > TeamState.LevelTotal)
				{
					TeamState.LevelTotal = num;
					Plugin.Log($"Level total updated: {num} (valuables finished spawning)");
				}
			}
		}

		private static bool InLobby()
		{
			if (!SemiFunc.RunIsLobby())
			{
				return SemiFunc.RunIsLobbyMenu();
			}
			return true;
		}
	}
	internal static class TeamHaul
	{
		private sealed class LimboEntry
		{
			public readonly int Team;

			public readonly int Value;

			public readonly string Name;

			public readonly float HeldSince;

			public LimboEntry(int team, Deliverable delivered)
			{
				Team = team;
				Value = delivered?.Value ?? 0;
				Name = ((delivered != null) ? delivered.Name : "?");
				HeldSince = Time.time;
			}
		}

		private sealed class Deliverable
		{
			public readonly GameObject Object;

			public readonly int Value;

			public readonly string Name;

			public Deliverable(GameObject target, int value)
			{
				Object = target;
				Value = value;
				Name = (((Object)(object)target != (Object)null) ? ((Object)target).name : "?");
			}
		}

		private static readonly Dictionary<int, int> creditByObject = new Dictionary<int, int>();

		private static readonly Dictionary<int, Deliverable> pendingValue = new Dictionary<int, Deliverable>();

		private static readonly HashSet<int> banked = new HashSet<int>();

		private static readonly HashSet<int> warnedIds = new HashSet<int>();

		private static readonly Dictionary<int, LimboEntry> limbo = new Dictionary<int, LimboEntry>();

		private const float LimboSeconds = 10f;

		private static int lastCompletions;

		private static float lastCompletionTime = -1000f;

		public static void Reset()
		{
			if (TeamNetworking.IsMasterSession)
			{
				TeamState.Earned[0] += TeamState.Banked[0];
				TeamState.Earned[1] += TeamState.Banked[1];
			}
			creditByObject.Clear();
			pendingValue.Clear();
			banked.Clear();
			warnedIds.Clear();
			limbo.Clear();
			lastCompletions = GameInternals.CompletedCheckCount();
			lastCompletionTime = -1000f;
			TeamState.Haul[0] = 0;
			TeamState.Haul[1] = 0;
			TeamState.Banked[0] = 0;
			TeamState.Banked[1] = 0;
		}

		public static void Pin(ValuableObject valuable)
		{
			if (!((Object)(object)valuable == (Object)null) && TeamNetworking.IsMasterSession)
			{
				Credit(((Component)valuable).gameObject);
				Track();
			}
		}

		public static void Track()
		{
			if (!TeamNetworking.IsMasterSession)
			{
				return;
			}
			RoundDirector instance = RoundDirector.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			HashSet<int> hashSet = new HashSet<int>();
			foreach (GameObject dollarHaul in instance.dollarHaulList)
			{
				if ((Object)(object)dollarHaul == (Object)null)
				{
					continue;
				}
				ValuableObject component = dollarHaul.GetComponent<ValuableObject>();
				if (!((Object)(object)component == (Object)null) && GameInternals.IsInExtraction(component))
				{
					int instanceID = ((Object)dollarHaul).GetInstanceID();
					hashSet.Add(instanceID);
					if (Credit(dollarHaul) != -1)
					{
						pendingValue[instanceID] = new Deliverable(dollarHaul, (int)GameInternals.ValuableCurrentValue(component));
						limbo.Remove(instanceID);
					}
				}
			}
			int num = GameInternals.CompletedCheckCount();
			bool flag = num > lastCompletions;
			if (flag)
			{
				lastCompletions = num;
				lastCompletionTime = Time.time;
			}
			bool flag2 = flag || Time.time - lastCompletionTime <= 10f;
			foreach (KeyValuePair<int, Deliverable> item in new List<KeyValuePair<int, Deliverable>>(pendingValue))
			{
				if (!hashSet.Contains(item.Key))
				{
					pendingValue.Remove(item.Key);
					GameObject val = item.Value.Object;
					if ((Object)(object)val != (Object)null && (Object)(object)GameInternals.Deliverer(val.GetComponentInParent<PhysGrabObject>()) != (Object)null)
					{
						Plugin.Log("Haul credit dropped: " + ((Object)val).name + " was taken back out of the check");
					}
					else if (!flag2)
					{
						limbo[item.Key] = new LimboEntry(TeamOf(item.Key), item.Value);
						Plugin.Log($"Haul waiting: {item.Value.Name} ({item.Value.Value}) left the check, banking on the next completion -> {TeamLabel(TeamOf(item.Key))}");
					}
					else
					{
						Bank(item.Key, TeamOf(item.Key), item.Value.Value, item.Value.Name);
					}
				}
			}
			if (flag)
			{
				BankLimbo();
			}
			ExpireLimbo();
			int[] array = new int[2]
			{
				TeamState.Banked[0],
				TeamState.Banked[1]
			};
			foreach (KeyValuePair<int, Deliverable> item2 in pendingValue)
			{
				array[TeamOf(item2.Key)] += item2.Value.Value;
			}
			bool num2 = array[0] != TeamState.Haul[0] || array[1] != TeamState.Haul[1];
			TeamState.Haul[0] = array[0];
			TeamState.Haul[1] = array[1];
			int num3 = TeamState.Goal[0];
			int num4 = TeamState.Goal[1];
			TeamRound.RecalculateGoals();
			if (num2 || TeamState.Goal[0] != num3 || TeamState.Goal[1] != num4)
			{
				TeamNetworking.Instance.BroadcastTally();
				Plugin.LogVerbose($"Haul: Rojo {TeamState.Haul[0]}/{TeamState.Goal[0]}  Azul {TeamState.Haul[1]}/{TeamState.Goal[1]}");
			}
		}

		private static int TeamOf(int instanceId)
		{
			if (!creditByObject.TryGetValue(instanceId, out var value))
			{
				return -1;
			}
			return value;
		}

		private static void Bank(int instanceId, int team, int value, string name)
		{
			if (team == 0 || team == 1)
			{
				TeamState.Banked[team] += value;
				banked.Add(instanceId);
				Plugin.Log($"Haul banked: {name} ({value}) -> {TeamLabel(team)}");
			}
		}

		private static void BankLimbo()
		{
			if (limbo.Count == 0)
			{
				return;
			}
			int num = 0;
			int num2 = 0;
			foreach (LimboEntry value in limbo.Values)
			{
				if (value.Team == 0)
				{
					num += value.Value;
				}
				else if (value.Team == 1)
				{
					num2 += value.Value;
				}
			}
			foreach (int item in new List<int>(limbo.Keys))
			{
				banked.Add(item);
			}
			limbo.Clear();
			TeamState.Banked[0] += num;
			TeamState.Banked[1] += num2;
			Plugin.Log($"Check consumed: banked Rojo {num}, Azul {num2}");
		}

		private static void ExpireLimbo()
		{
			foreach (KeyValuePair<int, LimboEntry> item in new List<KeyValuePair<int, LimboEntry>>(limbo))
			{
				if (Time.time - item.Value.HeldSince > 10f)
				{
					limbo.Remove(item.Key);
					Plugin.Log($"Haul credit lost: {item.Value.Name} ({item.Value.Value}) broke inside the check before extraction; it stops counting");
				}
			}
		}

		private static int Credit(GameObject hauledObject)
		{
			int instanceID = ((Object)hauledObject).GetInstanceID();
			if (creditByObject.TryGetValue(instanceID, out var value))
			{
				return value;
			}
			ValuableObject component = hauledObject.GetComponent<ValuableObject>();
			PhysGrabObject componentInParent = hauledObject.GetComponentInParent<PhysGrabObject>();
			int num = GameInternals.DelivererTeam(componentInParent);
			if (num == -1 && (Object)(object)component != (Object)null)
			{
				PhysGrabCart val = GameInternals.CurrentCart(component);
				PhysGrabObject val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<PhysGrabObject>() : null);
				num = TeamOwnership.TeamOf(val2);
				if (num == -1)
				{
					num = GameInternals.DelivererTeam(val2);
				}
				if (num != -1 && (Object)(object)val2 != (Object)null)
				{
					Plugin.Log("Haul credit: " + ((Object)hauledObject).name + " rides a cart -> " + TeamLabel(num));
				}
			}
			if (num == -1)
			{
				WarnOnce(instanceID, ((Object)hauledObject).name);
				return -1;
			}
			creditByObject[instanceID] = num;
			Plugin.Log("Haul credit: " + ((Object)hauledObject).name + " -> " + TeamLabel(num) + " (" + GameInternals.PlayerName(GameInternals.Deliverer(componentInParent)) + ")");
			Claim(hauledObject, num);
			return num;
		}

		public static void MarkIntoTeamCart(PhysGrabObjectImpactDetector detector)
		{
			if (!TeamNetworking.IsMasterSession || (Object)(object)detector == (Object)null)
			{
				return;
			}
			ValuableObject componentInParent = ((Component)detector).GetComponentInParent<ValuableObject>();
			if ((Object)(object)componentInParent == (Object)null)
			{
				return;
			}
			PhysGrabObject componentInParent2 = ((Component)componentInParent).GetComponentInParent<PhysGrabObject>();
			if (!((Object)(object)componentInParent2 == (Object)null) && TeamOwnership.TeamOf(componentInParent2) == -1)
			{
				PhysGrabCart val = GameInternals.CurrentCart(componentInParent);
				int num = TeamOwnership.TeamOf(((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<PhysGrabObject>() : null);
				if (num != -1)
				{
					creditByObject[((Object)((Component)componentInParent).gameObject).GetInstanceID()] = num;
					Claim(((Component)componentInParent).gameObject, num);
					Plugin.Log("Cart claim: " + ((Object)componentInParent).name + " entered the " + ((num == 0) ? "Rojo" : "Azul") + " cart");
				}
			}
		}

		private static string TeamLabel(int team)
		{
			return team switch
			{
				1 => "Azul", 
				0 => "Rojo", 
				_ => "sin equipo", 
			};
		}

		public static int[] LevelContributions()
		{
			int[] array = new int[2]
			{
				TeamState.Banked[0],
				TeamState.Banked[1]
			};
			foreach (KeyValuePair<int, Deliverable> item in pendingValue)
			{
				int num = TeamOf(item.Key);
				if (num == 0 || num == 1)
				{
					array[num] += item.Value.Value;
				}
			}
			foreach (LimboEntry value in limbo.Values)
			{
				if (value.Team == 0 || value.Team == 1)
				{
					array[value.Team] += value.Value;
				}
			}
			return array;
		}

		public static void Claim(GameObject target, int team)
		{
			if ((Object)(object)target == (Object)null || (team != 0 && team != 1))
			{
				return;
			}
			int instanceID = ((Object)target).GetInstanceID();
			if (!creditByObject.ContainsKey(instanceID))
			{
				creditByObject[instanceID] = team;
			}
			PhysGrabObject componentInParent = target.GetComponentInParent<PhysGrabObject>();
			if (!((Object)(object)componentInParent == (Object)null) && TeamOwnership.TeamOf(componentInParent) == -1)
			{
				PhotonView component = target.GetComponent<PhotonView>();
				if (!((Object)(object)component == (Object)null))
				{
					TeamOwnership.Set(component.ViewID, team);
					TeamNetworking.Instance?.BroadcastOwnership(new int[2] { component.ViewID, team }, 1);
				}
			}
		}

		private static void WarnOnce(int id, string name)
		{
			if (warnedIds.Add(id))
			{
				Plugin.Log("Haul credit: " + name + " arrived with no team attached (nobody and no cart); it does not count yet");
			}
		}
	}
	public class TeamHud : MonoBehaviour
	{
		private sealed class RowTeamButtons
		{
			public MenuPlayerListed row;

			public MenuPage page;

			public GameObject root;

			public Image redImage;

			public Image blueImage;

			public Color redBase;

			public Color blueBase;

			public Outline redFrame;

			public Outline blueFrame;

			public int actor = int.MinValue;
		}

		private Canvas rootCanvas;

		private TextMeshProUGUI scoreText;

		private Image tugBack;

		private Image tugRed;

		private Image tugBlue;

		private TextMeshProUGUI tugAscii;

		private TMP_FontAsset blockFont;

		private string lastTugAscii;

		private readonly List<TextMeshProUGUI> styledLabels = new List<TextMeshProUGUI>();

		private bool styleAdopted;

		private string lastScore;

		private float nextRefresh;

		private float nextRowRefresh;

		private float nextStyleRetry;

		private bool vanillaCurrencyHidden;

		private float announcedOverlay = -1f;

		private readonly Dictionary<int, RowTeamButtons> rowButtons = new Dictionary<int, RowTeamButtons>();

		private RowTeamButtons escSwitch;

		private void OnDestroy()
		{
			RestoreVanillaCurrency();
		}

		private void Update()
		{
			RunManager instance = RunManager.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)instance.levelCurrent == (Object)null || (Object)(object)GameDirector.instance == (Object)null)
			{
				SetScoreVisible(visible: false);
				RefreshTugBar();
				ClearRowButtons();
				RestoreVanillaCurrency();
				return;
			}
			EnsureBuilt();
			if (Time.time < TeamState.OverlayUntil)
			{
				SetScoreVisible(visible: false);
				RefreshTugBar();
				ClearRowButtons();
				MaybeAnnounceWinner();
				RestoreVanillaCurrency();
			}
			else if (SemiFunc.RunIsLobby() || SemiFunc.RunIsLobbyMenu())
			{
				if (LobbyReady())
				{
					SetScoreVisible(visible: true);
					RefreshLobbyStrip();
					if (SemiFunc.RunIsLobbyMenu())
					{
						RefreshRowButtons();
					}
					else
					{
						ClearRowButtons();
					}
				}
				else
				{
					SetScoreVisible(visible: false);
					RefreshTugBar();
					ClearRowButtons();
				}
				RefreshEscSwitch();
				UpdateRowInteraction();
				RestoreVanillaCurrency();
			}
			else if (!SemiFunc.RunIsLevel() && !SemiFunc.RunIsShop())
			{
				SetScoreVisible(visible: false);
				RefreshTugBar();
				ClearRowButtons();
				DestroyEscSwitch();
				RestoreVanillaCurrency();
			}
			else
			{
				SetScoreVisible(visible: true);
				ClearRowButtons();
				RefreshEscSwitch();
				UpdateRowInteraction();
				SyncVanillaCurrency();
				RefreshScore();
			}
		}

		private void MaybeAnnounceWinner()
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			int lastWinner = TeamState.LastWinner;
			if ((lastWinner != 0 && lastWinner != 1) || TeamState.OverlayUntil == announcedOverlay || (Object)(object)BigMessageUI.instance == (Object)null)
			{
				return;
			}
			announcedOverlay = TeamState.OverlayUntil;
			string text = ((lastWinner == 0) ? "GANA ROJO" : "GANA AZUL");
			Color val = ((lastWinner == 0) ? new Color(1f, 0.3f, 0.25f) : new Color(0.3f, 0.6f, 1f));
			try
			{
				SemiFunc.UIBigMessage(text, "{check}", 25f, val, Color.white);
			}
			catch (Exception ex)
			{
				Plugin.Log("Winner cartel failed: " + ex.Message);
			}
		}

		private void RefreshScore()
		{
			if (!(Time.time < nextRefresh))
			{
				nextRefresh = Time.time + 0.25f;
				AdoptStyle();
				string text = RoundCounterText();
				if (text != lastScore)
				{
					lastScore = text;
					((TMP_Text)scoreText).text = text;
				}
				RefreshTugBar();
			}
		}

		private void RefreshLobbyStrip()
		{
			if (!(Time.time < nextRefresh))
			{
				nextRefresh = Time.time + 0.5f;
				AdoptStyle();
				string text = LobbyStripText();
				if (text != lastScore)
				{
					lastScore = text;
					((TMP_Text)scoreText).text = text;
				}
				RefreshTugBar();
			}
		}

		private void RefreshRowButtons()
		{
			foreach (int item in new List<int>(rowButtons.Keys))
			{
				if (!rowButtons.TryGetValue(item, out var value) || value == null)
				{
					rowButtons.Remove(item);
					continue;
				}
				if ((Object)(object)value.root == (Object)null || (Object)(object)value.row == (Object)null)
				{
					rowButtons.Remove(item);
					continue;
				}
				value.actor = RowActor(value.row);
				int team = TeamState.GetTeam(value.actor);
				((Behaviour)value.redFrame).enabled = team == 0;
				((Behaviour)value.blueFrame).enabled = team == 1;
			}
			if (rowButtons.Count > 0 && Time.time < nextRowRefresh)
			{
				return;
			}
			nextRowRefresh = Time.time + 0.5f;
			HashSet<int> hashSet = new HashSet<int>();
			MenuPlayerListed[] array = Object.FindObjectsOfType<MenuPlayerListed>();
			foreach (MenuPlayerListed val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				int instanceID = ((Object)val).GetInstanceID();
				hashSet.Add(instanceID);
				if (!rowButtons.TryGetValue(instanceID, out var value2) || value2 == null || (Object)(object)value2.root == (Object)null)
				{
					value2 = BuildRowButtons(val);
					if (value2 == null)
					{
						continue;
					}
					rowButtons[instanceID] = value2;
				}
				value2.actor = RowActor(val);
				int team2 = TeamState.GetTeam(value2.actor);
				((Behaviour)value2.redFrame).enabled = team2 == 0;
				((Behaviour)value2.blueFrame).enabled = team2 == 1;
			}
			foreach (int item2 in new List<int>(rowButtons.Keys))
			{
				if (!hashSet.Contains(item2))
				{
					rowButtons.Remove(item2);
				}
			}
		}

		private void RefreshEscSwitch()
		{
			if (!GameInternals.EscMenuOpen() || (Object)(object)MenuPageEsc.instance == (Object)null)
			{
				DestroyEscSwitch();
				return;
			}
			if (escSwitch == null || (Object)(object)escSwitch.root == (Object)null)
			{
				DestroyEscSwitch();
				escSwitch = BuildEscSwitch(((Component)MenuPageEsc.instance).transform);
			}
			if (escSwitch != null)
			{
				escSwitch.actor = TeamState.LocalActor;
				int team = TeamState.GetTeam(escSwitch.actor);
				((Behaviour)escSwitch.redFrame).enabled = team == 0;
				((Behaviour)escSwitch.blueFrame).enabled = team == 1;
			}
		}

		private void DestroyEscSwitch()
		{
			if (escSwitch != null && (Object)(object)escSwitch.root != (Object)null)
			{
				Object.Destroy((Object)(object)escSwitch.root);
			}
			escSwitch = null;
		}

		private static RowTeamButtons BuildEscSwitch(Transform page)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_019d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)page == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("TeamWarsTeams");
			RectTransform val2 = FindMainMenuRow(page);
			RowTeamButtons rowTeamButtons = new RowTeamButtons
			{
				root = val,
				actor = TeamState.LocalActor,
				page = ((Component)page).GetComponent<MenuPage>()
			};
			rowTeamButtons.redBase = new Color(0.85f, 0.12f, 0.12f);
			rowTeamButtons.blueBase = new Color(0.15f, 0.4f, 0.95f);
			if ((Object)(object)val2 != (Object)null)
			{
				Rect rect = val2.rect;
				if (((Rect)(ref rect)).width > 200f)
				{
					val.transform.SetParent((Transform)(object)val2, false);
					rowTeamButtons.redImage = BuildTeamSquare(val.transform, "Red", rowTeamButtons.redBase, Vector2.zero, 16f, out rowTeamButtons.redFrame);
					rowTeamButtons.blueImage = BuildTeamSquare(val.transform, "Blue", rowTeamButtons.blueBase, Vector2.zero, 16f, out rowTeamButtons.blueFrame);
					CornerSquare(((Graphic)rowTeamButtons.redImage).rectTransform, new Vector2(-46f, 0f));
					CornerSquare(((Graphic)rowTeamButtons.blueImage).rectTransform, new Vector2(-26f, 0f));
					goto IL_01b7;
				}
			}
			val.transform.SetParent(page, false);
			rowTeamButtons.redImage = BuildTeamSquare(val.transform, "Red", rowTeamButtons.redBase, new Vector2(126f, 104f), 16f, out rowTeamButtons.redFrame);
			rowTeamButtons.blueImage = BuildTeamSquare(val.transform, "Blue", rowTeamButtons.blueBase, new Vector2(146f, 104f), 16f, out rowTeamButtons.blueFrame);
			goto IL_01b7;
			IL_01b7:
			return rowTeamButtons;
		}

		private static RectTransform FindMainMenuRow(Transform page)
		{
			TextMeshProUGUI[] componentsInChildren = ((Component)page).GetComponentsInChildren<TextMeshProUGUI>(true);
			foreach (TextMeshProUGUI val in componentsInChildren)
			{
				if ((Object)