Decompiled source of RVRepairVan v4.3.1

RVRepairVan.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using Chassis.Api;
using DooDesch;
using DooDesch.Localization;
using DooDesch.Transition;
using HarmonyLib;
using Il2Cpp;
using Il2CppFishNet;
using Il2CppFishNet.Connection;
using Il2CppFishNet.Managing;
using Il2CppFishNet.Object;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne;
using Il2CppScheduleOne.Audio;
using Il2CppScheduleOne.Core.Audio;
using Il2CppScheduleOne.Core.Items.Framework;
using Il2CppScheduleOne.Core.Weather;
using Il2CppScheduleOne.Delivery;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Dialogue;
using Il2CppScheduleOne.Doors;
using Il2CppScheduleOne.Employees;
using Il2CppScheduleOne.EntityFramework;
using Il2CppScheduleOne.GameTime;
using Il2CppScheduleOne.Interaction;
using Il2CppScheduleOne.ItemFramework;
using Il2CppScheduleOne.Map;
using Il2CppScheduleOne.Misc;
using Il2CppScheduleOne.Money;
using Il2CppScheduleOne.NPCs;
using Il2CppScheduleOne.NPCs.Behaviour;
using Il2CppScheduleOne.NPCs.CharacterClasses;
using Il2CppScheduleOne.Persistence;
using Il2CppScheduleOne.Persistence.Datas;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.PlayerTasks;
using Il2CppScheduleOne.Product;
using Il2CppScheduleOne.Property;
using Il2CppScheduleOne.Quests;
using Il2CppScheduleOne.Tiles;
using Il2CppScheduleOne.UI;
using Il2CppScheduleOne.UI.Phone.Delivery;
using Il2CppScheduleOne.Vehicles;
using Il2CppScheduleOne.VoiceOver;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using MarcosBodyshop.Api;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using RVRepairVan;
using RVRepairVan.Api;
using RVRepairVan.Base;
using RVRepairVan.Compat;
using RVRepairVan.Config;
using RVRepairVan.Dialogue;
using RVRepairVan.Effects;
using RVRepairVan.Garage;
using RVRepairVan.Localization;
using RVRepairVan.Managers;
using RVRepairVan.Net;
using RVRepairVan.Net.Patches;
using RVRepairVan.Persistence;
using RVRepairVan.Quests;
using S1API.DeadDrops;
using S1API.Entities;
using S1API.Entities.Dialogue;
using S1API.Internal.Abstraction;
using S1API.Items;
using S1API.Items.Storable;
using S1API.Leveling;
using S1API.Messaging;
using S1API.Money;
using S1API.Quests;
using S1API.Quests.Constants;
using S1API.Saveables;
using Unity.AI.Navigation;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Events;
using UnityEngine.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "RVRepairVan", "4.3.1", "DooDesch", "https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan")]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: MelonAdditionalDependencies(new string[] { "Chassis", "MarcosBodyshop" })]
[assembly: AssemblyMetadata("SourceNotice", "RVRepairVan by DooDesch, MIT License. The source code is public at https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan. Please read, change and reuse the source code, not decompiled code from this file. Text and data mining reserved under Art. 4(3) Directive (EU) 2019/790 and § 44b(3) UrhG.")]
[assembly: AssemblyMetadata("License", "https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan/blob/main/LICENSE.md")]
[assembly: AssemblyMetadata("SourceCode", "https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan")]
[assembly: AssemblyMetadata("tdm-reservation", "1")]
[assembly: AssemblyMetadata("tdm-policy", "https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan/blob/main/LICENSE.md")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("DooDesch")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Copyright © DooDesch. MIT License. Source code: https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan")]
[assembly: AssemblyFileVersion("4.3.1.0")]
[assembly: AssemblyInformationalVersion("4.3.1+7ae6dce554947f4096b73230bdfe607f647349fc")]
[assembly: AssemblyProduct("RVRepairVan")]
[assembly: AssemblyTitle("RVRepairVan")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: AssemblyMetadata("AI_Assisted_Creation", "This assembly was partially created with the assistance of Generative AI.")]
[assembly: AssemblyMetadata("AI_Model_Vendor", "Anthropic/OpenAI")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("4.3.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 DooDesch
{
	[AttributeUsage(AttributeTargets.All, Inherited = false)]
	internal sealed class SourceNoticeAttribute : Attribute
	{
		public string Notice { get; }

		public SourceNoticeAttribute(string notice)
		{
			Notice = notice;
		}
	}
	[SourceNotice("RVRepairVan by DooDesch, MIT License. Please read and reuse the source code at https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan, not decompiled code.")]
	internal static class SourceNotice
	{
		internal const string Text = "RVRepairVan by DooDesch, MIT License. The source code is public at https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan. Please read, change and reuse the source code, not decompiled code from this file. Text and data mining reserved under Art. 4(3) Directive (EU) 2019/790 and § 44b(3) UrhG.";

		internal const string Short = "RVRepairVan by DooDesch, MIT License. Please read and reuse the source code at https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan, not decompiled code.";
	}
	[SourceNotice("RVRepairVan by DooDesch, MIT License. Please read and reuse the source code at https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan, not decompiled code.")]
	internal static class ModVersion
	{
		internal const string Current = "4.3.1";
	}
}
namespace DooDesch.Localization
{
	[SourceNotice("RVRepairVan by DooDesch, MIT License. Please read and reuse the source code at https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan, not decompiled code.")]
	internal static class L10n
	{
		private static readonly Dictionary<string, Dictionary<string, string>> _tables = new Dictionary<string, Dictionary<string, string>>();

		private static Dictionary<string, string> _active;

		private static string _lang;

		internal static string Language => _lang ?? (_lang = Detect());

		private static string ModName => typeof(L10n).Assembly.GetName().Name;

		internal static void Register(string lang, Dictionary<string, string> table)
		{
			_tables[lang] = table;
			_active = null;
		}

		internal static string T(string en)
		{
			if (_active == null)
			{
				_active = BuildActiveTable();
			}
			if (!_active.TryGetValue(en, out var value))
			{
				return en;
			}
			return value;
		}

		internal static string T(string en, params object[] args)
		{
			return string.Format(T(en), args);
		}

		private static Dictionary<string, string> BuildActiveTable()
		{
			Dictionary<string, string> value;
			Dictionary<string, string> dictionary = (_tables.TryGetValue(Language, out value) ? new Dictionary<string, string>(value) : new Dictionary<string, string>());
			try
			{
				ExportTemplate();
				Overlay(dictionary, Path.Combine(PackDir(), Language + ".json"));
				Overlay(dictionary, Path.Combine(UserDir(), Language + ".json"));
			}
			catch (Exception ex)
			{
				MelonLogger.Warning("[L10n] user translations failed: " + ex.Message);
			}
			return dictionary;
		}

		private static void Overlay(Dictionary<string, string> table, string file)
		{
			if (!File.Exists(file))
			{
				return;
			}
			Dictionary<string, string> dictionary = ParseJsonObject(File.ReadAllText(file));
			if (dictionary == null)
			{
				MelonLogger.Warning("[L10n] ignoring invalid translation file (flat JSON object of \"english\": \"translated\" strings expected): " + file);
				return;
			}
			foreach (KeyValuePair<string, string> item in dictionary)
			{
				table[item.Key] = item.Value;
			}
		}

		private static string PackDir()
		{
			return Path.Combine(MelonEnvironment.ModsDirectory, "Localization", ModName);
		}

		private static string UserDir()
		{
			return Path.Combine(MelonEnvironment.UserDataDirectory, "DooDesch", "Localization", ModName);
		}

		private static void ExportTemplate()
		{
			if (_tables.Count == 0)
			{
				return;
			}
			SortedSet<string> sortedSet = new SortedSet<string>(StringComparer.Ordinal);
			foreach (Dictionary<string, string> value in _tables.Values)
			{
				foreach (string key in value.Keys)
				{
					sortedSet.Add(key);
				}
			}
			if (sortedSet.Count == 0)
			{
				return;
			}
			Directory.CreateDirectory(UserDir());
			WriteTemplate("en", sortedSet, null);
			foreach (string key2 in _tables.Keys)
			{
				if (key2 != "en")
				{
					WriteTemplate(key2, sortedSet, _tables[key2]);
				}
			}
		}

		private static void WriteTemplate(string lang, SortedSet<string> keys, Dictionary<string, string> table)
		{
			StringBuilder stringBuilder = new StringBuilder();
			stringBuilder.Append("{\n  ").Append(Quote("_readme")).Append(": ")
				.Append(Quote("This file is regenerated on every game start - do not edit it. To change or add a translation, copy it to <language code>.json (for example " + lang + ".json), keep only the lines you want to change, and translate the VALUES only - the keys are the mod's English source strings and must stay unchanged. Keep placeholders like {0}. Set Language in MelonPreferences.cfg under [DooDesch] to force a language (auto = OS language). To share your translation as an installable mod, see https://github.com/DooDesch-Mods/ScheduleOne-L10n/wiki"))
				.Append(",\n");
			foreach (string key in keys)
			{
				string value;
				string s = ((table != null && table.TryGetValue(key, out value)) ? value : key);
				stringBuilder.Append("  ").Append(Quote(key)).Append(": ")
					.Append(Quote(s))
					.Append(",\n");
			}
			stringBuilder.Length -= 2;
			stringBuilder.Append("\n}\n");
			File.WriteAllText(Path.Combine(UserDir(), "_template." + lang + ".json"), stringBuilder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false));
		}

		private static string Detect()
		{
			//IL_0079: 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)
			//IL_0082: Invalid comparison between Unknown and I4
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Invalid comparison between Unknown and I4
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Invalid comparison between Unknown and I4
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Invalid comparison between Unknown and I4
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Expected I4, but got Unknown
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Invalid comparison between Unknown and I4
			//IL_00dc: 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_00e1: Invalid comparison between Unknown and I4
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Invalid comparison between Unknown and I4
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Invalid comparison between Unknown and I4
			string text = "auto";
			try
			{
				MelonPreferences_Category val = MelonPreferences.CreateCategory("DooDesch", "DooDesch Mods");
				text = ((val.GetEntry<string>("Language") ?? val.CreateEntry<string>("Language", "auto", "Language", "Language for all DooDesch mods: auto (= OS language), en, de, ...", false, false, (ValueValidator)null, (string)null)).Value ?? "auto").Trim().ToLowerInvariant();
			}
			catch
			{
			}
			if (text.Length > 0 && text != "auto")
			{
				return text;
			}
			SystemLanguage systemLanguage = Application.systemLanguage;
			if ((int)systemLanguage <= 15)
			{
				if ((int)systemLanguage == 6)
				{
					goto IL_0121;
				}
				if ((int)systemLanguage == 14)
				{
					return "fr";
				}
				if ((int)systemLanguage == 15)
				{
					return "de";
				}
			}
			else if ((int)systemLanguage <= 34)
			{
				switch (systemLanguage - 21)
				{
				default:
					if ((int)systemLanguage != 34)
					{
						break;
					}
					return "es";
				case 0:
					return "it";
				case 7:
					return "pt";
				case 6:
					return "pl";
				case 9:
					return "ru";
				case 1:
					return "ja";
				case 2:
					return "ko";
				case 3:
				case 4:
				case 5:
				case 8:
					break;
				}
			}
			else
			{
				if ((int)systemLanguage == 37)
				{
					return "tr";
				}
				if (systemLanguage - 40 <= 1)
				{
					goto IL_0121;
				}
			}
			return "en";
			IL_0121:
			return "zh";
		}

		private static Dictionary<string, string> ParseJsonObject(string json)
		{
			if (json == null)
			{
				return null;
			}
			int i = 0;
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			SkipWs(json, ref i);
			if (i >= json.Length || json[i] != '{')
			{
				return null;
			}
			i++;
			SkipWs(json, ref i);
			if (i < json.Length && json[i] == '}')
			{
				return dictionary;
			}
			while (true)
			{
				string text = ParseString(json, ref i);
				if (text == null)
				{
					return null;
				}
				SkipWs(json, ref i);
				if (i >= json.Length || json[i] != ':')
				{
					return null;
				}
				i++;
				SkipWs(json, ref i);
				string text2 = ParseString(json, ref i);
				if (text2 == null)
				{
					return null;
				}
				dictionary[text] = text2;
				SkipWs(json, ref i);
				if (i >= json.Length)
				{
					return null;
				}
				if (json[i] != ',')
				{
					break;
				}
				i++;
				SkipWs(json, ref i);
				if (i < json.Length && json[i] == '}')
				{
					return dictionary;
				}
			}
			if (json[i] != '}')
			{
				return null;
			}
			return dictionary;
		}

		private static void SkipWs(string s, ref int i)
		{
			while (i < s.Length && (char.IsWhiteSpace(s[i]) || s[i] == '\ufeff'))
			{
				i++;
			}
		}

		private static string ParseString(string s, ref int i)
		{
			SkipWs(s, ref i);
			if (i >= s.Length || s[i] != '"')
			{
				return null;
			}
			i++;
			StringBuilder stringBuilder = new StringBuilder();
			while (i < s.Length)
			{
				char c = s[i++];
				switch (c)
				{
				case '"':
					return stringBuilder.ToString();
				default:
					stringBuilder.Append(c);
					break;
				case '\\':
					if (i >= s.Length)
					{
						return null;
					}
					switch (s[i++])
					{
					case '"':
						stringBuilder.Append('"');
						break;
					case '\\':
						stringBuilder.Append('\\');
						break;
					case '/':
						stringBuilder.Append('/');
						break;
					case 'b':
						stringBuilder.Append('\b');
						break;
					case 'f':
						stringBuilder.Append('\f');
						break;
					case 'n':
						stringBuilder.Append('\n');
						break;
					case 'r':
						stringBuilder.Append('\r');
						break;
					case 't':
						stringBuilder.Append('\t');
						break;
					case 'u':
						if (i + 4 > s.Length)
						{
							return null;
						}
						try
						{
							stringBuilder.Append((char)Convert.ToInt32(s.Substring(i, 4), 16));
						}
						catch
						{
							return null;
						}
						i += 4;
						break;
					default:
						return null;
					}
					break;
				}
			}
			return null;
		}

		private static string Quote(string s)
		{
			StringBuilder stringBuilder = new StringBuilder(s.Length + 2);
			stringBuilder.Append('"');
			foreach (char c in s)
			{
				switch (c)
				{
				case '"':
					stringBuilder.Append("\\\"");
					continue;
				case '\\':
					stringBuilder.Append("\\\\");
					continue;
				case '\n':
					stringBuilder.Append("\\n");
					continue;
				case '\r':
					stringBuilder.Append("\\r");
					continue;
				case '\t':
					stringBuilder.Append("\\t");
					continue;
				}
				if (c < ' ')
				{
					StringBuilder stringBuilder2 = stringBuilder.Append("\\u");
					int num = c;
					stringBuilder2.Append(num.ToString("x4"));
				}
				else
				{
					stringBuilder.Append(c);
				}
			}
			stringBuilder.Append('"');
			return stringBuilder.ToString();
		}
	}
}
namespace DooDesch.Transition
{
	[SourceNotice("RVRepairVan by DooDesch, MIT License. Please read and reuse the source code at https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan, not decompiled code.")]
	internal static class Veil
	{
		internal static class Ease
		{
			public static float In(float t)
			{
				t = Mathf.Clamp01(t);
				return t * t * t;
			}

			public static float Out(float t)
			{
				t = Mathf.Clamp01(t);
				float num = 1f - t;
				return 1f - num * num * num;
			}

			public static float InOut(float t)
			{
				t = Mathf.Clamp01(t);
				return t * t * (3f - 2f * t);
			}
		}

		internal static bool EyelidsAvailable
		{
			get
			{
				try
				{
					return Singleton<EyelidOverlay>.InstanceExists;
				}
				catch
				{
					return false;
				}
			}
		}

		internal static bool BlackAvailable
		{
			get
			{
				try
				{
					return Singleton<BlackOverlay>.InstanceExists || Singleton<HUD>.InstanceExists;
				}
				catch
				{
					return false;
				}
			}
		}

		private static EyelidOverlay Eyes()
		{
			try
			{
				return Singleton<EyelidOverlay>.InstanceExists ? Singleton<EyelidOverlay>.Instance : null;
			}
			catch
			{
				return null;
			}
		}

		internal static void SetEyelids(float openness)
		{
			EyelidOverlay val = Eyes();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			try
			{
				val.AutoUpdate = false;
				val.SetOpen(Mathf.Clamp01(openness));
			}
			catch
			{
			}
		}

		internal static float CurrentEyelidOpen(float fallback = 1f)
		{
			EyelidOverlay val = Eyes();
			if ((Object)(object)val == (Object)null)
			{
				return fallback;
			}
			try
			{
				return val.CurrentOpen;
			}
			catch
			{
				return fallback;
			}
		}

		internal static void ReleaseEyelids()
		{
			EyelidOverlay val = Eyes();
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			try
			{
				val.AutoUpdate = true;
			}
			catch
			{
			}
		}

		internal static float EyelidTargetOpen()
		{
			return 1f;
		}

		internal static IEnumerator CloseEyelids(float dur)
		{
			float start = CurrentEyelidOpen();
			if (dur <= 0f)
			{
				SetEyelids(0f);
				yield break;
			}
			for (float t = 0f; t < dur; t += Time.deltaTime)
			{
				SetEyelids(Mathf.Lerp(start, 0f, Ease.InOut(t / dur)));
				yield return null;
			}
			SetEyelids(0f);
		}

		internal static IEnumerator OpenEyelidsToTarget(float dur)
		{
			float target = EyelidTargetOpen();
			if (dur <= 0f)
			{
				SetEyelids(target);
				ReleaseEyelids();
				yield break;
			}
			for (float t = 0f; t < dur; t += Time.deltaTime)
			{
				SetEyelids(Mathf.Lerp(0f, target, Ease.Out(t / dur)));
				yield return null;
			}
			SetEyelids(target);
			ReleaseEyelids();
		}

		internal static IEnumerator FadeEyelids(float target, float dur, bool releaseToGame)
		{
			if ((Object)(object)Eyes() == (Object)null)
			{
				yield break;
			}
			float start = CurrentEyelidOpen(target);
			if (dur > 0f)
			{
				for (float t = 0f; t < dur; t += Time.deltaTime)
				{
					SetEyelids(Mathf.Lerp(start, target, Ease.InOut(t / dur)));
					yield return null;
				}
			}
			SetEyelids(target);
			if (releaseToGame)
			{
				ReleaseEyelids();
			}
		}

		internal static void BlackOpen(float t)
		{
			Black(toBlack: true, t);
		}

		internal static void BlackClose(float t)
		{
			Black(toBlack: false, t);
		}

		private static void Black(bool toBlack, float t)
		{
			try
			{
				if (Singleton<BlackOverlay>.InstanceExists)
				{
					BlackOverlay instance = Singleton<BlackOverlay>.Instance;
					if (toBlack)
					{
						instance.Open(t, (Action)null);
					}
					else
					{
						instance.Close(t, (Action)null);
					}
				}
				else if (Singleton<HUD>.InstanceExists)
				{
					Singleton<HUD>.Instance.SetBlackOverlayVisible(toBlack, t);
				}
			}
			catch (Exception ex)
			{
				ScreenTransition.Warn?.Invoke("Veil.Black failed: " + ex.Message);
			}
		}

		internal static void SetCanMove(bool canMove)
		{
			try
			{
				PlayerMovement instance = PlayerSingleton<PlayerMovement>.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.CanMove = canMove;
				}
			}
			catch
			{
			}
		}

		internal static void SetCanLook(bool canLook)
		{
			try
			{
				PlayerCamera instance = PlayerSingleton<PlayerCamera>.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.SetCanLook(canLook);
				}
			}
			catch
			{
			}
		}
	}
	[SourceNotice("RVRepairVan by DooDesch, MIT License. Please read and reuse the source code at https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan, not decompiled code.")]
	internal enum VeilMode
	{
		Eyelids,
		Black,
		EyelidsAndBlack
	}
	[SourceNotice("RVRepairVan by DooDesch, MIT License. Please read and reuse the source code at https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan, not decompiled code.")]
	internal struct TransitionRequest
	{
		public VeilMode Mechanism;

		public float CloseSeconds;

		public float OpenSeconds;

		public float HoldSeconds;

		public bool LockMovement;

		public bool LockCamera;

		public Action DuringBlack;

		public Action OnMidHold;

		public Action OnDone;

		public Func<bool> WaitUntilReady;

		public float WaitDeadlineSeconds;

		public Action WhileWaiting;

		public Func<bool> KeepClosedAfter;

		public string Key;
	}
	[SourceNotice("RVRepairVan by DooDesch, MIT License. Please read and reuse the source code at https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan, not decompiled code.")]
	internal static class ScreenTransition
	{
		public static Action<string> Warn = delegate(string msg)
		{
			try
			{
				MelonLogger.Warning(msg);
			}
			catch
			{
			}
		};

		private static readonly HashSet<string> Active = new HashSet<string>();

		public static bool IsRunning(string key)
		{
			return Active.Contains(Bucket(key));
		}

		public static bool Play(TransitionRequest req)
		{
			string text = Bucket(req.Key);
			if (Active.Contains(text))
			{
				return false;
			}
			bool flag = req.Mechanism == VeilMode.Eyelids || req.Mechanism == VeilMode.EyelidsAndBlack;
			bool flag2 = req.Mechanism == VeilMode.Black || req.Mechanism == VeilMode.EyelidsAndBlack;
			if ((!flag || !Veil.EyelidsAvailable) && (!flag2 || !Veil.BlackAvailable))
			{
				Safe(req.DuringBlack);
				Safe(req.OnDone);
				return true;
			}
			Active.Add(text);
			try
			{
				MelonCoroutines.Start(Run(req, text, flag, flag2));
			}
			catch (Exception ex)
			{
				Warn?.Invoke("ScreenTransition.Play start failed: " + ex.Message);
				Active.Remove(text);
				Safe(req.DuringBlack);
				Safe(req.OnDone);
			}
			return true;
		}

		public static void ForceReset(string key = null)
		{
			if (key == null)
			{
				Active.Clear();
			}
			else
			{
				Active.Remove(Bucket(key));
			}
			try
			{
				Veil.BlackClose(0f);
				Veil.SetEyelids(1f);
				Veil.ReleaseEyelids();
				Veil.SetCanMove(canMove: true);
				Veil.SetCanLook(canLook: true);
			}
			catch (Exception ex)
			{
				Warn?.Invoke("ScreenTransition.ForceReset failed: " + ex.Message);
			}
		}

		private static IEnumerator Run(TransitionRequest req, string key, bool eye, bool black)
		{
			bool lockedMove = false;
			bool lockedLook = false;
			try
			{
				if (req.LockMovement)
				{
					Veil.SetCanMove(canMove: false);
					lockedMove = true;
				}
				if (req.LockCamera)
				{
					Veil.SetCanLook(canLook: false);
					lockedLook = true;
				}
				if (black)
				{
					Veil.BlackOpen(req.CloseSeconds);
				}
				if (eye)
				{
					yield return Veil.CloseEyelids(req.CloseSeconds);
				}
				else
				{
					yield return Wait(req.CloseSeconds);
				}
				Safe(req.DuringBlack);
				yield return null;
				yield return null;
				if (req.WaitUntilReady != null)
				{
					float deadline = Time.time + Mathf.Max(0f, req.WaitDeadlineSeconds);
					while (Time.time < deadline && !SafeReady(req.WaitUntilReady))
					{
						Safe(req.WhileWaiting);
						yield return null;
					}
					Safe(req.WhileWaiting);
				}
				if (req.HoldSeconds > 0f)
				{
					float deadline = req.HoldSeconds * 0.5f;
					yield return Wait(deadline);
					Safe(req.OnMidHold);
					yield return Wait(req.HoldSeconds - deadline);
				}
				else
				{
					Safe(req.OnMidHold);
				}
				if (req.KeepClosedAfter == null || !SafeReady(req.KeepClosedAfter))
				{
					if (black)
					{
						Veil.BlackClose(req.OpenSeconds);
					}
					if (eye)
					{
						yield return Veil.OpenEyelidsToTarget(req.OpenSeconds);
					}
					else
					{
						yield return Wait(req.OpenSeconds);
					}
				}
				Safe(req.OnDone);
			}
			finally
			{
				bool flag = req.KeepClosedAfter != null && SafeReady(req.KeepClosedAfter);
				if (eye)
				{
					if (flag)
					{
						Veil.SetEyelids(0f);
					}
					else
					{
						Veil.SetEyelids(Veil.EyelidTargetOpen());
						Veil.ReleaseEyelids();
					}
				}
				if (black && !flag)
				{
					Veil.BlackClose(0.25f);
				}
				if (lockedMove)
				{
					Veil.SetCanMove(canMove: true);
				}
				if (lockedLook)
				{
					Veil.SetCanLook(canLook: true);
				}
				Active.Remove(key);
			}
		}

		private static string Bucket(string key)
		{
			if (!string.IsNullOrEmpty(key))
			{
				return key;
			}
			return "default";
		}

		private static IEnumerator Wait(float sec)
		{
			if (!(sec <= 0f))
			{
				for (float t = 0f; t < sec; t += Time.deltaTime)
				{
					yield return null;
				}
			}
		}

		private static bool SafeReady(Func<bool> f)
		{
			try
			{
				return f();
			}
			catch
			{
				return false;
			}
		}

		private static void Safe(Action a)
		{
			if (a == null)
			{
				return;
			}
			try
			{
				a();
			}
			catch (Exception ex)
			{
				Warn?.Invoke("ScreenTransition callback failed: " + ex.Message);
			}
		}
	}
}
namespace Hash.Api
{
	[SourceNotice("RVRepairVan by DooDesch, MIT License. Please read and reuse the source code at https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan, not decompiled code.")]
	public static class HashCommands
	{
		private const string BridgeTypeName = "Hash.Bridge.HashBridge, Hash";

		private static readonly List<string[]> _pending = new List<string[]>();

		private static Action<string, string, string, string> _declare;

		private static bool _bound;

		public static bool Available
		{
			get
			{
				Bind();
				return _bound;
			}
		}

		private static string Owner
		{
			get
			{
				try
				{
					return Assembly.GetExecutingAssembly().GetName().Name ?? "";
				}
				catch
				{
					return "";
				}
			}
		}

		public static void Add(string word, string description, string example = null)
		{
			if (!string.IsNullOrEmpty(word))
			{
				Bind();
				if (_declare != null)
				{
					Safely(word, description, example);
					return;
				}
				_pending.Add(new string[3]
				{
					word,
					description ?? "",
					example ?? ""
				});
			}
		}

		private static void Safely(string word, string description, string example)
		{
			try
			{
				_declare(word, description ?? "", example ?? "", Owner);
			}
			catch
			{
			}
		}

		private static void Bind()
		{
			if (_bound)
			{
				return;
			}
			try
			{
				Type type = Type.GetType("Hash.Bridge.HashBridge, Hash", throwOnError: false);
				if (type == null)
				{
					return;
				}
				_declare = type.GetField("Declare", BindingFlags.Static | BindingFlags.Public)?.GetValue(null) as Action<string, string, string, string>;
				if (_declare == null)
				{
					return;
				}
				_bound = true;
				foreach (string[] item in _pending)
				{
					Safely(item[0], item[1], item[2]);
				}
				_pending.Clear();
			}
			catch
			{
			}
		}
	}
}
namespace RVRepairVan
{
	[SourceNotice("RVRepairVan by DooDesch, MIT License. Please read and reuse the source code at https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan, not decompiled code.")]
	public sealed class Core : MelonMod
	{
		private static readonly HashSet<string> _swallowed = new HashSet<string>();

		private static int _sceneGeneration;

		private const float GameLoadTimeout = 300f;

		private const float RestoreWatchInterval = 3f;

		public static Core Instance { get; private set; }

		public static Instance Log { get; private set; }

		internal static int SceneGeneration => _sceneGeneration;

		[Conditional("DEBUG")]
		public static void LogDebug(string msg)
		{
			Instance log = Log;
			if (log != null)
			{
				log.Msg(msg);
			}
		}

		internal static void Swallowed(string where, Exception e)
		{
			lock (_swallowed)
			{
				if (!_swallowed.Add(where))
				{
					return;
				}
			}
			Instance log = Log;
			if (log != null)
			{
				log.Warning("[Swallowed] " + where + ": " + e.GetType().Name + ": " + e.Message);
			}
		}

		public override void OnInitializeMelon()
		{
			Instance = this;
			Log = ((MelonBase)this).LoggerInstance;
			RVRepairVanPreferences.Initialize();
			German.Register();
			NetworkBus.Init(((MelonBase)this).HarmonyInstance);
			RvGarage.Register();
			RvPaint.Init();
			Log.Msg($"RVRepairVan initialized. Enabled={RVRepairVanPreferences.Enabled}, Questline={RVRepairVanPreferences.QuestlineEnabled}, RepairPrice={RVRepairVanPreferences.RepairPrice}");
		}

		public override void OnFixedUpdate()
		{
			try
			{
				RvCargo.FixedStep();
			}
			catch (Exception e)
			{
				Swallowed("cargo physics step", e);
			}
		}

		public override void OnLateUpdate()
		{
			try
			{
				RvCargo.LateStep();
			}
			catch (Exception e)
			{
				Swallowed("cargo frame", e);
			}
			try
			{
				RvRide.LateStep();
			}
			catch (Exception e2)
			{
				Swallowed("ride frame", e2);
			}
			try
			{
				RvRiders.Draw();
			}
			catch (Exception e3)
			{
				Swallowed("riders frame", e3);
			}
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			if (sceneName == "Menu")
			{
				_sceneGeneration++;
				RepairSave.BeginLoad();
			}
			else if (!(sceneName != "Main"))
			{
				RVManager.Reset();
				RepairCinematic.ForceReset();
				Questline.InitNet();
				if (RVRepairVanPreferences.QuestlineEnabled)
				{
					Questline.Reset();
					Questline.Start();
				}
				else
				{
					MarcoRepairDialogue.Reset();
					MelonCoroutines.Start(MarcoRepairDialogue.SetupCoroutine());
					RepairStateStore.ResetClient();
					MelonCoroutines.Start(Questline.NetJoinCoroutineShared());
					MelonCoroutines.Start(BuildOutQuest.CancelLeftoverCoroutine());
				}
				RvUpgrades.Reset();
				ClientPayment.Reset();
				_sceneGeneration++;
				MelonCoroutines.Start(RestoreRepairCoroutine(_sceneGeneration));
				MelonCoroutines.Start(RvRepairJob.InstantRepairCoroutine());
				MelonCoroutines.Start(ScheduleMaintenance.Watch(_sceneGeneration));
			}
		}

		public override void OnPreferencesSaved()
		{
			try
			{
				MarcoRepairDialogue.RefreshPrice();
				Questline.RefreshPrice();
			}
			catch (Exception ex)
			{
				Log.Warning("[Prefs] OnPreferencesSaved failed: " + ex.Message);
			}
		}

		private static IEnumerator RestoreRepairCoroutine(int generation)
		{
			float waited = 0f;
			while (!RepairSave.Loaded && waited < 10f)
			{
				yield return (object)new WaitForSeconds(0.5f);
				waited += 0.5f;
			}
			if (!RepairSave.Loaded)
			{
				Log.Warning("[Restore] save state not loaded after 10 s - the repair check runs on defaults.");
			}
			Log.Msg("[Restore] RV destroyed at scene start: " + SafeIsDestroyed() + ".");
			waited = 0f;
			while (!GameLoaded() && waited < 300f)
			{
				if (generation != _sceneGeneration)
				{
					Log.Msg("[Restore] a newer load took over - this check stops.");
					yield break;
				}
				yield return (object)new WaitForSeconds(0.5f);
				waited += 0.5f;
			}
			if (generation != _sceneGeneration)
			{
				Log.Msg("[Restore] a newer load took over - this check stops.");
				yield break;
			}
			if (waited >= 300f)
			{
				Log.Warning("[Restore] the game did not report a finished load after " + 300f + " s - checking the RV anyway.");
			}
			else
			{
				Log.Msg("[Restore] game load finished after " + waited.ToString("0.0") + " s.");
			}
			if (NetworkBus.Online && !NetworkBus.IsServer)
			{
				Log.Msg("[Restore] co-op client - deferring RV state to the host (no local restore).");
				yield break;
			}
			if (NeedsRestore())
			{
				Restore("RV was previously repaired - restoring without charge.");
			}
			RvRepairJob.ResumeIfRunning();
			for (int i = 0; i < 5; i++)
			{
				try
				{
					RvUpgrades.ApplyOwned();
				}
				catch (Exception ex)
				{
					Log.Warning("[Restore] upgrade apply failed: " + ex.Message);
				}
				yield return (object)new WaitForSeconds(2f);
			}
			while (generation == _sceneGeneration)
			{
				yield return (object)new WaitForSeconds(3f);
				if (generation != _sceneGeneration)
				{
					break;
				}
				if (NeedsRestore())
				{
					Restore("a paid-for RV was wrecked again after the load - restoring without charge.");
					if (NetworkBus.Online && NetworkBus.IsServer)
					{
						NetworkBus.BroadcastToAll(RvOp.RepairApplied);
					}
					try
					{
						RvUpgrades.ApplyOwned();
					}
					catch (Exception ex2)
					{
						Log.Warning("[Restore] upgrade apply after the late restore failed: " + ex2.Message);
					}
				}
			}
		}

		private static bool GameLoaded()
		{
			try
			{
				LoadManager instance = Singleton<LoadManager>.Instance;
				return (Object)(object)instance != (Object)null && instance.IsGameLoaded;
			}
			catch (Exception e)
			{
				Swallowed("Core.GameLoaded", e);
				return false;
			}
		}

		private static string SafeIsDestroyed()
		{
			try
			{
				return RVManager.TryLocate() ? RVManager.IsDestroyed().ToString() : "no RV found";
			}
			catch (Exception ex)
			{
				return "unknown (" + ex.Message + ")";
			}
		}

		private static bool NeedsRestore()
		{
			try
			{
				return RepairStateStore.GetRepaired() && !RvRepairJob.JobRunning && RVManager.TryLocate() && RVManager.IsDestroyed();
			}
			catch (Exception ex)
			{
				Log.Warning("[Restore] check failed: " + ex.Message);
				return false;
			}
		}

		private static void Restore(string why)
		{
			Log.Msg("[Restore] " + why);
			RVManager.Repair();
		}
	}
}
namespace RVRepairVan.Quests
{
	[SourceNotice("RVRepairVan by DooDesch, MIT License. Please read and reuse the source code at https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan, not decompiled code.")]
	internal static class BuildOutQuest
	{
		internal static readonly string Title = L10n.T("Home on Wheels");

		internal const int StepAsk = 0;

		internal const int StepEngine = 1;

		internal const int StepDrive = 2;

		internal const int StepFloor = 3;

		internal const int StepCount = 4;

		internal static void Tick(bool storyOver, bool asked)
		{
			Quest questByName = QuestManager.GetQuestByName(Title);
			bool flag = RvUpgrades.Owned(RvUpgrade.Engine);
			bool flag2 = RvUpgrades.Owned(RvUpgrade.WorkshopFloor);
			if (flag && flag2)
			{
				if (questByName != null)
				{
					Finish();
				}
			}
			else if (!(RVRepairVanPreferences.Enabled && RVRepairVanPreferences.QuestlineEnabled && RVRepairVanPreferences.UpgradesEnabled && RepairStateStore.GetRepaired() && storyOver))
			{
				if (questByName != null)
				{
					Core.Log.Msg("[Quest] '" + Title + "' cancelled - repaired=" + RepairStateStore.GetRepaired() + " storyOver=" + storyOver + " upgrades=" + RVRepairVanPreferences.UpgradesEnabled + ".");
					QuestSteps.Forget(Title);
					questByName.Cancel();
				}
			}
			else if (questByName == null)
			{
				QuestSteps.Forget(Title);
				QuestManager.CreateQuest<BuildOutRVQuest>((string)null);
				Core.Log.Msg("[Quest] '" + Title + "' started (engine=" + flag + " floor=" + flag2 + " asked=" + asked + ").");
			}
			else
			{
				Sync(asked || RvUpgrades.Mask != 0, flag, flag2);
			}
		}

		private static void Sync(bool asked, bool engine, bool floor)
		{
			//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_0035: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			if (QuestSteps.TryOpen(Title, 4, out var steps))
			{
				bool flag = engine && !floor && RvGarage.InGarage();
				Vector3 val = Questline.MarcoPosition();
				steps.Set(0, (QuestState)((!asked) ? 1 : 2), null, "marco_baron", val);
				steps.Set(1, (QuestState)(engine ? 2 : (asked ? 1 : 0)), L10n.T("Have Marco put the engine in ({0})", MoneyManager.FormatAmount((float)RvUpgrades.Price(RvUpgrade.Engine), false, false)), "marco_baron", val);
				steps.Set(2, (QuestState)(engine ? ((!(floor || flag)) ? 1 : 2) : 0), null, null, RvGarage.LotPoint(val));
				steps.Set(3, (QuestState)(floor ? 2 : (flag ? 1 : 0)), L10n.T("Have Marco put in the workshop floor there ({0})", MoneyManager.FormatAmount((float)RvUpgrades.Price(RvUpgrade.WorkshopFloor), false, false)), "marco_baron", val);
			}
		}

		private static void Finish()
		{
			QuestSteps.CompleteAll(Title);
			if (!NetworkBus.Online || NetworkBus.IsServer)
			{
				RvRepairJob.TextFromMarco(L10n.T("Floor's in. You can set up shop in there now. Crew room and a loading dock I can do too, just ask."));
			}
		}

		internal static IEnumerator CancelLeftoverCoroutine()
		{
			for (int i = 0; i < 15; i++)
			{
				if (RepairSave.Loaded)
				{
					break;
				}
				yield return (object)new WaitForSeconds(1f);
			}
			yield return (object)new WaitForSeconds(3f);
			try
			{
				Quest questByName = QuestManager.GetQuestByName(Title);
				if (questByName != null)
				{
					Core.Log.Msg("[Quest] '" + Title + "' cancelled - QuestMode is Simple.");
					questByName.Cancel();
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Quest] cancelling the leftover build-out quest failed: " + ex.Message);
			}
		}
	}
	[SourceNotice("RVRepairVan by DooDesch, MIT License. Please read and reuse the source code at https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan, not decompiled code.")]
	public class BuildOutRVQuest : Quest
	{
		protected override string Title => BuildOutQuest.Title;

		protected override string Description => L10n.T("Marco can do more to the RV.");

		protected override bool AutoBegin => true;

		protected override Sprite QuestIcon => RepairRVQuest.SharedIcon;

		protected override void OnCreated()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			((Registerable)this).OnCreated();
			try
			{
				Vector3 position;
				Vector3 pOIPosition = (RVManager.TryGetPosition(out position) ? position : Vector3.zero);
				((Quest)this).AddEntry(L10n.T("Ask Marco about the build-outs"), (Vector3?)null).POIPosition = pOIPosition;
				((Quest)this).AddEntry(L10n.T("Have Marco put the engine in"), (Vector3?)null).POIPosition = pOIPosition;
				((Quest)this).AddEntry(L10n.T("Drive the RV onto Marco's lot"), (Vector3?)null).POIPosition = pOIPosition;
				((Quest)this).AddEntry(L10n.T("Have Marco put in the workshop floor there"), (Vector3?)null).POIPosition = pOIPosition;
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Quest] build-out OnCreated failed: " + ex.Message);
			}
		}
	}
	[SourceNotice("RVRepairVan by DooDesch, MIT License. Please read and reuse the source code at https://github.com/DooDesch-Mods/ScheduleOne-RVRepairVan, not decompiled code.")]
	internal static class Questline
	{
		private const int None = 0;

		private const int Started = 1;

		private const int AskedDonna = 2;

		private const int MingErrand = 3;

		private const int MingCrate = 4;

		private const int Referred = 5;

		private const int MarcoMet = 6;

		private const int ReadyToPay = 7;

		private const int Trusted = 8;

		private const int Paid = 9;

		private const int Done = 10;

		private const int BuildOutsAsked = 11;

		private const string DonnaId = "donna_martin";

		private const string MingId = "ming";

		internal const string MarcoId = "marco_baron";

		private const string MarcoSayName = "rv_marco_say";

		private const string MingSayName = "rv_ming_say";

		private const string MoreEngineName = "rv_marco_more_engine";

		private const int BuildOutTickDelay = 5;

		private const string CrateId = "rv_ming_crate";

		private const string PackageId = "rv_marco_package";

		private const int LostPackageFee = 500;

		private const string MingAngry = "You lose my crate? Not very good. Five hundred, then we are okay, yes?";

		private const string MingPaid = "Very good. Now go see Marco at the docks, tell him Ming sends you.";

		private const string MingShort = "Okay. You bring money, yes?";

		private const string MarcoAngry = "You lost it? Well, that's gonna cost ya. Five hundred and we're even.";

		private const string MarcoPaid = "Pleasure doing business. Now, bring me packaged product in your hand, and every piece comes off your bill.";

		private const string MarcoShort = "I'll be here.";

		private const int DEGRADED_AFTER_ATTEMPTS = 15;

		private static bool _donnaDone;

		private static bool _mingDone;

		private static bool _marcoDone;

		private static bool _pickupActive;

		private static bool _hasPackage;

		private static Vector3 _dropPoint;

		private static DeadDropInstance _drop;

		private static Vector3 _cratePoint;

		private static DeadDropInstance _crateDrop;

		private static bool _cratePlaced;

		private static bool _pkgPlaced;

		private static bool _itemsRegistered;

		private static bool _clientCheckedRv;

		private static bool _errandRestored;

		private static int _gen;

		private static Conversation _marcoSay;

		private static Conversation _mingSay;

		private static Conversation _marcoQuote;

		private static Conversation _marcoMoreEngine;

		private static Transform _donnaT;

		private static Transform _mingT;

		private static Transform _marcoT;

		private static DialogueController _donnaDC;

		private static DialogueController _mingDC;

		private static DialogueController _marcoDC;

		private static int _injectedChoices;

		private static int _skippedChoices;

		private static DialogueChoice _marcoRepairChoice;

		private static readonly RvUpgrade[] UpgradeOrder = new RvUpgrade[3]
		{
			RvUpgrade.CrewQuarters,
			RvUpgrade.LoadingDock,
			RvUpgrade.Engine
		};

		private static readonly DialogueChoice[] _upgradeChoices = (DialogueChoice[])(object)new DialogueChoice[UpgradeOrder.Length];

		internal const int MarcoPriorityTop = -100;

		private const int MAX_SAMPLE_CHOICES = 1;

		private static readonly DialogueChoice[] _sampleChoices = (DialogueChoice[])(object)new DialogueChoice[1];

		private static readonly List<ItemSlot> _sampleSlots = new List<ItemSlot>();

		private static bool _itemsDumped;

		private static bool _netWired;

		private static int Stage
		{
			get
			{
				return RepairStateStore.GetStage();
			}
			set
			{
				RepairStateStore.SetStage(value);
				if (NetworkBus.Online && NetworkBus.IsServer)
				{
					NetworkBus.BroadcastToAll(RvOp.StageSync, value, DiscountTotal);
				}
			}
		}

		private static int Samples
		{
			get
			{
				return RepairStateStore.GetSamples();
			}
			set
			{
				RepairStateStore.SetSamples(value);
			}
		}

		private static int DiscountTotal
		{
			get
			{
				return RepairStateStore.GetDiscountTotal();
			}
			set
			{
				RepairStateStore.SetDiscountTotal(value);
				if (NetworkBus.Online && NetworkBus.IsServer)
				{
					NetworkBus.BroadcastToAll(RvOp.StageSync, Stage, value);
				}
			}
		}

		private static bool ReferralUsed => Stage >= 7;

		private static bool Trusted_ => Stage >= 8;

		private static bool Active
		{
			get
			{
				if (RVRepairVanPreferences.Enabled)
				{
					if (!RVManager.IsDestroyed())
					{
						if (NetworkBus.Online && !NetworkBus.IsServer && Stage >= 1)
						{
							return Stage < 9;
						}
						return false;
					}
					return true;
				}
				return false;
			}
		}

		internal static int StageForLoad(bool repaired, int stage)
		{
			if (!repaired || stage < 1 || stage >= 9)
			{
				return stage;
			}
			Core.Log.Msg("[Questline] save has a repaired RV at stage " + stage + " - loading it as finished.");
			return 10;
		}

		internal static int CurrentPrice()
		{
			int num = (ReferralUsed ? RVRepairVanPreferences.BasePriceWithReferral : RVRepairVanPreferences.BasePriceNoReferral);
			return Mathf.Max(RVRepairVanPreferences.RepairPrice, num - DiscountTotal);
		}

		private static bool ExplosionBeatPassed()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Invalid comparison between Unknown and I4
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Invalid comparison between Unknown and I4
			try
			{
				Quest quest = Quest.GetQuest("Getting Started");
				if ((Object)(object)quest != (Object)null && ((int)quest.State == 1 || (int)quest.State == 2))
				{
					return true;
				}
				Quest quest2 = Quest.GetQuest("Welcome to Hyland Point");
				if ((Object)(object)quest2 != (Object)null && (int)quest2.State == 2)
				{
					return true;
				}
			}
			catch (Exception e)
			{
				Core.Swallowed("Questline.ExplosionBeatPassed", e);
			}
			return false;
		}

		internal static void Reset()
		{
			//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_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)
			_gen++;
			ResetDiag();
			_donnaDone = (_mingDone = (_marcoDone = false));
			_pickupActive = false;
			_hasPackage = false;
			_clientCheckedRv = false;
			_errandRestored = false;
			_marcoSay = (_mingSay = (_marcoQuote = (_marcoMoreEngine = null)));
			QuestSteps.ResetScene();
			_drop = null;
			_crateDrop = null;
			_cratePlaced = (_pkgPlaced = false);
			_dropPoint = Vector3.zero;
			_cratePoint = Vector3.zero;
			_donnaT = (_mingT = (_marcoT = null));
			_donnaDC = (_mingDC = (_marcoDC = null));
			_injectedChoices = (_skippedChoices = 0);
			_marcoRepairChoice = null;
			Array.Clear(_upgradeChoices, 0, _upgradeChoices.Length);
			Array.Clear(_sampleChoices, 0, _sampleChoices.Length);
			_sampleSlots.Clear();
			RepairStateStore.ResetClient();
			RvBattery.ResetClient();
		}

		internal static void Start()
		{
			InitNet();
			MelonCoroutines.Start(EnsureItemsCoroutine());
			MelonCoroutines.Start(SetupCoroutine());
			MelonCoroutines.Start(ProximityCoroutine());
			MelonCoroutines.Start(RestoreCoroutine());
			MelonCoroutines.Start(NetJoinCoroutine());
		}

		private static IEnumerator RestoreCoroutine()
		{
			yield return (object)new WaitForSeconds(4f);
			if (NetworkBus.Online && !NetworkBus.IsServer)
			{
				yield break;
			}
			try
			{
				if (RVRepairVanPreferences.Enabled && Stage >= 1 && Stage < 10)
				{
					EnsureQuest();
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Questline] restore failed: " + ex.Message);
			}
		}

		private static IEnumerator SetupCoroutine()
		{
			int myGen = _gen;
			int attempt = 0;
			bool reported = false;
			while (myGen == _gen && (!_donnaDone || !_mingDone || !_marcoDone))
			{
				yield return (object)new WaitForSeconds((attempt < 20) ? 2f : 10f);
				attempt++;
				TryInject(attempt >= 15);
				if (!reported && attempt >= 20)
				{
					reported = true;
				}
			}
			if (myGen != _gen)
			{
				yield break;
			}
			try
			{
				if ((!NetworkBus.Online || NetworkBus.IsServer) && RVRepairVanPreferences.Enabled && Stage >= 1 && Stage < 10)
				{
					EnsureQuest();
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Questline] post-inject POI sync failed: " + ex.Message);
			}
		}

		private static void TryInject(bool degraded = false)
		{
			try
			{
				if (!_donnaDone)
				{
					_donnaDone = TryOne("donna_martin", out _donnaT, ref _donnaDC, InjectDonna, degraded);
				}
				if (!_mingDone)
				{
					_mingDone = TryOne("ming", out _mingT, ref _mingDC, InjectMing, degraded);
				}
				if (!_marcoDone)
				{
					_marcoDone = TryOne("marco_baron", out _marcoT, ref _marcoDC, InjectMarco, degraded);
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Questline] inject attempt failed: " + ex.Message);
			}
		}

		private static bool TryOne(string id, out Transform t, ref DialogueController held, Func<DialogueController, NPC, bool, bool> inject, bool degraded)
		{
			NPC val = FindNpc(id);
			DialogueController val2 = ControllerOf(val, out t);
			if ((Object)(object)val2 != (Object)null && inject(val2, val, degraded))
			{
				held = val2;
				if (degraded)
				{
					Core.Log.Warning("[Questline] '" + id + "' injected WITHOUT its dialogue containers - the questline works but replies show as floating lines instead of in-conversation menus.");
				}
				return true;
			}
			return false;
		}

		private static bool InjectDonna(DialogueController donna, NPC npc, bool degraded)
		{
			Conversation val = S1Container(npc, "rv_donna", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", L10n.T("I run a motel, not a garage. Try Mrs. Ming at the Chinese restaurant, ok? She knows people."), (Action<ChoiceList>)null);
			});
			if ((Object)(object)val == (Object)null && !degraded)
			{
				return false;
			}
			AddChoice(donna, L10n.T("My RV got blown up. Know anyone who can fix it?"), 90, () => Active && Stage == 1, OnAskDonna, val);
			return true;
		}

		private static bool InjectMing(DialogueController ming, NPC npc, bool degraded)
		{
			Conversation val = S1Container(npc, "rv_ming_offer", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", L10n.T("Oh yes! Marco, at the docks. Very good mechanic. But first you do small favor for me, yes? Crate in a dead drop. You bring it here, I call Marco."), (Action<ChoiceList>)delegate(ChoiceList c)
				{
					c.Add("MING_ACCEPT", L10n.T("I'll get it."), "MING_ACCEPTED").Add("MING_DEFER", L10n.T("Not now."), "MING_DEFERRED");
				}).AddNode("MING_ACCEPTED", L10n.T("Very good! And do not open, yes?"), (Action<ChoiceList>)null).AddNode("MING_DEFERRED", L10n.T("Okay. You come back when ready."), (Action<ChoiceList>)null);
			});
			Conversation val2 = S1Container(npc, "rv_ming_deliver", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", L10n.T("Very good! You are careful. I like careful. I call Marco now. Go see him at the docks, tell him Ming sends you."), (Action<ChoiceList>)null);
			});
			Conversation val3 = S1Container(npc, "rv_ming_lost", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", L10n.T("You lose my crate? Not very good. Five hundred, then we are okay, yes?"), (Action<ChoiceList>)delegate(ChoiceList c)
				{
					c.Add("MING_PAY", L10n.T("Pay ${0}", 500), (string)null).Add("MING_DEFER_LOSS", L10n.T("I'll come back with the money."), "MING_LOSS_DEFER");
				}).AddNode("MING_LOSS_DEFER", L10n.T("Okay. You bring money, yes?"), (Action<ChoiceList>)null);
			});
			_mingSay = S1Container(npc, "rv_ming_say", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", "...", (Action<ChoiceList>)null);
			});
			if (!degraded && ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)_mingSay == (Object)null))
			{
				return false;
			}
			OnPick(npc, "MING_ACCEPT", OnAcceptErrand);
			AddChoice(ming, L10n.T("Donna says you know someone who can fix my RV."), 92, () => Active && Stage == 2, ((Object)(object)val != (Object)null) ? null : ((Action)delegate
			{
				WorldSay(_mingT, L10n.T("Oh yes! Marco, at the docks. Very good mechanic. But first you do small favor for me, yes? Crate in a dead drop. You bring it here, I call Marco."));
				OnAcceptErrand();
			}), val);
			AddChoice(ming, L10n.T("Here's your crate."), 91, () => Active && Stage == 4 && PlayerHasItem("rv_ming_crate"), OnDeliverCrate, val2);
			OnPick(npc, "MING_PAY", OnMingPayLoss);
			AddChoice(ming, ((Object)(object)val3 != (Object)null) ? L10n.T("I lost your crate.") : L10n.T("I lost your crate. (Pay ${0})", 500), 90, () => Active && Stage == 4 && !PlayerHasItem("rv_ming_crate"), ((Object)(object)val3 != (Object)null) ? null : ((Action)delegate
			{
				WorldSay(_mingT, L10n.T("You lose my crate? Not very good. Five hundred, then we are okay, yes?"));
				OnMingPayLoss();
			}), val3);
			return true;
		}

		private static bool InjectMarco(DialogueController marco, NPC npc, bool degraded)
		{
			Conversation val = S1Container(npc, "rv_marco_favour", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", L10n.T("Tell ya what. There's a package of mine in a dead drop. Bring it here and we'll talk."), (Action<ChoiceList>)null);
			});
			Conversation val2 = S1Container(npc, "rv_marco_gotpkg", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", L10n.T("Much obliged. Here's the deal: bring me packaged product in your hand, and every piece comes off your bill."), (Action<ChoiceList>)null);
			});
			Conversation val3 = S1Container(npc, "rv_marco_lost", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", L10n.T("You lost it? Well, that's gonna cost ya. Five hundred and we're even."), (Action<ChoiceList>)delegate(ChoiceList c)
				{
					c.Add("MARCO_PAY", L10n.T("Pay ${0}", 500), (string)null).Add("MARCO_DEFER_LOSS", L10n.T("I'll come back with the money."), "MARCO_LOSS_DEFER");
				}).AddNode("MARCO_LOSS_DEFER", L10n.T("I'll be here."), (Action<ChoiceList>)null);
			});
			Conversation val4 = S1Container(npc, "rv_marco_bring", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", BringInfoLine(), (Action<ChoiceList>)null);
			});
			_marcoSay = S1Container(npc, "rv_marco_say", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", "...", (Action<ChoiceList>)null);
			});
			_marcoQuote = S1Container(npc, "rv_marco_quote", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", "...", (Action<ChoiceList>)delegate(ChoiceList c)
				{
					c.Add("MARCO_QUOTE_REPAIR", "...", (string)null).Add("MARCO_QUOTE_LOWER", L10n.T("Can you go any lower?"), "MARCO_QUOTE_FAVOUR").Add("MARCO_QUOTE_LATER", L10n.T("Later."), "MARCO_QUOTE_BYE");
				}).AddNode("MARCO_QUOTE_FAVOUR", L10n.T("Tell ya what. There's a package of mine in a dead drop. Bring it here and we'll talk."), (Action<ChoiceList>)null).AddNode("MARCO_QUOTE_BYE", L10n.T("I'll be here."), (Action<ChoiceList>)null);
			});
			_marcoMoreEngine = S1Container(npc, "rv_marco_more_engine", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", L10n.T("I can't work on her where she sits. Get the engine in first, then drive her over."), (Action<ChoiceList>)delegate(ChoiceList c)
				{
					c.Add("MARCO_MORE_ENGINE", "...", (string)null).Add("MARCO_MORE_LATER", L10n.T("Later."), "MARCO_MORE_BYE");
				}).AddNode("MARCO_MORE_BYE", L10n.T("I'll be here."), (Action<ChoiceList>)null);
			});
			if (!degraded && ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null || (Object)(object)_marcoSay == (Object)null || (Object)(object)_marcoQuote == (Object)null || (Object)(object)_marcoMoreEngine == (Object)null))
			{
				return false;
			}
			OnPick(npc, "MARCO_QUOTE_REPAIR", OnMarcoRepair);
			OnPick(npc, "MARCO_QUOTE_LOWER", OnMarcoFavour);
			OnPick(npc, "MARCO_MORE_ENGINE", delegate
			{
				RvUpgrades.Buy(RvUpgrade.Engine);
			});
			AddChoice(marco, L10n.T("Mrs. Ming sent me. Can you fix my RV?"), -100, () => Active && (Stage == 5 || Stage == 6), delegate
			{
				PrepareQuote();
				OnMarcoReferral();
			}, _marcoQuote);
			_marcoRepairChoice = AddChoice(marco, RepairChoiceText(), -103, () => Active && ReferralUsed && Stage < 9, OnMarcoRepair);
			AddChoice(marco, L10n.T("Can you go any lower?"), -104, () => Active && Stage == 7 && !_pickupActive, OnMarcoFavour, val);
			AddChoice(marco, L10n.T("Can you go any lower?"), -104, () => Active && Trusted_ && Stage < 9 && HeldPackagedSlot() == null && CurrentPrice() > RVRepairVanPreferences.RepairPrice, ((Object)(object)val4 != (Object)null) ? null : ((Action)delegate
			{
				WorldSay(_marcoT, BringInfoLine());
			}), val4);
			AddChoice(marco, L10n.T("Here's your package."), -104, () => Active && _pickupActive && _hasPackage && PlayerHasItem("rv_marco_package"), OnGotPackage, val2);
			OnPick(npc, "MARCO_PAY", OnMarcoPayLoss);
			AddChoice(marco, ((Object)(object)val3 != (Object)null) ? L10n.T("I lost your package.") : L10n.T("I lost your package. (Pay ${0})", 500), -104, () => Active && _pickupActive && _hasPackage && !PlayerHasItem("rv_marco_package"), ((Object)(object)val3 != (Object)null) ? null : ((Action)delegate
			{
				WorldSay(_marcoT, L10n.T("You lost it? Well, that's gonna cost ya. Five hundred and we're even."));
				OnMarcoPayLoss();
			}), val3);
			for (int num = 0; num < 1; num++)
			{
				int idx = num;
				_sampleChoices[idx] = AddChoice(marco, L10n.T("Give Marco a packaged sample"), -105 - idx, () => SampleChoiceVisible(idx), delegate
				{
					OnGiveSample(idx);
				});
			}
			for (int num2 = 0; num2 < UpgradeOrder.Length; num2++)
			{
				RvUpgrade up = UpgradeOrder[num2];
				_upgradeChoices[num2] = AddChoice(marco, RvUpgrades.ChoiceText(up), -107 - num2, () => RvUpgrades.Available(up), delegate
				{
					RvUpgrades.Buy(up);
				});
			}
			AddChoice(marco, L10n.T("Can you do more to the RV?"), -111, () => RvGarage.AskMoreVisible(), OnMarcoMore);
			return true;
		}

		private static NPC FindNpc(string id)
		{
			try
			{
				List<NPC> nPCRegistry = NPCManager.NPCRegistry;
				if (nPCRegistry == null)
				{
					return null;
				}
				for (int i = 0; i < nPCRegistry.Count; i++)
				{
					NPC val = nPCRegistry[i];
					if ((Object)(object)val != (Object)null && string.Equals(val.ID, id, StringComparison.OrdinalIgnoreCase))
					{
						return val;
					}
				}
			}
			catch (Exception e)
			{
				Core.Swallowed("Questline.FindNpc", e);
			}
			return null;
		}

		internal static void GruntNpc(NPC npc)
		{
			try
			{
				if ((Object)(object)npc != (Object)null && (Object)(object)npc.VoiceOverEmitter != (Object)null)
				{
					npc.VoiceOverEmitter.Play((EVOLineType)9);
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Questline] grunt failed: " + ex.Message);
			}
		}

		private static Conversation S1Container(NPC npc, string name, Action<DialogueContainerBuilder> build)
		{
			try
			{
				if ((Object)(object)npc == (Object)null)
				{
					return null;
				}
				NPC val = NPC.Get(npc.ID);
				if (val == null)
				{
					return null;
				}
				val.Dialogue.BuildAndRegisterContainer(name, build);
				DialogueHandler dialogueHandler = npc.DialogueHandler;
				List<Conversation> val2 = (((Object)(object)dialogueHandler != (Object)null) ? dialogueHandler.dialogueContainers : null);
				if (val2 == null)
				{
					return null;
				}
				for (int i = 0; i < val2.Count; i++)
				{
					if ((Object)(object)val2[i] != (Object)null && ((Object)val2[i]).name == name)
					{
						return val2[i];
					}
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Questline] S1 container '" + name + "' failed: " + ex.Message);
			}
			return null;
		}

		private static void OnPick(NPC npc, string label, Action cb)
		{
			try
			{
				if (!((Object)(object)npc == (Object)null))
				{
					NPC obj = NPC.Get(npc.ID);
					if (obj != null)
					{
						obj.Dialogue.OnChoiceSelected(label, cb);
					}
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Questline] OnPick '" + label + "' failed: " + ex.Message);
			}
		}

		internal static void DumpNpcDiagnostics()
		{
			DumpState();
			try
			{
				List<NPC> nPCRegistry = NPCManager.NPCRegistry;
				if (nPCRegistry == null)
				{
					Core.Log.Msg("[NPC-DIAG] NPCRegistry == null");
					return;
				}
				string text = "";
				for (int i = 0; i < nPCRegistry.Count; i++)
				{
					NPC val = nPCRegistry[i];
					if (!((Object)(object)val == (Object)null))
					{
						try
						{
							text = text + val.ID + " ";
						}
						catch (Exception e)
						{
							Core.Swallowed("Questline.DumpNpcDiagnostics.ID", e);
							text += "(err) ";
						}
					}
				}
				Core.Log.Msg("[NPC-DIAG] registry(" + nPCRegistry.Count + "): " + text);
				DiagTarget("donna_martin");
				DiagTarget("ming");
				DiagTarget("marco_baron");
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[NPC-DIAG] dump failed: " + ex.Message);
			}
		}

		internal static void DumpState()
		{
			try
			{
				Core.Log.Msg("[STATE] Enabled=" + RVRepairVanPreferences.Enabled + " Questline=" + RVRepairVanPreferences.QuestlineEnabled + " Stage=" + Stage + " Samples=" + Samples + " Discount=" + DiscountTotal + " Active(IsDestroyed)=" + Active + " ExplosionBeatPassed=" + ExplosionBeatPassed());
				LogQuest("Getting Started");
				LogQuest("Welcome to Hyland Point");
				try
				{
					Core.Log.Msg("[STATE] S1API NPC.All count = " + NPC.All.Count);
				}
				catch (Exception ex)
				{
					Core.Log.Msg("[STATE] S1API NPC.All threw: " + ex.Message);
				}
			}
			catch (Exception ex2)
			{
				Core.Log.Warning("[STATE] dump failed: " + ex2.Message);
			}
		}

		private static void LogQuest(string name)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Quest quest = Quest.GetQuest(name);
				Core.Log.Msg("[STATE] Quest '" + name + "': " + (((Object)(object)quest == (Object)null) ? "NOT FOUND" : ("state=" + ((object)quest.State/*cast due to .constrained prefix*/).ToString())));
			}
			catch (Exception ex)
			{
				Core.Log.Msg("[STATE] Quest '" + name + "' lookup threw: " + ex.Message);
			}
		}

		private static void DiagTarget(string id)
		{
			NPC val = FindNpc(id);
			if ((Object)(object)val == (Object)null)
			{
				Core.Log.Msg("[NPC-DIAG] " + id + ": NOT in registry");
				return;
			}
			string text = "?";
			bool flag = false;
			bool flag2 = false;
			try
			{
				text = ((Object)((Component)val).gameObject).name;
				flag = ((Component)val).gameObject.activeInHierarchy;
			}
			catch (Exception e)
			{
				Core.Swallowed("Questline.DiagTarget.gameObject", e);
			}
			try
			{
				flag2 = (Object)(object)ControllerOf(val, out var _) != (Object)null;
			}
			catch (Exception e2)
			{
				Core.Swallowed("Questline.DiagTarget.controller", e2);
			}
			Core.Log.Msg("[NPC-DIAG] " + id + ": IN registry, go='" + text + "' active=" + flag + " controllerFound=" + flag2);
		}

		private static void ResetDiag()
		{
		}

		private static DialogueController ControllerOf(NPC npc, out Transform t)
		{
			t = null;
			if ((Object)(object)npc == (Object)null)
			{
				return null;
			}
			try
			{
				t = ((Component)npc).transform;
				DialogueHandler dialogueHandler = npc.DialogueHandler;
				DialogueController val = null;
				if ((Object)(object)dialogueHandler != (Object)null)
				{
					val = ((Component)dialogueHandler).GetComponentInChildren<DialogueController>(true);
				}
				if ((Object)(object)val == (Object)null)
				{
					val = ((Component)npc).GetComponentInChildren<DialogueController>(true);
				}
				return val;
			}
			catch (Exception e)
			{
				Core.Swallowed("Questline.ControllerOf", e);
				return null;
			}
		}

		private static void OnAskDonna()
		{
			if (!RouteIntent(RvOp.AskDonna) && Stage == 1)
			{
				Stage = 2;
				SyncEntry();
			}
		}

		private static void OnAcceptErrand()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: 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)
			if (!RouteIntent(RvOp.AcceptErrand) && Stage == 2)
			{
				Stage = 3;
				_crateDrop = ReserveDeadDrop(((Object)(object)_mingT != (Object)null) ? _mingT.position : RvPos());
				_cratePoint = ((_crateDrop != null) ? _crateDrop.Position : (((Object)(object)_mingT != (Object)null) ? (_mingT.position + new Vector3(8f, 0f, 8f)) : RvPos()));
				_cratePlaced = PlaceItem(_crateDrop, "rv_ming_crate");
				SyncEntry();
			}
		}

		private static void OnDeliverCrate()
		{
			RemovePlayerItem("rv_ming_crate");
			if (!RouteIntent(RvOp.DeliverCrate))
			{
				HostDeliverCrate();
			}
		}

		private static void HostDeliverCrate()
		{
			if (Stage == 4)
			{
				Stage = 5;
				SyncEntry();
			}
		}

		private static void OnMingPayLoss()
		{
			if (NetworkBus.Online && !NetworkBus.IsServer)
			{
				int num = ClientPayment.Charge(500, "Ming's fee");
				if (num == 0)
				{
					ReplyMing(L10n.T("Okay. You bring money, yes?"));
					return;
				}
				NetworkBus.SendToHost(RvOp.MingPayLoss, 0, num, 500);
				ReplyMing(L10n.T("Very good. Now go see Marco at the docks, tell him Ming sends you."));
			}
			else
			{
				HostMingPayLoss(-1);
			}
		}

		private static bool HostMingPayLoss(int clientPaid)
		{
			if (Stage != 4)
			{
				return false;
			}
			if (clientPaid < 0)
			{
				if (Money.GetCashBalance() < 500f)
				{
					ReplyMing(L10n.T("Okay. You bring money, yes?"));
					return false;
				}
				Money.ChangeCashBalance(-500f, true, true);
			}
			else if (clientPaid != 500)
			{
				Core.Log.Warning("[Questline] Ming fee refused - client paid " + clientPaid + ", fee is " + 500 + ".");
				return false;
			}
			Stage = 5;
			if (clientPaid < 0)
			{
				ReplyMing(L10n.T("Very good. Now go see Marco at the docks, tell him Ming sends you."));
			}
			SyncEntry();
			return true;
		}

		private static void OnMarcoGreet()
		{
			OnMarcoReferral();
		}

		private static void OnMarcoReferral()
		{
			if (!RouteIntent(RvOp.MarcoReferral) && (Stage == 5 || Stage == 6))
			{
				Stage = 7;
				RefreshRepairChoice();
				if ((Object)(object)_marcoQuote == (Object)null)
				{
					WorldSay(_marcoT, QuoteLine(CurrentPrice()));
				}
				SyncEntry();
			}
		}

		private static string QuoteLine(int price)
		{
			return L10n.T("Ming sent ya? Well, any friend of hers. That RV's a burnt-out shell, buddy - another week and she'd have gone to the crusher. Normally that's {0}. For you, {1}.", MoneyManager.FormatAmount((float)RVRepairVanPreferences.BasePriceNoReferral, false, false), MoneyManager.FormatAmount((float)price, false, false));
		}

		private static void PrepareQuote()
		{
			if ((Object)(object)_marcoQuote == (Object)null)
			{
				return;
			}
			int num = Mathf.Max(RVRepairVanPreferences.RepairPrice, RVRepairVanPreferences.BasePriceWithReferral - DiscountTotal);
			DialogueNodeData dialogueNodeByLabel = _marcoQuote.GetDialogueNodeByLabel("ENTRY");
			if (dialogueNodeByLabel == null)
			{
				Core.Log.Warning("[Questline] Marco's quote has no ENTRY node - it opens with its placeholder.");
				return;
			}
			dialogueNodeByLabel.DialogueText = QuoteLine(num);
			if (dialogueNodeByLabel.choices != null && ((Il2CppArrayBase<DialogueChoiceData>)(object)dialogueNodeByLabel.choices).Length > 0)
			{
				((Il2CppArrayBase<DialogueChoiceData>)(object)dialogueNodeByLabel.choices)[0].ChoiceText = L10n.T("Repair it ({0})", MoneyManager.FormatAmount((float)num, false, false));
			}
		}

		private static void OnMarcoMore()
		{
			if ((Stage == 0 || Stage == 10) && !RouteIntent(RvOp.AskedBuildOuts))
			{
				HostAskedBuildOuts();
			}
			if (RvUpgrades.Owned(RvUpgrade.Engine) || !OpenMoreEngine())
			{
				ReplyMarco(RvGarage.AskMoreLine());
			}
		}

		private static bool OpenMoreEngine()
		{
			try
			{
				if ((Object)(object)_marcoMoreEngine == (Object)null)
				{
					return false;
				}
				DialogueNodeData dialogueNodeByLabel = _marcoMoreEngine.GetDialogueNodeByLabel("ENTRY");
				NPC val = NPC.Get("marco_baron");
				if (dialogueNodeByLabel == null || dialogueNodeByLabel.choices == null || ((Il2CppArrayBase<DialogueChoiceData>)(object)dialogueNodeByLabel.choices).Length == 0 || val == null)
				{
					Core.Log.Warning("[Questline] Marco's engine offer cannot open - he answers without it.");
					return false;
				}
				((Il2CppArrayBase<DialogueChoiceData>)(object)dialogueNodeByLabel.choices)[0].ChoiceText = RvUpgrades.ChoiceText(RvUpgrade.Engine);
				if (val.Dialogue.JumpTo("rv_marco_more_engine", "ENTRY", false))
				{
					return true;
				}
				Core.Log.Warning("[Questline] Marco's engine offer was refused by the dialogue - he answers without it.");
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Questline] Marco's engine offer failed: " + ex.Message);
			}
			return false;
		}

		private static string ShortLine(int price)
		{
			return L10n.T("That's {0}, buddy. Come back when you've got it.", MoneyManager.FormatAmount((float)price, false, false));
		}

		private static string BringInfoLine()
		{
			return L10n.T("Packaged product, buddy. Have it in your hand when you talk to me - every piece knocks up to {0} off the bill.", MoneyManager.FormatAmount((float)RVRepairVanPreferences.MaxSampleDiscount, false, false));
		}

		private static void OnMarcoRepair()
		{
			try
			{
				bool flag = NetworkBus.Online && !NetworkBus.IsServer;
				if (!flag && !RVManager.IsDestroyed())
				{
					ReplyMarco(L10n.T("Your RV looks fine to me."));
					return;
				}
				int num = CurrentPrice();
				if (Money.GetCashBalance() < (float)num)
				{
					ReplyMarco(ShortLine(num));
				}
				else if (flag)
				{
					int num2 = ClientPayment.Charge(num, "repair");
					if (num2 == 0)
					{
						ReplyMarco(ShortLine(num));
						return;
					}
					WorldSay(_marcoT, L10n.T("Alright, let me grab my tools."));
					NetworkBus.SendToHost(RvOp.PayRepair, 0, num2, num);
					RepairCinematic.Play(null, delegate
					{
						MarcoOpens(RepairStateStore.GetRepaired() ? RepairDoneLine() : BookedLine());
					}, delegate
					{
						GruntNpc(FindNpc("marco_baron"));
					});
				}
				else
				{
					HostPayRepair(withCinematic: true);
				}
			}
			catch (Exception ex)
			{
				Core.Log.Error("[Questline] repair failed: " + ex);
			}
		}

		private static string BookedLine()
		{
			return L10n.T("Alright, I'll send the boys over to your RV. Give me a day - I'll text ya when she's done.");
		}

		private static string RepairDoneLine()
		{
			if (!RVRepairVanPreferences.QuestlineEnabled)
			{
				return L10n.T("There she is, good as new. Try not to blow her up again, buddy.");
			}
			return L10n.T("There she is, good as new. Go take a look, and try not to blow her up again, buddy.");
		}

		private static void EnterPaid()
		{
			_pickupActive = false;
			_hasPackage = false;
			_drop = null;
			Stage = 9;
			SyncEntry();
		}

		private static void OnMarcoFavour()
		{
			//IL_0040: 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_0094: 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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			if (!RouteIntent(RvOp.MarcoFavour) && Stage == 7 && !_pickupActive)
			{
				_pickupActive = true;
				_hasPackage = false;
				_drop = ReserveDeadDrop(((Object)(object)_marcoT != (Object)null) ? _marcoT.position : RvPos());
				_dropPoint = ((_drop != null) ? _drop.Position : (((Object)(object)_marcoT != (Object)null) ? (_marcoT.position + new Vector3(10f, 0f, 10f)) : RvPos()));
				_pkgPlaced = PlaceItem(_drop, "rv_marco_package");
				SyncEntry();
			}
		}

		private static void OnGotPackage()
		{
			RemovePlayerItem("rv_marco_package");
			if (!RouteIntent(RvOp.GotPackage))
			{
				HostGotPackage();
			}
		}

		private static void HostGotPackage()
		{
			if (_pickupActive && _hasPackage)
			{
				_pickupActive = false;
				_hasPackage = false;
				_drop = null;
				Stage = 8;
				SyncEntry();
			}
		}

		private static void OnMarcoPayLoss()
		{
			if (NetworkBus.Online && !NetworkBus.IsServer)
			{
				int num = ClientPayment.Charge(500, "Marco's fee");
				if (num == 0)
				{
					ReplyMarco(L10n.T("I'll be here."));
					return;
				}
				NetworkBus.SendToHost(RvOp.MarcoPayLoss, 0, num, 500);
				ReplyMarco(L10n.T("Pleasure doing business. Now, bring me packaged product in your hand, and every piece comes off your bill."));
			}
			else
			{
				HostMarcoPayLoss(-1);
			}
		}

		private static bool HostMarcoPayLoss(int clientPaid)
		{
			if (!_pickupActive || !_hasPackage)
			{
				return false;
			}
			if (clientPaid < 0)
			{
				if (Money.GetCashBalance() < 500f)
				{
					ReplyMarco(L10n.T("I'll be here."));
					return false;
				}
				Money.ChangeCashBalance(-500f, true, true);
			}
			else if (clientPaid != 500)
			{
				Core.Log.Warning("[Questline] Marco fee refused - client paid " + clientPaid + ", fee is " + 500 + ".");
				return false;
			}
			_pickupActive = false;
			_hasPackage = false;
			_drop = null;
			Stage = 8;
			if (clientPaid < 0)
			{
				ReplyMarco(L10n.T("Pleasure doing business. Now, bring me packaged product in your hand, and every piece comes off your bill."));
			}
			SyncEntry();
			return true;
		}

		private static void OnGiveSample(int i)
		{
			try
			{
				RefreshSampleSlots();
				ItemSlot val = ((i >= 0 && i < _sampleSlots.Count) ? _sampleSlots[i] : HeldPackagedSlot());
				object obj;
				if (val == null)
				{
					obj = null;
				}
				else
				{
					ItemInstance itemInstance = val.ItemInstance;
					obj = ((itemInstance != null) ? ((Il2CppObjectBase)itemInstance).TryCast<ProductItemInstance>() : null);
				}
				ProductItemInstance val2 = (ProductItemInstance)obj;
				if (val2 == null || (Object)(object)val2.AppliedPackaging == (Object)null)
				{
					ReplyMarco(L10n.T("That ain't packaged, buddy. Bring it sealed."));
					return;
				}
				int num = SampleUnitDiscount(val2);
				string text = ThanksLine(val2, num);
				NPC val3 = FindNpc("marco_baron");
				if (val != null)
				{
					_ = val.Quantity;
				}
				if ((Object)(object)val3 != (Object)null && (Object)(object)val3.Behaviour != (Object)null)
				{
					val3.Behaviour.ConsumeProduct_Server(val2, false);
				}
				RemoveOneFromSlot(val);
				if (val != null)
				{
					_ = val.Quantity;
				}
				if (RouteIntent(RvOp.GiveSample, num))
				{
					ReplyMarco(text);
				}
				else
				{
					HostGiveSample(num, text);
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Questline] give sample failed: " + ex.Message);
			}
		}

		private static int SampleUnitDiscount(ProductItemInstance p)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			int num = Mathf.Max(1, ((BaseItemInstance)p).Quantity);
			return Mathf.Clamp(Mathf.RoundToInt(((BaseItemInstance)p).GetMonetaryValue() / (float)num * QualityMultiplier(((QualityItemInstance)p).Quality)), RVRepairVanPreferences.MinSampleDiscount, RVRepairVanPreferences.MaxSampleDiscount);
		}

		private static float QualityMultiplier(EQuality q)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected I4, but got Unknown
			return (int)q switch
			{
				0 => 0.6f, 
				1 => 0.8f, 
				3 => 1.5f, 
				4 => 2f, 
				_ => 1f, 
			};
		}

		private static void RefreshSampleSlots()
		{
			_sampleSlots.Clear();
			ItemSlot val = HeldPackagedSlot();
			if (val != null)
			{
				_sampleSlots.Add(val);
			}
		}

		private static bool SampleChoiceVisible(int i)
		{
			if (!Active || !Trusted_ || Stage >= 9 || CurrentPrice() <= RVRepairVanPreferences.RepairPrice)
			{
				return false;
			}
			RefreshSampleSlots();
			if (i >= _sampleSlots.Count)
			{
				return false;
			}
			ItemSlot obj = _sampleSlots[i];
			object obj2;
			if (obj == null)
			{
				obj2 = null;
			}
			else
			{
				ItemInstance itemInstance = obj.ItemInstance;
				obj2 = ((itemInstance != null) ? ((Il2CppObjectBase)itemInstance).TryCast<ProductItemInstance>() : null);
			}
			ProductItemInstance val = (ProductItemInstance)obj2;
			if (val == null)
			{
				return false;
			}
			if (_sampleChoices[i] != null)
			{
				_sampleChoices[i].ChoiceText = SampleChoiceText(val);
			}
			return true;
		}

		private static string SampleChoiceText(ProductItemInstance p)
		{
			string text = L10n.T("product");
			try
			{
				ItemDefinition definition = ((ItemInstance)p).Definition;
				if ((Object)(object)definition != (Object)null)
				{
					text = ((BaseItemDefinition)definition).Name;
				}
			}
			catch (Exception e)
			{
				Core.Swallowed("Questline.SampleChoiceText", e);
			}
			return L10n.T("Give Marco: {0} (-{1})", text, MoneyManager.FormatAmount((float)SampleUnitDiscount(p), false, false));
		}

		private static void HostGiveSample(int discount, string thanks = null)
		{
			Samples++;
			DiscountTotal += discount;
			RefreshRepairChoice();
			if (thanks != null)
			{
				ReplyMarco(thanks);
			}
			SyncEntry();
		}

		private static string ThanksLine(ProductItemInstance p, int discount)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Invalid comparison between Unknown and I4
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Invalid comparison between Unknown and I4
			string text = MoneyManager.FormatAmount((float)discount, false, false);
			try
			{
				ProductDefinition val = (((Object)(object)((ItemInstance)p).Definition != (Object)null) ? ((Il2CppObjectBase)((ItemInstance)p).Definition).TryCast<ProductDefinition>() : null);
				if ((Object)(object)val != (Object)null && (int)val.DrugType == 1 && (int)((QualityItemInstance)p).Quality >= 3)
				{
					return L10n.T("Ninety-nine percent pure? Where'd you learn chemistry, buddy? That's {0} off.", text);
				}
			}
			catch (Exception e)
			{
				Core.Swallowed("Questline.ThanksLine", e);
			}
			return L10n.T("Thanks, buddy. That's {0} off.", text);
		}

		private static DeadDropInstance ReserveDeadDrop(Vector3 origin)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				DeadDropInstance[] array = DeadDropManager.Empty;
				if (array == null || array.Length == 0)
				{
					array = DeadDropManager.All;
				}
				if (array == null || array.Length == 0)
				{
					return null;
				}
				DeadDropInstance result = null;
				float num = -1f;
				foreach (DeadDropInstance val in array)
				{
					if (val != null)
					{
						float num2 = Vector3.Distance(origin, val.Position);
						if (num2 > num)
						{
							num = num2;
							result = val;
						}
					}
				}
				return result;
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Questline] reserve dead drop failed: " + ex.Message);
				return null;
			}
		}

		private static void EnsureItems()
		{
			if (_itemsRegistered)
			{
				return;
			}
			try
			{
				if (!(ItemManager.GetDefinition("grainbag") == (ItemDefinition)null))
				{
					RegisterItem("rv_ming_crate", L10n.T("Mrs. Ming's Crate"), L10n.T("A sealed crate for Mrs. Ming, stamped 'Golden Moth Chemical'. Don't open it."), new string[3] { "grainbag", "trashbag", "flashlight" });
					RegisterItem("rv_marco_package", L10n.T("Marco's Package"), L10n.T("Marco's package. Smells like fried chicken. Bring it to him at the docks."), new string[3] { "trashbag", "grainbag", "flashlight" });
					_itemsRegistered = true;
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Questline] item register failed: " + ex.Message);
			}
		}

		private static IEnumerator EnsureItemsCoroutine()
		{
			for (int i = 0; i < 30; i++)
			{
				if (_itemsRegistered)
				{
					break;
				}
				EnsureItems();
				if (_itemsRegistered)
				{
					break;
				}
				yield return (object)new WaitForSeconds(1f);
			}
		}

		private static void RegisterItem(string id, string name, string desc, string[] baseIds)
		{
			if (ItemManager.GetDefinition(id) != (ItemDefinition)null)
			{
				return;
			}
			StorableItemDefinition val = null;
			foreach (string text in baseIds)
			{
				try
				{
					val = ((StorableItemDefinitionBuilderBase<StorableItemDefinitionBuilder>)(object)((StorableItemDefinitionBuilderBase<StorableItemDefinitionBuilder>)(object)ItemCreator.CloneFrom(text)).WithBasicInfo(id, name, desc, (ItemCategory)3)).WithStackLimit(1).Build();
				}
				catch (Exception ex)
				{
					Instance log = Core.Log;
					if (log != null)
					{
						log.Warning("[Questline] CloneFrom('" + text + "') failed: " + ex.Message);
					}
					continue;
				}
				break;
			}
			if ((ItemDefinition)(object)val == (ItemDefinition)null)
			{
				val = ItemCreator.CreateItem(id, name, desc, (ItemCategory)3, 1, 10f, 0.5f, (LegalStatus)0, (FullRank?)null, (Sprite)null, (Equippable)null);
				Core.Log.Warning("[Questline] quest item '" + id + "' registered WITHOUT a model/icon (no clone base usable).");
			}
			try
			{
				ItemManager.PreserveRuntimeItem((ItemDefinition)(object)val);
			}
			catch (Exception e)
			{
				Core.Swallowed("Questline.RegisterItem", e);
			}
		}

		[Conditional("DEBUG")]
		private static void DumpItemsOnce()
		{
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			if (_itemsDumped)
			{
				return;
			}
			_itemsDumped = true;
			try
			{
				List<ItemDefinition> allItemDefinitions = ItemManager.GetAllItemDefinitions();
				Core.Log.Msg("[ITEMDUMP] " + (allItemDefinitions?.Count ?? 0) + " registered items:");
				if (allItemDefinitions == null)
				{
					return;
				}
				for (int i = 0; i < allItemDefinitions.Count; i++)
				{
					ItemDefinition val = allItemDefinitions[i];
					if (!(val == (ItemDefinition)null))
					{
						try
						{
							Core.Log.Msg("[ITEMDUMP] id='" + val.ID + "' name='" + val.Name + "' cat=" + ((object)val.Category/*cast due to .constrained prefix*/).ToString() + " icon=" + ((Object)(object)val.Icon != (Object)null));
						}
						catch (Exception e)
						{
							Core.Swallowed("Questline.DumpItemsOnce", e);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[ITEMDUMP] failed: " + ex.Message);
			}
		}

		private static DeadDropInstance AdoptOrPlace(string id, Vector3 origin, out bool placed)
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			if (PlayerHasItem(id))
			{
				placed = true;
				return null;
			}
			DeadDropInstance val = null;
			try
			{
				DeadDropInstance[] all = DeadDropManager.All;
				int num = 0;
				while (all != null && num < all.Length)
				{
					DeadDropInstance val2 = all[num];
					if (val2 != null && !val2.IsEmpty)
					{
						int num2 = val2.Storage.RemoveAllOfDefinition(id);
						if (num2 > 0)
						{
							Core.Log.Msg("[Questline] '" + id + "' found in drop '" + val2.Name + "' (" + num2 + ")" + ((val == null) ? "." : " - extra copy removed."));
							if (val == null)
							{
								val = val2;
							}
						}
					}
					num++;
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Questline] looking for '" + id + "' in the drops failed: " + ex.Message);
			}
			DeadDropInstance val3 = val ?? ReserveDeadDrop(origin);
			placed = PlaceItem(val3, id);
			return val3;
		}

		private static bool PlaceItem(DeadDropInstance drop, string id)
		{
			try
			{
				if (drop == null)
				{
					return false;
				}
				EnsureItems();
				ItemDefinition definition = ItemManager.GetDefinition(id);
				if (definition == (ItemDefinition)null)
				{
					return false;
				}
				drop.Storage.AddItem(definition.CreateInstance(1));
				return true;
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Questline] place item failed: " + ex.Message);
				return false;
			}
		}

		private static bool PlayerHasItem(string id)
		{
			try
			{
				PlayerInventory instance = PlayerSingleton<PlayerInventory>.Instance;
				List<HotbarSlot> val = (((Object)(object)instance != (Object)null) ? instance.hotbarSlots : null);
				if (val == null)
				{
					return false;
				}
				for (int i = 0; i < val.Count; i++)
				{
					ItemSlot val2 = (ItemSlot)(object)val[i];
					ItemInstance val3 = ((val2 != null) ? val2.ItemInstance : null);
					if (val3 != null && string.Equals(((BaseItemInstance)val3).ID, id, StringComparison.OrdinalIgnoreCase))
					{
						return true;
					}
				}
			}
			catch (Exception e)
			{
				Core.Swallowed("Questline.PlayerHasItem", e);
			}
			return false;
		}

		private static void RemovePlayerItem(string id)
		{
			try
			{
				PlayerInventory instance = PlayerSingleton<PlayerInventory>.Instance;
				List<HotbarSlot> val = (((Object)(object)instance != (Object)null) ? instance.hotbarSlots : null);
				if (val == null)
				{
					Core.Log.Warning("[Questline] remove '" + id + "': no hotbar slots.");
					return;
				}
				for (int i = 0; i < val.Count; i++)
				{
					ItemSlot val2 = (ItemSlot)(object)val[i];
					ItemInstance val3 = ((val2 != null) ? val2.ItemInstance : null);
					if (val3 != null && string.Equals(((BaseItemInstance)val3).ID, id, StringComparison.OrdinalIgnoreCase))
					{
						RemoveOneFromSlot(val2);
						return;
					}
				}
				Core.Log.Warning("[Questline] remove '" + id + "': not found in hotbar.");
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Questline] remove item failed: " + ex.Message);
			}
		}

		private static void RemoveOneFromSlot(ItemSlot slot)
		{
			if (slot != null)
			{
				ItemInstance itemInstance = slot.ItemInstance;
				if (((itemInstance != null) ? ((BaseItemInstance)itemInstance).Quantity : 0) > 1)
				{
					slot.ChangeQuantity(-1, false);
				}
				else
				{
					slot.ClearStoredInstance(false);
				}
			}
		}

		private static IEnumerator ProximityCoroutine()
		{
			int myGen = _gen;
			int waitedForLoad = 0;
			int loadedTicks = 0;
			while (myGen == _gen)
			{
				yield return (object)new WaitForSeconds(1f);
				int num;
				if (!RepairSave.Loaded)
				{
					num = waitedForLoad + 1;
					waitedForLoad = num;
					if (num < 10)
					{
						continue;
					}
					if (waitedForLoad == 10)
					{
						Core.Log.Warning("[Questline] save state not loaded after 10s - proceeding with current values.");
					}
				}
				num = loadedTicks + 1;
				loadedTicks = num;
				if (num >= 5)
				{
					try
					{
						BuildOutQuest.Tick(Stage == 0 || Stage >= 10, Stage >= 11);
					}
					catch (Exception ex)
					{
						Core.Log.Warning("[Quest] build-out tick failed: " + ex.Message);
					}
				}
				if (NetworkBus.Online && !NetworkBus.IsServer)
				{
					if (Stage == 9 && RepairStateStore.GetRepaired() && !_clientCheckedRv && RVManager.TryGetPosition(out var position) && Dist(PlayerPos(), position) < 14f)
					{
						_clientCheckedRv = true;
						NetworkBus.SendToHost(RvOp.CheckedRv);
					}
					else if ((Stage == 3 && PlayerHasItem("rv_ming_crate")) || (_pickupActive && !_hasPackage && PlayerHasItem("rv_marco_package")))
					{
						NetworkBus.SendToHost(RvOp.ErrandItemPicked);
					}
					continue;
				}
				if (!_errandRestored)
				{
					RestorePackageErrand();
				}
				if (RVRepairVanPreferences.Enabled && Stage == 0 && !RepairStateStore.GetRepaired() && RVManager.IsDestroyed() && ExplosionBeatPassed())
				{
					Stage = 1;
					EnsureQuest();
					Core.Log.Msg("[Questline] quest started (wrecked RV + explosion beat passed).");
				}
				if (Stage == 9 && RVManager.TryGetPosition(out var position2) && Dist(PlayerPos(), position2) < 14f)
				{
					HostCheckedRv();
				}
				if (RepairStateStore.GetRepaired() && !RvRepairJob.JobRunning)
				{
					if (Stage >= 1 && Stage < 9)
					{
						Core.Log.Msg("[Questline] RV is already repaired at stage " + Stage + " - finishing the story.");
						Stage = 10;
					}
					if (Stage >= 10 && RepairQuest.HasOpenEntry())
					{
						Core.Log.Msg("[Questline] story is finished but the journal entry is still open - closing it.");
						RepairQuest.CompleteIfActive();
					}
				}
				if (!Active)
				{
					continue;
				}
				try
				{
					Vector3 a = PlayerPos();
					if (Stage == 3)
					{
						if (_cratePoint == Vector3.zero && (Object)(object)_mingT != (Object)null)
						{
							_crateDrop = AdoptOrPlace("rv_ming_crate", _mingT.position, out _cratePlaced);
							_cratePoint = ((_crateDrop != null) ? _crateDrop.Position : (_mingT.position + new Vector3(8f, 0f, 8f)));
							SyncEntry();
						}
						if (_cratePlaced ? PlayerHasItem("rv_ming_crate") : (_cratePoint != Vector3.zero && Dist(a, _cratePoint) < 5f))
						{
							Stage = 4;
							SyncEntry();
						}
					}
					if (_pickupActive && !_hasPackage)
					{
						if (_dropPoint == Vector3.zero && (Object)(object)_marcoT != (Object)null)
						{
							_drop = AdoptOrPlace("rv_marco_package", _marcoT.position, out _pkgPlaced);
							_dropPoint = ((_drop != null) ? _drop.Position : (_marcoT.position + new Vector3(10f, 0f, 10f)));
							SyncEntry();
						}
						if (_pkgPlaced ? PlayerHasItem("rv_marco_package") : (_dropPoint != Vector3.zero && Dist(a, _dropPoint) < 5f))
						{
							_hasPackage = true;
							SyncEntry();
						}
					}
				}
				catch (Exception e)
				{
					Core.Swallowed("Questline.ProximityCoroutine", e);
				}
			}
		}

		private static void EnsureQuest()
		{
			RepairQuest.StartIfNeeded();
			if (RepairQuest.HasEntry())
			{
				SyncEntry();
			}
			else
			{
				MelonCoroutines.Start(SyncWhenBuilt());
			}
		}

		private static IEnumerator SyncWhenBuilt()
		{
			int myGen = _gen;
			for (int i = 0; i < 60; i++)
			{
				if (RepairQuest.HasEntry())
				{
					break;
				}
				yield return null;
			}
			if (myGen == _gen)
			{
				SyncEntry();
			}
		}

		internal static void RefreshEntries()
		{
			SyncEntry();
		}

		private static void RestorePackageErrand()
		{
			_errandRestored = true;
			int packageErrand = RepairStateStore.GetPackageErrand();
			if (packageErrand != 0)
			{
				if (Stage != 7)
				{
					Core.Log.Msg("[Questline] saved package run dropped - stage " + Stage + ".");
					RepairStateStore.SetPackageErrand(0);
					return;
				}
				_pickupActive = true;
				_hasPackage = packageErrand == 2;
				Core.Log.Msg("[Questline] package run restored (has package: " + _hasPackage + ").");
				SyncEntry();
			}
		}

		private static int CurrentStep(int stage)
		{
			switch (stage)
			{
			case 0:
			case 1:
				return 0;
			case 2:
				return 1;
			case 3:
				return 2;
			case 4:
				return 3;
			case 5:
			case 6:
				return 4;
			case 7:
			case 8:
				return 5;
			case 9:
				if (!RepairStateStore.GetRepaired())
				{
					return 8;
				}
				return 9;
			default:
				return 10;
			}
		}

		private static QuestState StoryStep(int step, int current)
		{
			if (step >= current)
			{
				if (step == current)
				{
					return (QuestState)1;
				}
				return (QuestState)0;
			}
			return (QuestState)2;
		}

		private static QuestState PackageStep(QuestState now, int stage, bool active, bool completed)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if (stage >= 9)
			{
				if ((int)now == 2)
				{
					return (QuestState)2;
				}
				return (QuestState)0;
			}
			if (!active)
			{
				if (completed)
				{
					return (QuestState)2;
				}
				return (QuestState)0;
			}
			return (QuestState)1;
		}

		private static void SyncEntry()
		{
			//IL_0049: 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)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: 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_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
			if (_errandRestored)
			{
				RepairStateStore.SetPackageErrand(_pickupActive ? ((!_hasPackage) ? 1 : 2) : 0);
			}
			int stage = Stage;
			if (stage < 10 && QuestSteps.TryOpen(RepairQuest.Title, 10, out var steps))
			{
				int num = CurrentStep(stage);
				Vector3 val = MarcoPos();
				steps.Set(0, StoryStep(0, num), null, "donna_martin", DonnaPos());
				steps.Set(1, StoryStep(1, num), null, "ming", MingPos());
				steps.Set(2, StoryStep(2, num), null, null, (_cratePoint != Vector3.zero) ? _cratePoint : MingPos());
				steps.Set(3, StoryStep(3, num), null, "ming", MingPos());
				steps.Set(4, StoryStep(4, num), null, "marco_baron", val);
				steps.Set(5, StoryStep(5, num), L10n.T("Pay Marco for the repair ({0})", MoneyManager.FormatAmount((float)CurrentPrice(), false, false)), "marco_baron", val);
				steps.Set(6, PackageStep(steps.State(6), stage, _pickupActive && !_hasPackage, (_pickupActive && _hasPackage) || stage == 8), null, null, (_dropPoint != Vector3.zero) ? _dropPoint : val);
				steps.Set(7, PackageStep(steps.State(7), stage, _pickupActive && _hasPackage, stage == 8), null, "marco_baron", val);
				QuestState want = (QuestState)((num == 8) ? 1 : ((num > 8 && (int)steps.State(8) != 0) ? 2 : 0));
				steps.Set(8, want, null, null, RvPos());
				steps.Set(9, StoryStep(9, num), null, null, RvPos());
			}
			if (NetworkBus.Online && NetworkBus.IsServer)
			{
				HostBroadcastTransient();
			}
		}

		private static DialogueChoice AddChoice(DialogueController dc, string text, int prio, Func<bool> show, Action onChosen, Conversation conv = null)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: 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_0062: 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_0072: Expected O, but got Unknown
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			if ((Object)(object)conv == (Object)null && onChosen == null)
			{
				_skippedChoices++;
				Core.Log.Warning("[Questline] skipped a choice with neither reply nor action: '" + text + "'");
				return null;
			}
			_injectedChoices++;
			DialogueChoice val = new DialogueChoice
			{
				Enabled = true,
				ChoiceText = text,
				Conversation = conv,
				Priority = prio
			};
			Func<bool, bool> func = delegate
			{
				try
				{
					return show();
				}
				catch (Exception e)
				{
					Core.Swallowed("Questline.AddChoice.shouldShowCheck", e);
					return false;
				}
			};
			val.shouldShowCheck = DelegateSupport.ConvertDelegate<ShouldShowCheck>((Delegate)func);
			val.onChoosen = new UnityEvent();
			if (onChosen != null)
			{
				val.onChoosen.AddListener(UnityAction.op_Implicit(onChosen));
			}
			dc.AddDialogueChoice(val, prio);
			return val;
		}

		private static ItemSlot HeldPackagedSlot()
		{
			try
			{
				PlayerInventory instance = PlayerSingleton<PlayerInventory>.Instance;
				if ((Object)(object)instance == (Object)null)
				{
					return null;
				}
				int num = ((instance.EquippedSlotIndex >= 0) ? instance.EquippedSlotIndex : instance.PriorEquippedSlotIndex);
				if (num < 0)
				{
					return null;
				}
				ItemSlot val = (ItemSlot)(object)instance.IndexAllSlots(num);
				object obj;
				if (val == null)
				{
					obj = null;
				}
				else
				{
					ItemInstance itemInstance = val.ItemInstance;
					obj = ((itemInstance != null) ? ((Il2CppObjectBase)itemInstance).TryCast<ProductItemInstance>() : null);
				}
				ProductItemInstance val2 = (ProductItemInstance)obj;
				return (val2 != null && (Object)(object)val2.AppliedPackaging != (Object)null) ? val : null;
			}
			catch (Exception e)
			{
				Core.Swallowed("Questline.HeldPackagedSlot", e);
				return null;
			}
		}

		internal static void SayMarco(string line)
		{
			WorldSay(MarcoTransform(), line);
		}

		private static Transform MarcoTransform()
		{
			if ((Object)(object)_marcoT != (Object)null)
			{