Decompiled source of RVRepairVan v2.0.1

RVRepairVan.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne.Audio;
using Il2CppScheduleOne.Core.Items.Framework;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Dialogue;
using Il2CppScheduleOne.ItemFramework;
using Il2CppScheduleOne.Money;
using Il2CppScheduleOne.NPCs;
using Il2CppScheduleOne.NPCs.Behaviour;
using Il2CppScheduleOne.NPCs.CharacterClasses;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.Product;
using Il2CppScheduleOne.Property;
using Il2CppScheduleOne.Quests;
using Il2CppScheduleOne.UI;
using Il2CppScheduleOne.VoiceOver;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using RVRepairVan;
using RVRepairVan.Config;
using RVRepairVan.Dialogue;
using RVRepairVan.Effects;
using RVRepairVan.Managers;
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.Money;
using S1API.Quests;
using S1API.Saveables;
using UnityEngine;
using UnityEngine.Events;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "RVRepairVan", "2.0.1", "DooDesch", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("RVRepairVan")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.0.1.0")]
[assembly: AssemblyInformationalVersion("2.0.1+eb1621fa18946731a7f7cc6861d2e376fbc23254")]
[assembly: AssemblyProduct("RVRepairVan")]
[assembly: AssemblyTitle("RVRepairVan")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.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 RVRepairVan
{
	public sealed class Core : MelonMod
	{
		public static Core Instance { get; private set; }

		public static Instance Log { get; private set; }

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

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

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			if (!(sceneName != "Main"))
			{
				RepairSave.BeginLoad();
				RVManager.Reset();
				RepairCinematic.ForceReset();
				if (RVRepairVanPreferences.QuestlineEnabled)
				{
					Questline.Reset();
					Questline.Start();
				}
				else
				{
					MarcoRepairDialogue.Reset();
					MelonCoroutines.Start(MarcoRepairDialogue.SetupCoroutine());
				}
				MelonCoroutines.Start(RestoreRepairCoroutine());
			}
		}

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

		private static IEnumerator RestoreRepairCoroutine()
		{
			float waited = 0f;
			while (!RepairSave.Loaded && waited < 10f)
			{
				yield return (object)new WaitForSeconds(0.5f);
				waited += 0.5f;
			}
			yield return (object)new WaitForSeconds(2f);
			bool flag = false;
			try
			{
				flag = RVManager.TryLocate() && RepairStateStore.GetRepaired() && RVManager.IsDestroyed();
			}
			catch (Exception ex)
			{
				Log.Warning("[Restore] check failed: " + ex.Message);
			}
			if (flag)
			{
				Log.Msg("[Restore] RV was previously repaired - restoring without charge.");
				RVManager.Repair();
			}
		}
	}
}
namespace RVRepairVan.Quests
{
	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 string DonnaId = "donna_martin";

		private const string MingId = "ming";

		private const string MarcoId = "marco_baron";

		private const string CrateId = "rv_ming_crate";

		private const string PackageId = "rv_marco_package";

		private const int LostPackageFee = 500;

		private const string MingAngry = "You lost it? I don't lose things, and people who lose my things lose teeth. Five hundred buys you both back. Now.";

		private const string MingPaid = "Smart. We're square. Now go see Marco at the body shop down by the docks, and tell him Mrs. Ming sent you.";

		private const string MingShort = "Then don't come back until your hands are full.";

		private const string MarcoAngry = "You did what? You walk in here empty-handed and waste my time. Five hundred, or the next thing that goes missing is you.";

		private const string MarcoPaid = "Good. Mess like that gets forgotten when the cash shows up. Bring me some of that good stuff now and then, and I'll keep shaving down the bill.";

		private const string MarcoShort = "Clock's running. Come back with it.";

		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 int _gen;

		private static Transform _donnaT;

		private static Transform _mingT;

		private static Transform _marcoT;

		private static DialogueChoice _marcoRepairChoice;

		private static bool _itemsDumped;

		private static int Stage
		{
			get
			{
				return RepairStateStore.GetStage();
			}
			set
			{
				RepairStateStore.SetStage(value);
			}
		}

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

		private static int DiscountTotal
		{
			get
			{
				return RepairStateStore.GetDiscountTotal();
			}
			set
			{
				RepairStateStore.SetDiscountTotal(value);
			}
		}

		private static bool MarcoGreeted => Stage >= 6;

		private static bool ReferralUsed => Stage >= 7;

		private static bool Trusted_ => Stage >= 8;

		private static bool Active
		{
			get
			{
				if (RVRepairVanPreferences.Enabled)
				{
					return RVManager.IsDestroyed();
				}
				return false;
			}
		}

		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
			{
			}
			return false;
		}

		internal static void Reset()
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			_gen++;
			ResetDiag();
			_donnaDone = (_mingDone = (_marcoDone = false));
			_pickupActive = false;
			_hasPackage = false;
			_drop = null;
			_crateDrop = null;
			_cratePlaced = (_pkgPlaced = false);
			_dropPoint = Vector3.zero;
			_cratePoint = Vector3.zero;
			_donnaT = (_mingT = (_marcoT = null));
			_marcoRepairChoice = null;
		}

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

		private static IEnumerator RestoreCoroutine()
		{
			yield return (object)new WaitForSeconds(4f);
			try
			{
				if (Active && 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();
				if (!reported && attempt >= 20)
				{
					reported = true;
				}
			}
			_ = myGen;
			_ = _gen;
		}

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

		private static bool TryOne(string id, out Transform t, Action<DialogueController, NPC> inject)
		{
			NPC val = FindNpc(id);
			DialogueController val2 = ControllerOf(val, out t);
			if ((Object)(object)val2 != (Object)null)
			{
				inject(val2, val);
				return true;
			}
			return false;
		}

		private static void InjectDonna(DialogueController donna, NPC npc)
		{
			DialogueContainer conv = S1Container(npc, "rv_donna", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", "Do I look like a mechanic, sweetheart? Go ask Mrs. Ming over at the Chinese place. She knows people.", (Action<ChoiceList>)null);
			});
			AddChoice(donna, "My RV got blown up. Know anyone who can fix it?", 90, () => Active && Stage == 1, OnAskDonna, conv);
		}

		private static void InjectMing(DialogueController ming, NPC npc)
		{
			DialogueContainer conv = S1Container(npc, "rv_ming_offer", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", "Marco at the docks can fix almost anything. But favors move both ways. I have a crate waiting at a dead drop nearby. Bring it back, and I'll put in a word.", (Action<ChoiceList>)delegate(ChoiceList c)
				{
					c.Add("MING_ACCEPT", "I'll grab it.", "MING_ACCEPTED").Add("MING_DEFER", "Not right now.", "MING_DEFERRED");
				}).AddNode("MING_ACCEPTED", "Good. Pick it up, bring it here, and don't open it.", (Action<ChoiceList>)null).AddNode("MING_DEFERRED", "Then your RV can stay where it is.", (Action<ChoiceList>)null);
			});
			OnPick(npc, "MING_ACCEPT", OnAcceptErrand);
			AddChoice(ming, "Donna said you might know someone who can fix my RV.", 92, () => Active && Stage == 2, null, conv);
			DialogueContainer conv2 = S1Container(npc, "rv_ming_deliver", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", "Good. Go see Marco at the body shop down by the docks. Tell him Mrs. Ming sent you.", (Action<ChoiceList>)null);
			});
			AddChoice(ming, "Here's your crate.", 91, () => Active && Stage == 4 && (!_cratePlaced || PlayerHasItem("rv_ming_crate")), OnDeliverCrate, conv2);
			DialogueContainer conv3 = S1Container(npc, "rv_ming_lost", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", "You lost it? I don't lose things, and people who lose my things lose teeth. Five hundred buys you both back. Now.", (Action<ChoiceList>)delegate(ChoiceList c)
				{
					c.Add("MING_PAY", "Pay $" + 500, (string)null).Add("MING_DEFER_LOSS", "I'll get the money.", "MING_LOSS_DEFER");
				}).AddNode("MING_LOSS_DEFER", "Then don't come back until your hands are full.", (Action<ChoiceList>)null);
			});
			OnPick(npc, "MING_PAY", OnMingPayLoss);
			AddChoice(ming, "I lost your crate.", 90, () => Active && Stage == 4 && _cratePlaced && !PlayerHasItem("rv_ming_crate"), null, conv3);
		}

		private static void InjectMarco(DialogueController marco, NPC npc)
		{
			AddChoice(marco, "Can you fix my RV?", 100, () => Active && Stage == 5, OnMarcoGreet);
			AddChoice(marco, "Fifty grand?", 99, () => Active && Stage == 6, OnMarcoFifty);
			AddChoice(marco, "Mrs. Ming sent me.", 98, () => Active && Stage == 6, OnMarcoReferral);
			_marcoRepairChoice = AddChoice(marco, RepairChoiceText(), 97, () => Active && MarcoGreeted && Stage < 9, OnMarcoRepair);
			DialogueContainer conv = S1Container(npc, "rv_marco_favour", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", "Maybe. I left a package at a dead drop nearby. Pick it up, bring it back, and don't make it weird.", (Action<ChoiceList>)null);
			});
			AddChoice(marco, "Anything I can do to bring the price down?", 96, () => Active && Stage == 7 && !_pickupActive, OnMarcoFavour, conv);
			DialogueContainer conv2 = S1Container(npc, "rv_marco_gotpkg", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", "Good. You can follow instructions. Bring me some of that good stuff now and then, and I'll keep shaving down the bill.", (Action<ChoiceList>)null);
			});
			AddChoice(marco, "Got your package.", 96, () => Active && _pickupActive && _hasPackage && (!_pkgPlaced || PlayerHasItem("rv_marco_package")), OnGotPackage, conv2);
			DialogueContainer conv3 = S1Container(npc, "rv_marco_lost", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", "You did what? You walk in here empty-handed and waste my time. Five hundred, or the next thing that goes missing is you.", (Action<ChoiceList>)delegate(ChoiceList c)
				{
					c.Add("MARCO_PAY", "Pay $" + 500, (string)null).Add("MARCO_DEFER_LOSS", "I'll get the money.", "MARCO_LOSS_DEFER");
				}).AddNode("MARCO_LOSS_DEFER", "Clock's running. Come back with it.", (Action<ChoiceList>)null);
			});
			OnPick(npc, "MARCO_PAY", OnMarcoPayLoss);
			AddChoice(marco, "I lost your package.", 96, () => Active && _pickupActive && _hasPackage && _pkgPlaced && !PlayerHasItem("rv_marco_package"), null, conv3);
			AddChoice(marco, "Give Marco a packaged sample", 95, () => Active && Trusted_ && Stage < 9 && HoldingPackaged() && CurrentPrice() > RVRepairVanPreferences.RepairPrice, OnGiveSample);
			DialogueContainer conv4 = S1Container(npc, "rv_marco_bring", delegate(DialogueContainerBuilder b)
			{
				b.AddNode("ENTRY", "Bring me packaged product - sealed stuff, not raw. Every piece I take knocks its value off the bill, up to five hundred a pop, right down to my floor.", (Action<ChoiceList>)null);
			});
			AddChoice(marco, "What can I bring to lower the price?", 94, () => Active && Trusted_ && Stage < 9 && !HoldingPackaged() && CurrentPrice() > RVRepairVanPreferences.RepairPrice, null, conv4);
		}

		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
			{
			}
			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 DialogueContainer 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<DialogueContainer> val2 = (((Object)(object)dialogueHandler != (Object)null) ? dialogueHandler.dialogueContainers : null);
				if (val2 != 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
						{
							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
			{
			}
			try
			{
				flag2 = (Object)(object)ControllerOf(val, out var _) != (Object)null;
			}
			catch
			{
			}
			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
			{
				return null;
			}
		}

		private static void OnAskDonna()
		{
			Stage = 2;
			SyncEntry();
		}

		private static void OnAcceptErrand()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (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()
		{
			if (Stage == 4)
			{
				if (_cratePlaced)
				{
					RemovePlayerItem("rv_ming_crate");
				}
				Stage = 5;
				SyncEntry();
			}
		}

		private static void OnMingPayLoss()
		{
			if (Stage == 4)
			{
				if (Money.GetCashBalance() < 500f)
				{
					WorldSay(_mingT, "Then don't come back until your hands are full.");
					return;
				}
				Money.ChangeCashBalance(-500f, true, true);
				Stage = 5;
				WorldSay(_mingT, "Smart. We're square. Now go see Marco at the body shop down by the docks, and tell him Mrs. Ming sent you.");
				SyncEntry();
			}
		}

		private static void OnMarcoGreet()
		{
			Stage = 6;
			WorldSay(_marcoT, "Yeah, I can fix it. Fifty grand.");
			SyncEntry();
		}

		private static void OnMarcoFifty()
		{
			WorldSay(_marcoT, "You brought me a burnt-out shell. That's not a repair, that's a resurrection.");
		}

		private static void OnMarcoReferral()
		{
			if (Stage == 6)
			{
				Stage = 7;
				RefreshRepairChoice();
				WorldSay(_marcoT, "Mrs. Ming sent you? Yeah, alright. Should've opened with that. Ten grand.");
				SyncEntry();
			}
		}

		private static void OnMarcoRepair()
		{
			try
			{
				if (!RVManager.IsDestroyed())
				{
					WorldSay(_marcoT, "Your RV looks fine to me.");
					return;
				}
				int num = CurrentPrice();
				if (Money.GetCashBalance() < (float)num)
				{
					WorldSay(_marcoT, "You're short. Come back when you've got the cash.");
					return;
				}
				Money.ChangeCashBalance((float)(-num), true, true);
				int paid = num;
				WorldSay(_marcoT, "Alright. Hold still, this won't take long.");
				RepairCinematic.Play(delegate
				{
					if (RVManager.Repair())
					{
						RepairStateStore.SetRepaired(repaired: true);
						Stage = 9;
						SyncEntry();
						Core.Log.Msg("[Questline] RV repaired for " + MoneyManager.FormatAmount((float)paid, false, false) + ".");
					}
				}, delegate
				{
					WorldSay(_marcoT, "There she is - back from the dead. Go take a look, and try not to total her again.");
				}, delegate
				{
					GruntNpc(FindNpc("marco_baron"));
				});
			}
			catch (Exception ex)
			{
				Core.Log.Error("[Questline] repair failed: " + ex);
			}
		}

		private static void OnMarcoFavour()
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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_007e: 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_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			_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()
		{
			if (_pkgPlaced)
			{
				RemovePlayerItem("rv_marco_package");
			}
			_pickupActive = false;
			_hasPackage = false;
			_drop = null;
			Stage = 8;
			SyncEntry();
		}

		private static void OnMarcoPayLoss()
		{
			if (_pickupActive && _hasPackage)
			{
				if (Money.GetCashBalance() < 500f)
				{
					WorldSay(_marcoT, "Clock's running. Come back with it.");
					return;
				}
				Money.ChangeCashBalance(-500f, true, true);
				_pickupActive = false;
				_hasPackage = false;
				_drop = null;
				Stage = 8;
				WorldSay(_marcoT, "Good. Mess like that gets forgotten when the cash shows up. Bring me some of that good stuff now and then, and I'll keep shaving down the bill.");
				SyncEntry();
			}
		}

		private static void OnGiveSample()
		{
			try
			{
				PlayerInventory instance = PlayerSingleton<PlayerInventory>.Instance;
				object obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					ItemInstance equippedItem = instance.EquippedItem;
					obj = ((equippedItem != null) ? ((Il2CppObjectBase)equippedItem).TryCast<ProductItemInstance>() : null);
				}
				ProductItemInstance val = (ProductItemInstance)obj;
				if (val == null || (Object)(object)val.AppliedPackaging == (Object)null)
				{
					WorldSay(_marcoT, "That ain't packaged. Hand me something sealed.");
					return;
				}
				int num = Mathf.Clamp(Mathf.RoundToInt(((BaseItemInstance)val).GetMonetaryValue()), RVRepairVanPreferences.MinSampleDiscount, RVRepairVanPreferences.MaxSampleDiscount);
				NPC val2 = FindNpc("marco_baron");
				ConsumeProductBehaviour val3 = (((Object)(object)val2 != (Object)null && (Object)(object)val2.Behaviour != (Object)null) ? val2.Behaviour.ConsumeProductBehaviour : null);
				if ((Object)(object)instance != (Object)null && instance.equippedSlot != null)
				{
					_ = ((ItemSlot)instance.equippedSlot).Quantity;
				}
				if ((Object)(object)val3 != (Object)null)
				{
					val3.SendProduct(val, false);
				}
				if ((Object)(object)instance != (Object)null && instance.equippedSlot != null)
				{
					RemoveOneFromSlot((ItemSlot)(object)instance.equippedSlot);
				}
				if ((Object)(object)instance != (Object)null && instance.equippedSlot != null)
				{
					_ = ((ItemSlot)instance.equippedSlot).Quantity;
				}
				Samples++;
				DiscountTotal += num;
				RefreshRepairChoice();
				WorldSay(_marcoT, "Appreciate it. Knocked " + MoneyManager.FormatAmount((float)num, false, false) + " off the bill.");
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Questline] give sample failed: " + ex.Message);
			}
		}

		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
			{
				RegisterItem("rv_ming_crate", "Ming's Crate", "A sealed crate for Mrs. Ming. She said not to open it.", new string[3] { "grainbag", "trashbag", "flashlight" });
				RegisterItem("rv_marco_package", "Marco's Package", "A package Marco left at a drop. Don't make it weird.", new string[3] { "trashbag", "grainbag", "flashlight" });
				_itemsRegistered = true;
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Questline] item register failed: " + ex.Message);
			}
		}

		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)
				{
					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
			{
			}
		}

		[Conditional("DEBUG")]
		private static void DumpItemsOnce()
		{
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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
						{
						}
					}
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[ITEMDUMP] failed: " + ex.Message);
			}
		}

		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
			{
			}
			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;
			while (myGen == _gen)
			{
				yield return (object)new WaitForSeconds(1f);
				if (!RepairSave.Loaded)
				{
					int 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.");
					}
				}
				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 position) && Dist(PlayerPos(), position) < 14f)
				{
					Stage = 10;
					RepairQuest.CompleteIfActive();
					WorldSay(_marcoT, "There she is. Standing again. Interior's your problem. Try not to piss off whoever torched it the first time.");
					Core.Log.Msg("[Questline] quest complete (RV checked).");
				}
				if (!Active)
				{
					continue;
				}
				try
				{
					Vector3 a = PlayerPos();
					if (Stage == 3)
					{
						if (_cratePoint == Vector3.zero)
						{
							_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();
						}
						if ((!_cratePlaced) ? (_cratePoint != Vector3.zero && Dist(a, _cratePoint) < 5f) : (_crateDrop != null && _crateDrop.IsEmpty))
						{
							Stage = 4;
							SyncEntry();
						}
					}
					if (_pickupActive && !_hasPackage && ((!_pkgPlaced) ? (Dist(a, _dropPoint) < 5f) : (_drop != null && _drop.IsEmpty)))
					{
						_hasPackage = true;
						SyncEntry();
					}
				}
				catch
				{
				}
			}
		}

		private static void EnsureQuest()
		{
			RepairQuest.StartIfNeeded();
			SyncEntry();
		}

		private static void SyncEntry()
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			string title;
			Vector3 poi;
			if (_pickupActive)
			{
				title = (_hasPackage ? "Bring Marco's package back" : "Pick up Marco's package from the dead drop");
				poi = (_hasPackage ? MarcoPos() : _dropPoint);
			}
			else
			{
				switch (Stage)
				{
				case 1:
					title = "Ask the motel manager about the RV";
					poi = DonnaPos();
					break;
				case 2:
					title = "Talk to Mrs. Ming at the Chinese restaurant";
					poi = MingPos();
					break;
				case 3:
					title = "Pick up Ming's crate from the dead drop";
					poi = _cratePoint;
					break;
				case 4:
					title = "Bring Ming's crate back to Mrs. Ming";
					poi = MingPos();
					break;
				case 5:
					title = "Talk to Marco at the body shop";
					poi = MarcoPos();
					break;
				case 6:
					title = "Tell Marco Mrs. Ming sent you";
					poi = MarcoPos();
					break;
				case 7:
				case 8:
					title = "Pay Marco for the repair";
					poi = MarcoPos();
					break;
				case 9:
					title = "Check on the RV";
					poi = RvPos();
					break;
				default:
					title = "Find a way to repair your RV";
					poi = RvPos();
					break;
				}
			}
			RepairQuest.UpdateEntry(title, poi);
		}

		private static DialogueChoice AddChoice(DialogueController dc, string text, int prio, Func<bool> show, Action onChosen, DialogueContainer conv = null)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: 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_002f: Expected O, but got Unknown
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			DialogueChoice val = new DialogueChoice
			{
				Enabled = true,
				ChoiceText = text,
				Conversation = conv,
				Priority = prio
			};
			Func<bool, bool> func = delegate
			{
				try
				{
					return show();
				}
				catch
				{
					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 bool HoldingPackaged()
		{
			try
			{
				PlayerInventory instance = PlayerSingleton<PlayerInventory>.Instance;
				object obj;
				if (instance == null)
				{
					obj = null;
				}
				else
				{
					ItemInstance equippedItem = instance.EquippedItem;
					obj = ((equippedItem != null) ? ((Il2CppObjectBase)equippedItem).TryCast<ProductItemInstance>() : null);
				}
				ProductItemInstance val = (ProductItemInstance)obj;
				return val != null && (Object)(object)val.AppliedPackaging != (Object)null;
			}
			catch
			{
				return false;
			}
		}

		private static void RefreshRepairChoice()
		{
			try
			{
				if (_marcoRepairChoice != null)
				{
					_marcoRepairChoice.ChoiceText = RepairChoiceText();
				}
			}
			catch
			{
			}
		}

		internal static void RefreshPrice()
		{
			RefreshRepairChoice();
		}

		private static string RepairChoiceText()
		{
			return "Repair my RV (" + MoneyManager.FormatAmount((float)CurrentPrice(), false, false) + ")";
		}

		private static void WorldSay(Transform npc, string line)
		{
			try
			{
				if (!((Object)(object)npc == (Object)null))
				{
					NPC componentInParent = ((Component)npc).GetComponentInParent<NPC>();
					if ((Object)(object)componentInParent != (Object)null)
					{
						componentInParent.SendWorldSpaceDialogue(line, 5f);
					}
				}
			}
			catch
			{
			}
		}

		private static Vector3 PlayerPos()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Player local = Player.Local;
				if ((Object)(object)local != (Object)null)
				{
					return ((Component)local).transform.position;
				}
			}
			catch
			{
			}
			return Vector3.zero;
		}

		private static float Dist(Vector3 a, Vector3 b)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			return Vector3.Distance(a, b);
		}

		private static Vector3 RvPos()
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if (!RVManager.TryGetPosition(out var position))
			{
				return Vector3.zero;
			}
			return position;
		}

		private static Vector3 DonnaPos()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_donnaT != (Object)null))
			{
				return RvPos();
			}
			return _donnaT.position;
		}

		private static Vector3 MingPos()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_mingT != (Object)null))
			{
				return RvPos();
			}
			return _mingT.position;
		}

		private static Vector3 MarcoPos()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)_marcoT != (Object)null))
			{
				return RvPos();
			}
			return _marcoT.position;
		}
	}
	internal static class RepairQuest
	{
		internal const string Title = "Back on the Road";

		internal static bool IsActive()
		{
			try
			{
				return QuestManager.GetQuestByName("Back on the Road") != null;
			}
			catch
			{
				return false;
			}
		}

		internal static void StartIfNeeded()
		{
			try
			{
				if (IsActive())
				{
					Core.Log.Msg("[Quest] 'Back on the Road' already active.");
					return;
				}
				QuestManager.CreateQuest<RepairRVQuest>((string)null);
				Core.Log.Msg("[Quest] 'Back on the Road' started.");
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Quest] start failed: " + ex.Message);
			}
		}

		internal static void UpdateEntry(string title, Vector3 poi)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				Quest questByName = QuestManager.GetQuestByName("Back on the Road");
				if (questByName?.QuestEntries != null && questByName.QuestEntries.Count > 0)
				{
					QuestEntry obj = questByName.QuestEntries[0];
					obj.Title = title;
					obj.POIPosition = poi;
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Quest] update entry failed: " + ex.Message);
			}
		}

		internal static void CompleteIfActive()
		{
			try
			{
				Quest questByName = QuestManager.GetQuestByName("Back on the Road");
				if (questByName == null)
				{
					return;
				}
				if (questByName.QuestEntries != null)
				{
					foreach (QuestEntry questEntry in questByName.QuestEntries)
					{
						try
						{
							questEntry.Complete();
						}
						catch
						{
						}
					}
				}
				Core.Log.Msg("[Quest] 'Back on the Road' completed.");
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Quest] complete failed: " + ex.Message);
			}
		}
	}
	public class RepairRVQuest : Quest
	{
		private static Sprite _icon;

		private static bool _iconTried;

		protected override string Title => "Back on the Road";

		protected override string Description => "Your RV's wrecked. Someone in Hyland Point has to know a guy.";

		protected override bool AutoBegin => true;

		protected override Sprite QuestIcon
		{
			get
			{
				if (!_iconTried)
				{
					_iconTried = true;
					_icon = LoadIcon();
				}
				return _icon;
			}
		}

		private static Sprite LoadIcon()
		{
			//IL_005e: 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)
			//IL_006b: Expected O, but got Unknown
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("RVRepairVan.quest_icon.png");
				if (stream == null)
				{
					Core.Log.Warning("[Quest] icon resource missing");
					return null;
				}
				byte[] array = new byte[stream.Length];
				int num;
				for (int i = 0; i < array.Length; i += num)
				{
					num = stream.Read(array, i, array.Length - i);
					if (num <= 0)
					{
						break;
					}
				}
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false)
				{
					filterMode = (FilterMode)1
				};
				ImageConversion.LoadImage(val, Il2CppStructArray<byte>.op_Implicit(array), false);
				return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f);
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Quest] icon load failed: " + ex.Message);
				return null;
			}
		}

		protected override void OnCreated()
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			((Registerable)this).OnCreated();
			try
			{
				((Quest)this).AddEntry("Ask the motel manager about the RV", (Vector3?)null).POIPosition = (RVManager.TryGetPosition(out var position) ? position : Vector3.zero);
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Quest] OnCreated failed: " + ex.Message);
			}
		}
	}
}
namespace RVRepairVan.Persistence
{
	public class RepairSave : Saveable
	{
		[SaveableField("rv_repaired")]
		private bool _repaired;

		[SaveableField("rv_stage")]
		private int _stage;

		[SaveableField("rv_samples")]
		private int _samples;

		[SaveableField("rv_discount")]
		private int _discount;

		internal static RepairSave Instance { get; private set; }

		internal static bool Loaded { get; private set; }

		internal bool Repaired
		{
			get
			{
				return _repaired;
			}
			set
			{
				_repaired = value;
			}
		}

		internal int Stage
		{
			get
			{
				return _stage;
			}
			set
			{
				_stage = value;
			}
		}

		internal int Samples
		{
			get
			{
				return _samples;
			}
			set
			{
				_samples = value;
			}
		}

		internal int Discount
		{
			get
			{
				return _discount;
			}
			set
			{
				_discount = value;
			}
		}

		public RepairSave()
		{
			Instance = this;
		}

		internal static void BeginLoad()
		{
			Loaded = false;
			if (Instance != null)
			{
				Instance._repaired = false;
				Instance._stage = 0;
				Instance._samples = 0;
				Instance._discount = 0;
			}
		}

		protected override void OnLoaded()
		{
			Instance = this;
			Loaded = true;
			Core.Log.Msg($"[State] loaded: repaired={_repaired} stage={_stage} samples={_samples} discount={_discount}");
		}

		protected override void OnCreated()
		{
			Instance = this;
			_repaired = false;
			_stage = 0;
			_samples = 0;
			_discount = 0;
			Loaded = true;
			Core.Log.Msg("[State] created (fresh save) - defaults applied.");
		}

		protected override void OnSaved()
		{
			Core.Log.Msg($"[State] saved: repaired={_repaired} stage={_stage} samples={_samples} discount={_discount}");
		}
	}
	internal static class RepairStateStore
	{
		private static RepairSave S => RepairSave.Instance;

		internal static bool GetRepaired()
		{
			if (S != null)
			{
				return S.Repaired;
			}
			return false;
		}

		internal static void SetRepaired(bool repaired)
		{
			if (S != null)
			{
				S.Repaired = repaired;
			}
		}

		internal static int GetStage()
		{
			if (S == null)
			{
				return 0;
			}
			return S.Stage;
		}

		internal static void SetStage(int stage)
		{
			if (S != null)
			{
				S.Stage = stage;
			}
		}

		internal static int GetSamples()
		{
			if (S == null)
			{
				return 0;
			}
			return S.Samples;
		}

		internal static void SetSamples(int samples)
		{
			if (S != null)
			{
				S.Samples = samples;
			}
		}

		internal static int GetDiscountTotal()
		{
			if (S == null)
			{
				return 0;
			}
			return S.Discount;
		}

		internal static void SetDiscountTotal(int discount)
		{
			if (S != null)
			{
				S.Discount = discount;
			}
		}
	}
}
namespace RVRepairVan.Managers
{
	internal static class RVManager
	{
		private static Transform _root;

		private static RV _rv;

		private static Transform _model;

		private static Transform _destroyed;

		private static Transform _cartelNote;

		internal static bool IsReady
		{
			get
			{
				if ((Object)(object)_root != (Object)null)
				{
					return (Object)(object)_rv != (Object)null;
				}
				return false;
			}
		}

		internal static bool TryGetPosition(out Vector3 position)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			position = Vector3.zero;
			try
			{
				if (!TryLocate())
				{
					return false;
				}
				position = _root.position;
				return true;
			}
			catch
			{
				return false;
			}
		}

		internal static void Reset()
		{
			_root = null;
			_rv = null;
			_model = null;
			_destroyed = null;
			_cartelNote = null;
		}

		[Conditional("DEBUG")]
		internal static void LogState()
		{
			try
			{
				Il2CppArrayBase<RV> val = Object.FindObjectsOfType<RV>(true);
				int num = val?.Length ?? 0;
				Core.Log.Msg($"[RVManager] DIAG: FindObjectsOfType<RV>(true) -> {num} RV component(s)");
				for (int i = 0; i < num; i++)
				{
					RV val2 = val[i];
					if (!((Object)(object)val2 == (Object)null))
					{
						Transform transform = ((Component)val2).transform;
						bool value = false;
						bool value2 = false;
						try
						{
							value = val2.IsDestroyed;
						}
						catch
						{
						}
						try
						{
							value2 = val2._exploded;
						}
						catch
						{
						}
						string text = "";
						for (int j = 0; j < transform.childCount; j++)
						{
							Transform child = transform.GetChild(j);
							text = text + ((Object)child).name + "[" + (((Component)child).gameObject.activeSelf ? "ON" : "off") + "] ";
						}
						Core.Log.Msg($"[RVManager] DIAG: RV#{i} path='{FullPath(transform)}' activeInHierarchy={((Component)transform).gameObject.activeInHierarchy} IsDestroyed={value} _exploded={value2}");
						Core.Log.Msg($"[RVManager] DIAG: RV#{i} children -> {text}");
					}
				}
				GameObject val3 = GameObject.Find("@Properties");
				if ((Object)(object)val3 != (Object)null)
				{
					string text2 = "";
					for (int k = 0; k < val3.transform.childCount; k++)
					{
						Transform child2 = val3.transform.GetChild(k);
						text2 = text2 + ((Object)child2).name + "[" + (((Component)child2).gameObject.activeSelf ? "ON" : "off") + "] ";
					}
					Core.Log.Msg("[RVManager] DIAG: @Properties children -> " + text2);
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[RVManager] DIAG failed: " + ex.Message);
			}
		}

		private static string FullPath(Transform t)
		{
			string text = ((Object)t).name;
			Transform parent = t.parent;
			int num = 0;
			while ((Object)(object)parent != (Object)null && num++ < 12)
			{
				text = ((Object)parent).name + "/" + text;
				parent = parent.parent;
			}
			return text;
		}

		internal static bool TryLocate()
		{
			if (IsReady)
			{
				return true;
			}
			try
			{
				GameObject val = GameObject.Find("@Properties");
				if ((Object)(object)val == (Object)null)
				{
					return false;
				}
				Transform val2 = val.transform.Find("RV");
				if ((Object)(object)val2 == (Object)null)
				{
					return false;
				}
				RV component = ((Component)val2).GetComponent<RV>();
				if ((Object)(object)component == (Object)null)
				{
					return false;
				}
				_root = val2;
				_rv = component;
				_model = val2.Find("RV");
				_destroyed = val2.Find("Destroyed RV");
				_cartelNote = (((Object)(object)_destroyed != (Object)null) ? _destroyed.Find("CartelNote") : null);
				return true;
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[RVManager] locate failed: " + ex.Message);
				return false;
			}
		}

		internal static bool IsDestroyed()
		{
			try
			{
				if (!TryLocate())
				{
					return false;
				}
				if ((Object)(object)_destroyed != (Object)null && ((Component)_destroyed).gameObject.activeSelf)
				{
					return true;
				}
				return _rv.IsDestroyed;
			}
			catch
			{
				return false;
			}
		}

		internal static bool Repair()
		{
			if (!TryLocate())
			{
				Core.Log.Warning("[RVManager] RV not found - cannot repair.");
				return false;
			}
			try
			{
				_rv.IsDestroyed = false;
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[RVManager] set IsDestroyed failed: " + ex.Message);
			}
			try
			{
				_rv._exploded = false;
			}
			catch
			{
			}
			try
			{
				if ((Object)(object)_model != (Object)null && !((Component)_model).gameObject.activeSelf)
				{
					((Component)_model).gameObject.SetActive(true);
				}
				if ((Object)(object)_destroyed != (Object)null && ((Component)_destroyed).gameObject.activeSelf)
				{
					((Component)_destroyed).gameObject.SetActive(false);
				}
				if ((Object)(object)_cartelNote != (Object)null && ((Component)_cartelNote).gameObject.activeSelf)
				{
					((Component)_cartelNote).gameObject.SetActive(false);
				}
			}
			catch (Exception ex2)
			{
				Core.Log.Warning("[RVManager] visual swap failed: " + ex2.Message);
			}
			try
			{
				if ((Object)(object)_rv.FXContainer != (Object)null && !((Component)_rv.FXContainer).gameObject.activeSelf)
				{
					((Component)_rv.FXContainer).gameObject.SetActive(true);
				}
			}
			catch
			{
			}
			Core.Log.Msg("[RVManager] RV repaired.");
			return true;
		}
	}
}
namespace RVRepairVan.Effects
{
	internal static class RepairCinematic
	{
		private const float FadeTime = 0.6f;

		private const float HoldTime = 2.5f;

		private const float MidHoldDelay = 1.25f;

		private const float SoundVolume = 0.2f;

		private static AudioClip _clip;

		private static bool _clipTried;

		internal static void Play(Action doWhileBlack, Action onDone, Action onMidHold = null)
		{
			MelonCoroutines.Start(Run(doWhileBlack, onDone, onMidHold));
		}

		internal static void ForceReset()
		{
			Fade(toBlack: false);
			LockInput(locked: false);
		}

		private static IEnumerator Run(Action doWhileBlack, Action onDone, Action onMidHold)
		{
			try
			{
				LockInput(locked: true);
				Fade(toBlack: true);
				yield return (object)new WaitForSeconds(0.6f);
				PlaySound();
				yield return (object)new WaitForSeconds(1.25f);
				Safe(onMidHold);
				yield return (object)new WaitForSeconds(1.25f);
				Safe(doWhileBlack);
				Fade(toBlack: false);
				yield return (object)new WaitForSeconds(0.6f);
				Safe(onDone);
			}
			finally
			{
				Fade(toBlack: false);
				LockInput(locked: false);
			}
		}

		private static void Fade(bool toBlack)
		{
			try
			{
				if (Singleton<BlackOverlay>.InstanceExists)
				{
					BlackOverlay instance = Singleton<BlackOverlay>.Instance;
					if (toBlack)
					{
						instance.Open(0.6f);
					}
					else
					{
						instance.Close(0.6f);
					}
				}
				else if (Singleton<HUD>.InstanceExists)
				{
					Singleton<HUD>.Instance.SetBlackOverlayVisible(toBlack, 0.6f);
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Cinematic] fade failed: " + ex.Message);
			}
		}

		private static void LockInput(bool locked)
		{
			try
			{
				PlayerMovement instance = PlayerSingleton<PlayerMovement>.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					instance.CanMove = !locked;
				}
			}
			catch
			{
			}
			try
			{
				PlayerCamera instance2 = PlayerSingleton<PlayerCamera>.Instance;
				if ((Object)(object)instance2 != (Object)null)
				{
					instance2.SetCanLook(!locked);
				}
			}
			catch
			{
			}
		}

		private static void PlaySound()
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				AudioClip val = EnsureClip();
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				GameObject val2 = new GameObject("RVRepairSound");
				val2.transform.position = PlayerPos();
				AudioSource val3 = val2.AddComponent<AudioSource>();
				val3.clip = val;
				val3.volume = 0.2f;
				val3.spatialBlend = 0f;
				try
				{
					AudioManager instance = Singleton<AudioManager>.Instance;
					if ((Object)(object)instance != (Object)null && (Object)(object)instance.MainGameMixer != (Object)null)
					{
						val3.outputAudioMixerGroup = instance.MainGameMixer;
					}
				}
				catch
				{
				}
				val3.Play();
				Object.Destroy((Object)(object)val2, val.length + 0.3f);
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Cinematic] sound failed: " + ex.Message);
			}
		}

		private static Vector3 PlayerPos()
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				PlayerMovement instance = PlayerSingleton<PlayerMovement>.Instance;
				if ((Object)(object)instance != (Object)null)
				{
					return ((Component)instance).transform.position;
				}
			}
			catch
			{
			}
			return Vector3.zero;
		}

		private static AudioClip EnsureClip()
		{
			if (_clipTried)
			{
				return _clip;
			}
			_clipTried = true;
			try
			{
				using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("RVRepairVan.repair.wav");
				if (stream == null)
				{
					Core.Log.Warning("[Cinematic] repair.wav resource missing");
					return null;
				}
				byte[] array = new byte[stream.Length];
				int num;
				for (int i = 0; i < array.Length; i += num)
				{
					num = stream.Read(array, i, array.Length - i);
					if (num <= 0)
					{
						break;
					}
				}
				_clip = WavToClip(array);
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Cinematic] clip load failed: " + ex.Message);
			}
			return _clip;
		}

		private static AudioClip WavToClip(byte[] wav)
		{
			if (wav == null || wav.Length < 44)
			{
				return null;
			}
			int num = 1;
			int num2 = 22050;
			int num3 = 16;
			int num4 = -1;
			int num5 = 0;
			int num6 = 12;
			while (num6 + 8 <= wav.Length)
			{
				string text = Encoding.ASCII.GetString(wav, num6, 4);
				int num7 = BitConverter.ToInt32(wav, num6 + 4);
				int num8 = num6 + 8;
				if (text == "fmt " && num8 + 16 <= wav.Length)
				{
					num = BitConverter.ToInt16(wav, num8 + 2);
					num2 = BitConverter.ToInt32(wav, num8 + 4);
					num3 = BitConverter.ToInt16(wav, num8 + 14);
				}
				else if (text == "data")
				{
					num4 = num8;
					num5 = num7;
				}
				num6 = num8 + num7 + (num7 & 1);
			}
			if (num4 < 0 || num3 != 16 || num < 1)
			{
				Core.Log.Warning("[Cinematic] unsupported WAV (need 16-bit PCM)");
				return null;
			}
			if (num4 + num5 > wav.Length)
			{
				num5 = wav.Length - num4;
			}
			int num9 = num5 / 2;
			float[] array = new float[num9];
			for (int i = 0; i < num9; i++)
			{
				array[i] = (float)BitConverter.ToInt16(wav, num4 + i * 2) / 32768f;
			}
			AudioClip val = AudioClip.Create("rv_repair", num9 / num, num, num2, false);
			val.SetData(Il2CppStructArray<float>.op_Implicit(array), 0);
			Core.Log.Msg("[Cinematic] repair clip loaded (" + num9 / num + " frames, " + num + "ch, " + num2 + "Hz).");
			return val;
		}

		private static void Safe(Action a)
		{
			if (a == null)
			{
				return;
			}
			try
			{
				a();
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Cinematic] callback failed: " + ex.Message);
			}
		}
	}
}
namespace RVRepairVan.Dialogue
{
	internal static class MarcoRepairDialogue
	{
		private static bool _injected;

		private static DialogueChoice _repairChoice;

		internal static void Reset()
		{
			_injected = false;
			_repairChoice = null;
		}

		internal static void RefreshPrice()
		{
			try
			{
				if (_repairChoice != null)
				{
					_repairChoice.ChoiceText = BuildChoiceText();
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Marco] price refresh failed: " + ex.Message);
			}
		}

		internal static IEnumerator SetupCoroutine()
		{
			for (int attempt = 0; attempt < 20; attempt++)
			{
				if (_injected)
				{
					break;
				}
				yield return (object)new WaitForSeconds(2f);
				TryInject();
			}
			if (!_injected)
			{
				Core.Log.Warning("[Marco] Could not inject RV repair dialogue (Marco not found within ~40s).");
			}
		}

		private static void TryInject()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			try
			{
				Marco val = FindMarco();
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				DialogueController val2 = FindController(val);
				if (!((Object)(object)val2 == (Object)null))
				{
					DialogueChoice val3 = new DialogueChoice
					{
						Enabled = true,
						ChoiceText = BuildChoiceText(),
						Conversation = null,
						Priority = 100
					};
					Func<bool, bool> func = (bool enabled) => enabled && RVManager.IsDestroyed();
					val3.shouldShowCheck = DelegateSupport.ConvertDelegate<ShouldShowCheck>((Delegate)func);
					val3.onChoosen = new UnityEvent();
					val3.onChoosen.AddListener(UnityAction.op_Implicit((Action)OnRepairChosen));
					val2.AddDialogueChoice(val3, 100);
					_repairChoice = val3;
					_injected = true;
					Core.Log.Msg("[Marco] RV repair dialogue injected.");
				}
			}
			catch (Exception ex)
			{
				Core.Log.Warning("[Marco] inject attempt failed: " + ex.Message);
			}
		}

		private static Marco FindMarco()
		{
			Il2CppArrayBase<Marco> val = Object.FindObjectsOfType<Marco>();
			if (val == null || val.Length == 0)
			{
				return null;
			}
			return val[0];
		}

		private static DialogueController FindController(Marco marco)
		{
			try
			{
				DialogueHandler dialogueHandler = ((NPC)marco).DialogueHandler;
				if ((Object)(object)dialogueHandler != (Object)null)
				{
					DialogueController componentInChildren = ((Component)dialogueHandler).GetComponentInChildren<DialogueController>();
					if ((Object)(object)componentInChildren != (Object)null)
					{
						return componentInChildren;
					}
				}
			}
			catch
			{
			}
			try
			{
				return ((Component)marco).GetComponentInChildren<DialogueController>();
			}
			catch
			{
				return null;
			}
		}

		private static string BuildChoiceText()
		{
			return "Repair my RV (" + MoneyManager.FormatAmount((float)RVRepairVanPreferences.RepairPrice, false, false) + ")";
		}

		private static void WorldSay(NPC npc, string line)
		{
			try
			{
				if ((Object)(object)npc != (Object)null)
				{
					npc.SendWorldSpaceDialogue(line, 5f);
				}
			}
			catch
			{
			}
		}

		private static void OnRepairChosen()
		{
			try
			{
				if (!RVRepairVanPreferences.Enabled)
				{
					return;
				}
				if (!RVManager.IsDestroyed())
				{
					Core.Log.Msg("[Marco] RV is not destroyed - nothing to repair.");
					return;
				}
				float num = RVRepairVanPreferences.RepairPrice;
				if (Money.GetCashBalance() < num)
				{
					Core.Log.Msg("[Marco] Not enough cash for repair (" + MoneyManager.FormatAmount(num, false, false) + ").");
					return;
				}
				Money.ChangeCashBalance(0f - num, true, true);
				float paid = num;
				Marco marco = FindMarco();
				RepairCinematic.Play(delegate
				{
					if (RVManager.Repair())
					{
						RepairStateStore.SetRepaired(repaired: true);
						RepairQuest.CompleteIfActive();
						Core.Log.Msg("[Marco] RV repaired for " + MoneyManager.FormatAmount(paid, false, false) + ".");
					}
				}, delegate
				{
					WorldSay((NPC)(object)marco, "There she is - back from the dead. Try not to total her again.");
				}, delegate
				{
					Questline.GruntNpc((NPC)(object)marco);
				});
			}
			catch (Exception ex)
			{
				Core.Log.Error("[Marco] repair failed: " + ex);
			}
		}
	}
}
namespace RVRepairVan.Config
{
	internal static class RVRepairVanPreferences
	{
		private const string CategoryId = "RVRepairVan_01_Main";

		private static MelonPreferences_Category _category;

		private static MelonPreferences_Entry<bool> _enabled;

		private static MelonPreferences_Entry<int> _repairPrice;

		private static MelonPreferences_Entry<string> _questMode;

		private static MelonPreferences_Entry<int> _basePriceNoReferral;

		private static MelonPreferences_Entry<int> _basePriceWithReferral;

		private static MelonPreferences_Entry<int> _minSampleDiscount;

		private static MelonPreferences_Entry<int> _maxSampleDiscount;

		internal static bool Enabled => _enabled?.Value ?? true;

		internal static int RepairPrice => Mathf.Max(0, _repairPrice?.Value ?? 1500);

		internal static bool QuestlineEnabled => string.Equals(_questMode?.Value, "Questline", StringComparison.OrdinalIgnoreCase);

		internal static int BasePriceNoReferral => Mathf.Max(0, _basePriceNoReferral?.Value ?? 50000);

		internal static int BasePriceWithReferral => Mathf.Max(0, _basePriceWithReferral?.Value ?? 10000);

		internal static int MinSampleDiscount => Mathf.Max(0, _minSampleDiscount?.Value ?? 100);

		internal static int MaxSampleDiscount => Mathf.Max(MinSampleDiscount, _maxSampleDiscount?.Value ?? 500);

		internal static void Initialize()
		{
			if (_category == null)
			{
				_category = MelonPreferences.CreateCategory("RVRepairVan_01_Main", "RV Repair Van");
				_enabled = CreateEntry("Enabled", defaultValue: true, "Enabled", "Enable the RV repair feature.");
				_repairPrice = CreateEntry("RepairPrice", 1500, "Repair Price", "Cash required to repair the RV (Simple mode, and the price floor).");
				_questMode = CreateEntry("QuestMode", "Questline", "Quest Mode", "Questline (default) = the full Donna -> Ming -> Marco story (see docs/QUESTLINE.md). Simple = just talk to Marco and pay.");
				_basePriceNoReferral = CreateEntry("BasePriceNoReferral", 50000, "Questline: Price without referral", "Marco's price in Questline mode if you go straight to him.");
				_basePriceWithReferral = CreateEntry("BasePriceWithReferral", 10000, "Questline: Price with Ming's referral", "Marco's price in Questline mode after Mrs. Ming puts in a word.");
				_minSampleDiscount = CreateEntry("MinSampleDiscount", 100, "Questline: Min sample discount", "Smallest price cut a single free sample can give Marco (cheap product floors here).");
				_maxSampleDiscount = CreateEntry("MaxSampleDiscount", 500, "Questline: Max sample discount", "Largest price cut a single free sample can give. Each packaged sample cuts the price by its value, clamped between min and max, down to the Repair Price floor.");
			}
		}

		private static MelonPreferences_Entry<T> CreateEntry<T>(string identifier, T defaultValue, string displayName, string description = null)
		{
			return _category.CreateEntry<T>(identifier, defaultValue, displayName, description, false, false, (ValueValidator)null, (string)null);
		}
	}
}