Decompiled source of CinematicControl v1.0.2

CinematicControl.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: CompilationRelaxations(8)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace CinematicControl;

public enum CinematicMode
{
	AlwaysPlay,
	PlayOnce,
	Disabled
}
[BepInPlugin("com.drakosdj.cinematiccontrol", "CinematicControl", "1.0.2")]
public class CinematicControlPlugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(SceneLoader), "Awake")]
	public static class Patch_SceneLoader_Awake
	{
		private static void Postfix(SceneLoader __instance)
		{
			if (!ConfigModEnabled.Value)
			{
				return;
			}
			try
			{
				bool flag = false;
				if (ConfigStartupLogos.Value == CinematicMode.Disabled)
				{
					flag = true;
				}
				else if (ConfigStartupLogos.Value == CinematicMode.PlayOnce)
				{
					if (ConfigSeenStartupLogos.Value)
					{
						flag = true;
					}
					else
					{
						ConfigSeenStartupLogos.Value = true;
						((BaseUnityPlugin)Instance).Config.Save();
						Log.LogInfo((object)"Startup logos displayed for first time; recorded to config.");
					}
				}
				if (flag)
				{
					Traverse val = Traverse.Create((object)__instance);
					val.Field("_showLogos").SetValue((object)false);
					val.Field("_showHealthWarning").SetValue((object)false);
					val.Field("_showSaveNotification").SetValue((object)false);
					Log.LogInfo((object)"Startup logos bypassed by CinematicControl.");
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Exception in Patch_SceneLoader_Awake: " + ex));
			}
		}
	}

	[HarmonyPatch]
	public static class Patch_FejdStartup_PlayIntroCinematic
	{
		private static MethodBase TargetMethod()
		{
			return AccessTools.Method(typeof(FejdStartup), "TryPlayIntroCinematic", (Type[])null, (Type[])null) ?? AccessTools.Method(typeof(FejdStartup), "PlayIntroCinematic", (Type[])null, (Type[])null);
		}

		private static bool Prefix(FejdStartup __instance, ref IEnumerator __result)
		{
			if (!ConfigModEnabled.Value)
			{
				return true;
			}
			try
			{
				bool flag = false;
				if (ConfigLaunchCinematic.Value == CinematicMode.Disabled)
				{
					flag = true;
				}
				else if (ConfigLaunchCinematic.Value == CinematicMode.PlayOnce)
				{
					if (ConfigSeenLaunchMovie.Value)
					{
						flag = true;
					}
					else
					{
						ConfigSeenLaunchMovie.Value = true;
						((BaseUnityPlugin)Instance).Config.Save();
						Log.LogInfo((object)"Launch cinematic displayed for first time; recorded to config.");
						SetVanillaSkipIntroCinematic(skip: false);
					}
				}
				else if (ConfigLaunchCinematic.Value == CinematicMode.AlwaysPlay)
				{
					SetVanillaSkipIntroCinematic(skip: false);
				}
				if (flag)
				{
					Log.LogInfo((object)"Launch cinematic bypassed. Transitioning immediately to main menu.");
					SetVanillaSkipIntroCinematic(skip: true);
					__result = SkipLaunchCoroutine(__instance);
					return false;
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Exception in Patch_FejdStartup_PlayIntroCinematic: " + ex));
			}
			return true;
		}

		private static void SetVanillaSkipIntroCinematic(bool skip)
		{
			try
			{
				PlatformPrefs.SetBool("SkipIntroCinematic", skip);
			}
			catch
			{
			}
		}

		private static IEnumerator SkipLaunchCoroutine(FejdStartup startup)
		{
			if ((Object)(object)startup.m_mainMenu != (Object)null)
			{
				startup.m_mainMenu.SetActive(true);
			}
			if ((Object)(object)startup.m_menuAnimator != (Object)null)
			{
				startup.m_menuAnimator.SetTrigger("FadeIn");
			}
			yield break;
		}
	}

	[HarmonyPatch(typeof(CinematicsManager), "Awake")]
	public static class Patch_CinematicsManager_Awake
	{
		private static void Postfix(CinematicsManager __instance)
		{
			if (!ConfigModEnabled.Value)
			{
				return;
			}
			try
			{
				if (ConfigLaunchCinematic.Value == CinematicMode.Disabled || (ConfigLaunchCinematic.Value == CinematicMode.PlayOnce && ConfigSeenLaunchMovie.Value))
				{
					__instance.m_introOnStartup = false;
					Log.LogInfo((object)"CinematicsManager: m_introOnStartup set to false.");
				}
				if (ConfigNewWorldMovie.Value == CinematicMode.Disabled)
				{
					__instance.m_introOnNewWorld = false;
					Log.LogInfo((object)"CinematicsManager: m_introOnNewWorld set to false.");
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Exception in Patch_CinematicsManager_Awake: " + ex));
			}
		}
	}

	[HarmonyPatch(typeof(CinematicsManager), "Play", new Type[]
	{
		typeof(string),
		typeof(VideoCompleteAction)
	})]
	public static class Patch_CinematicsManager_PlayString
	{
		private static bool Prefix(string name, VideoCompleteAction onStop, ref bool __result)
		{
			if (!ConfigModEnabled.Value)
			{
				return true;
			}
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null && localPlayer.IsSleeping())
				{
					if (ConfigDreamCinematics.Value == CinematicMode.Disabled)
					{
						Log.LogInfo((object)("Dream cinematic '" + name + "' suppressed (Disabled mode). Falling back to dream text."));
						__result = false;
						return false;
					}
					if (ConfigDreamCinematics.Value == CinematicMode.PlayOnce)
					{
						string key = "CinematicControl_DreamSeen_" + name;
						if (localPlayer.m_customData.ContainsKey(key))
						{
							Log.LogInfo((object)("Dream cinematic '" + name + "' already seen on this character. Falling back to dream text."));
							__result = false;
							return false;
						}
						localPlayer.m_customData[key] = "true";
						Log.LogInfo((object)("Playing maiden dream cinematic '" + name + "' for character."));
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Exception in Patch_CinematicsManager_PlayString: " + ex));
			}
			return true;
		}
	}

	[HarmonyPatch(typeof(CinematicsManager), "Play", new Type[]
	{
		typeof(Settings),
		typeof(VideoCompleteAction)
	})]
	public static class Patch_CinematicsManager_PlaySettings
	{
		private static bool Prefix(Settings firstWithSetting, VideoCompleteAction onStop, ref bool __result)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Invalid comparison between Unknown and I4
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a4: Invalid comparison between Unknown and I4
			if (!ConfigModEnabled.Value)
			{
				return true;
			}
			try
			{
				if ((int)firstWithSetting == 2)
				{
					if ((Object)(object)Game.instance == (Object)null)
					{
						if (ConfigLaunchCinematic.Value == CinematicMode.Disabled)
						{
							Log.LogInfo((object)"Startup launch cinematic suppressed (Disabled mode).");
							__result = false;
							return false;
						}
						if (ConfigLaunchCinematic.Value == CinematicMode.PlayOnce)
						{
							if (ConfigSeenLaunchMovie.Value)
							{
								Log.LogInfo((object)"Startup launch cinematic already seen once.");
								__result = false;
								return false;
							}
							ConfigSeenLaunchMovie.Value = true;
							((BaseUnityPlugin)Instance).Config.Save();
							Log.LogInfo((object)"Playing launch cinematic for first time; recorded to config.");
						}
					}
					else
					{
						if (ConfigNewWorldMovie.Value == CinematicMode.Disabled)
						{
							Log.LogInfo((object)"New world movie suppressed (Disabled mode).");
							__result = false;
							return false;
						}
						if (ConfigNewWorldMovie.Value == CinematicMode.PlayOnce)
						{
							PlayerProfile playerProfile = Game.instance.GetPlayerProfile();
							string text = ((playerProfile != null) ? playerProfile.GetName() : "");
							long playerID = ((playerProfile != null) ? playerProfile.GetPlayerID() : 0);
							if (HasCharacterSeenIntro(text, playerID))
							{
								Log.LogInfo((object)("New world movie already seen by character '" + text + "'."));
								__result = false;
								return false;
							}
						}
					}
				}
				if ((int)firstWithSetting == 4 || (int)firstWithSetting == 8)
				{
					if (ConfigEndingCinematics.Value == CinematicMode.Disabled)
					{
						Log.LogInfo((object)"Ending cinematic suppressed (Disabled mode).");
						if (onStop != null)
						{
							onStop.Invoke((VideoEntry)null, true);
						}
						__result = false;
						return false;
					}
					if (ConfigEndingCinematics.Value == CinematicMode.PlayOnce)
					{
						if (ConfigSeenEndingMovie.Value)
						{
							Log.LogInfo((object)"Ending cinematic already seen.");
							if (onStop != null)
							{
								onStop.Invoke((VideoEntry)null, true);
							}
							__result = false;
							return false;
						}
						ConfigSeenEndingMovie.Value = true;
						((BaseUnityPlugin)Instance).Config.Save();
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Exception in Patch_CinematicsManager_PlaySettings: " + ex));
			}
			return true;
		}
	}

	[HarmonyPatch(typeof(Game), "ShowIntro")]
	public static class Patch_Game_ShowIntro
	{
		private static bool Prefix(Game __instance)
		{
			if (!ConfigModEnabled.Value)
			{
				return true;
			}
			try
			{
				bool flag = false;
				if (ConfigNewWorldMovie.Value == CinematicMode.Disabled)
				{
					flag = true;
				}
				else if (ConfigNewWorldMovie.Value == CinematicMode.PlayOnce)
				{
					PlayerProfile playerProfile = __instance.GetPlayerProfile();
					string characterName = ((playerProfile != null) ? playerProfile.GetName() : "");
					long playerID = ((playerProfile != null) ? playerProfile.GetPlayerID() : 0);
					if (HasCharacterSeenIntro(characterName, playerID))
					{
						flag = true;
					}
				}
				if (flag)
				{
					Log.LogInfo((object)"New world intro lore text suppressed by CinematicControl.");
					Traverse.Create((object)__instance).Field("m_inIntro").SetValue((object)false);
					Traverse.Create((object)__instance).Field("m_queuedIntro").SetValue((object)false);
					if ((Object)(object)TextViewer.instance != (Object)null)
					{
						TextViewer.instance.HideIntro();
					}
					return false;
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Exception in Patch_Game_ShowIntro: " + ex));
			}
			return true;
		}
	}

	[HarmonyPatch(typeof(Valkyrie), "Awake")]
	public static class Patch_Valkyrie_Awake
	{
		private static void Postfix(Valkyrie __instance)
		{
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			if (!ConfigModEnabled.Value)
			{
				return;
			}
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if (!((Object)(object)localPlayer == (Object)null))
				{
					string playerName = localPlayer.GetPlayerName();
					long playerID = localPlayer.GetPlayerID();
					bool flag = HasCharacterSeenIntro(playerName, playerID);
					if (localPlayer.m_customData.ContainsKey("CinematicControl_ForceReplayValkyrie"))
					{
						flag = false;
						localPlayer.m_customData.Remove("CinematicControl_ForceReplayValkyrie");
					}
					bool flag2 = false;
					if (ConfigValkyrieFlight.Value == CinematicMode.Disabled)
					{
						flag2 = true;
					}
					else if (ConfigValkyrieFlight.Value == CinematicMode.PlayOnce && flag)
					{
						flag2 = true;
					}
					if (flag2)
					{
						Log.LogInfo((object)("Bypassing Valkyrie flight sequence for character '" + playerName + "'."));
						Vector3 position = ((Component)__instance).transform.position;
						Traverse val = Traverse.Create((object)__instance);
						Vector3 value = val.Field<Vector3>("m_targetPoint").Value;
						Vector3 value2 = val.Field<Vector3>("m_descentStart").Value;
						RevealFlightCorridor(position, value2, value);
						RecordCharacterSeen(playerName, playerID);
						((Behaviour)__instance).enabled = false;
						((MonoBehaviour)Instance).StartCoroutine(WaitForAreaAndCompleteDrop(localPlayer, __instance, value));
					}
					else
					{
						Log.LogInfo((object)("Playing maiden Valkyrie flight for character '" + playerName + "'."));
					}
				}
			}
			catch (Exception ex)
			{
				Log.LogError((object)("Exception in Patch_Valkyrie_Awake: " + ex));
			}
		}
	}

	[HarmonyPatch(typeof(Hud), "UpdateBlackScreen")]
	public static class Patch_Hud_UpdateBlackScreen
	{
		private static void Postfix(Hud __instance, Player player, float dt)
		{
			if (ConfigModEnabled.Value && _isWaitingForSpawnArea && (Object)(object)__instance != (Object)null)
			{
				if ((Object)(object)__instance.m_loadingScreen != (Object)null)
				{
					((Component)__instance.m_loadingScreen).gameObject.SetActive(true);
					__instance.m_loadingScreen.alpha = 1f;
				}
				if ((Object)(object)__instance.m_loadingProgress != (Object)null)
				{
					__instance.m_loadingProgress.SetActive(true);
				}
			}
		}
	}

	[HarmonyPatch(typeof(Valkyrie), "DropPlayer")]
	public static class Patch_Valkyrie_DropPlayer
	{
		private static void Postfix()
		{
			if (!ConfigModEnabled.Value)
			{
				return;
			}
			try
			{
				Player localPlayer = Player.m_localPlayer;
				if ((Object)(object)localPlayer != (Object)null)
				{
					RecordCharacterSeen(localPlayer.GetPlayerName(), localPlayer.GetPlayerID());
				}
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Exception in Patch_Valkyrie_DropPlayer: " + ex));
			}
		}
	}

	[HarmonyPatch(typeof(FejdStartup), "OnCinematics")]
	public static class Patch_FejdStartup_OnCinematics
	{
		private static void Postfix(FejdStartup __instance)
		{
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Expected O, but got Unknown
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Expected O, but got Unknown
			if (!ConfigModEnabled.Value)
			{
				return;
			}
			try
			{
				UnityAction val = null;
				if ((Object)(object)__instance.m_cinematicsBack == (Object)null)
				{
					return;
				}
				Transform parent = __instance.m_cinematicsBack.transform.parent;
				if ((Object)(object)parent == (Object)null)
				{
					return;
				}
				Transform val2 = parent.Find("CinematicControl_ResetButton");
				if ((Object)(object)val2 != (Object)null)
				{
					return;
				}
				GameObject val3 = Object.Instantiate<GameObject>(__instance.m_cinematicsBack, parent);
				((Object)val3).name = "CinematicControl_ResetButton";
				val3.transform.localScale = Vector3.one;
				int siblingIndex = __instance.m_cinematicsBack.transform.GetSiblingIndex();
				val3.transform.SetSiblingIndex(siblingIndex);
				TMP_Text text = val3.GetComponentInChildren<TMP_Text>();
				if ((Object)(object)text != (Object)null)
				{
					text.text = "RESET SEEN CINEMATICS";
				}
				Button component = val3.GetComponent<Button>();
				if ((Object)(object)component != (Object)null)
				{
					component.onClick = new ButtonClickedEvent();
					ButtonClickedEvent onClick = component.onClick;
					if (val == null)
					{
						val = (UnityAction)delegate
						{
							ResetAllSeenHistory();
							if ((Object)(object)text != (Object)null)
							{
								text.text = "<color=#00FF00>CINEMATICS RESET!</color>";
								((MonoBehaviour)__instance).StartCoroutine(RevertButtonText(text, "RESET SEEN CINEMATICS", 2f));
							}
						};
					}
					((UnityEvent)onClick).AddListener(val);
				}
				val3.SetActive(true);
				Log.LogInfo((object)"Added 'Reset Seen Cinematics' button to FejdStartup Cinematics sub-menu.");
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Exception in Patch_FejdStartup_OnCinematics: " + ex));
			}
		}

		private static IEnumerator RevertButtonText(TMP_Text text, string original, float delay)
		{
			yield return (object)new WaitForSecondsRealtime(delay);
			if ((Object)(object)text != (Object)null)
			{
				text.text = original;
			}
		}
	}

	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	public static class Patch_Terminal_InitTerminal
	{
		private static void Postfix()
		{
			//IL_0035: 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_0024: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			try
			{
				new ConsoleCommand("cinematic_reset", "Resets all CinematicControl 'seen' flags back to unplayed.", (ConsoleEvent)delegate(ConsoleEventArgs args)
				{
					ResetAllSeenHistory();
					args.Context.AddString("CinematicControl: All seen cinematic flags have been reset to unplayed!");
				}, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
				new ConsoleCommand("cinematiccontrol_reset", "Resets all CinematicControl 'seen' flags back to unplayed.", (ConsoleEvent)delegate(ConsoleEventArgs args)
				{
					ResetAllSeenHistory();
					args.Context.AddString("CinematicControl: All seen cinematic flags have been reset to unplayed!");
				}, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			}
			catch (Exception ex)
			{
				Log.LogWarning((object)("Exception in Patch_Terminal_InitTerminal: " + ex));
			}
		}
	}

	public const string PluginGUID = "com.drakosdj.cinematiccontrol";

	public const string PluginName = "CinematicControl";

	public const string PluginVersion = "1.0.2";

	private const string CustomDataKeyValkyrie = "CinematicControl_ValkyrieSeen";

	private const string CustomDataPrefixDream = "CinematicControl_DreamSeen_";

	public static ConfigEntry<bool> ConfigModEnabled;

	public static ConfigEntry<CinematicMode> ConfigStartupLogos;

	public static ConfigEntry<CinematicMode> ConfigLaunchCinematic;

	public static ConfigEntry<CinematicMode> ConfigNewWorldMovie;

	public static ConfigEntry<CinematicMode> ConfigValkyrieFlight;

	public static ConfigEntry<bool> ConfigRevealValkyrieMapPath;

	public static ConfigEntry<CinematicMode> ConfigDreamCinematics;

	public static ConfigEntry<CinematicMode> ConfigEndingCinematics;

	public static ConfigEntry<bool> ConfigSeenStartupLogos;

	public static ConfigEntry<bool> ConfigSeenLaunchMovie;

	public static ConfigEntry<bool> ConfigSeenEndingMovie;

	public static ConfigEntry<bool> ConfigResetSeenHistory;

	public static ConfigEntry<string> ConfigSeenCharacters;

	private Harmony _harmony;

	private static bool _isWaitingForSpawnArea = false;

	public static CinematicControlPlugin Instance { get; private set; }

	public static ManualLogSource Log { get; private set; }

	private void Awake()
	{
		//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f0: Expected O, but got Unknown
		//IL_0215: Unknown result type (might be due to invalid IL or missing references)
		//IL_021f: Expected O, but got Unknown
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		ConfigModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ModEnabled", true, "Master switch to enable or disable all CinematicControl features.");
		ConfigStartupLogos = ((BaseUnityPlugin)this).Config.Bind<CinematicMode>("Launch", "StartupLogos", CinematicMode.Disabled, "Controls the Iron Gate and Coffee Stain startup splash logos when launching the game. (AlwaysPlay = 0, PlayOnce = 1, Disabled = 2)");
		ConfigLaunchCinematic = ((BaseUnityPlugin)this).Config.Bind<CinematicMode>("Launch", "LaunchCinematic", CinematicMode.PlayOnce, "Controls the Valheim 1.0 animated launch cinematic played at game startup before the main menu. (AlwaysPlay = 0, PlayOnce = 1, Disabled = 2)");
		ConfigNewWorldMovie = ((BaseUnityPlugin)this).Config.Bind<CinematicMode>("World", "NewWorldMovie", CinematicMode.PlayOnce, "Controls the introductory lore movie played when entering a newly generated world. (AlwaysPlay = 0, PlayOnce = 1, Disabled = 2)");
		ConfigValkyrieFlight = ((BaseUnityPlugin)this).Config.Bind<CinematicMode>("Valkyrie", "ValkyrieFlight", CinematicMode.PlayOnce, "Controls the Valkyrie introductory flight into the world. PlayOnce plays the maiden flight for new characters, and skips subsequent world spawns. (AlwaysPlay = 0, PlayOnce = 1, Disabled = 2)");
		ConfigRevealValkyrieMapPath = ((BaseUnityPlugin)this).Config.Bind<bool>("Valkyrie", "RevealFlightMapPathOnSkip", true, "When the Valkyrie flight is bypassed/skipped, automatically reveal the flight path corridor on the world map fog-of-war.");
		ConfigDreamCinematics = ((BaseUnityPlugin)this).Config.Bind<CinematicMode>("Dreams", "DreamCinematics", CinematicMode.PlayOnce, "Controls the new 1.0 animated dream videos during sleep. When bypassed, seamlessly displays classic Valheim dream text instead. (AlwaysPlay = 0, PlayOnce = 1, Disabled = 2)");
		ConfigEndingCinematics = ((BaseUnityPlugin)this).Config.Bind<CinematicMode>("Ending", "EndingCinematics", CinematicMode.AlwaysPlay, "Controls the post-boss outro cutscene and game ending credits. (AlwaysPlay = 0, PlayOnce = 1, Disabled = 2)");
		ConfigSeenStartupLogos = ((BaseUnityPlugin)this).Config.Bind<bool>("State", "SeenStartupLogos", false, "Internal state: tracks whether startup logos have been seen at least once.");
		ConfigSeenLaunchMovie = ((BaseUnityPlugin)this).Config.Bind<bool>("State", "SeenLaunchMovie", false, "Internal state: tracks whether the game launch cinematic has been played at least once.");
		ConfigSeenEndingMovie = ((BaseUnityPlugin)this).Config.Bind<bool>("State", "SeenEndingMovie", false, "Internal state: tracks whether the game ending cinematics have been played at least once.");
		ConfigSeenCharacters = ((BaseUnityPlugin)this).Config.Bind<string>("State", "SeenCharacters", "", "Internal state: comma-separated list of character names that have completed their maiden Valkyrie / world intro sequence.");
		ConfigResetSeenHistory = ((BaseUnityPlugin)this).Config.Bind<bool>("Reset", "ResetSeenHistory", false, new ConfigDescription("Set to true (or click the button in Configuration Manager / FejdStartup Cinematics menu) to reset all 'Seen' playback history back to unplayed. Automatically reverts to false.", (AcceptableValueBase)null, new object[1]
		{
			new ConfigurationManagerAttributes
			{
				CustomDrawer = delegate
				{
					if (GUILayout.Button("Reset All Seen Cinematics", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) }))
					{
						ResetAllSeenHistory();
					}
				}
			}
		}));
		if (ConfigResetSeenHistory.Value)
		{
			ResetAllSeenHistory();
		}
		try
		{
			_harmony = new Harmony("com.drakosdj.cinematiccontrol");
			_harmony.PatchAll();
			Log.LogInfo((object)"CinematicControl v1.0.2 loaded successfully!");
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Failed to initialize Harmony patches: " + ex));
		}
	}

	private void Update()
	{
		if (ConfigResetSeenHistory != null && ConfigResetSeenHistory.Value)
		{
			ResetAllSeenHistory();
		}
	}

	public static bool HasCharacterSeenIntro(string characterName, long playerID)
	{
		try
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				if (localPlayer.m_customData.ContainsKey("CinematicControl_ForceReplayValkyrie"))
				{
					return false;
				}
				if (localPlayer.m_customData.ContainsKey("CinematicControl_ValkyrieSeen"))
				{
					return true;
				}
			}
			string text = ConfigSeenCharacters.Value ?? "";
			string[] array = text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
			string[] array2 = array;
			foreach (string text2 in array2)
			{
				string text3 = text2.Trim();
				if (!string.IsNullOrEmpty(characterName) && string.Equals(text3, characterName, StringComparison.OrdinalIgnoreCase))
				{
					return true;
				}
				if (playerID != 0 && text3 == playerID.ToString())
				{
					return true;
				}
			}
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Exception in HasCharacterSeenIntro: " + ex));
		}
		return false;
	}

	public static void RecordCharacterSeen(string characterName, long playerID)
	{
		try
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				localPlayer.m_customData["CinematicControl_ValkyrieSeen"] = "true";
				localPlayer.m_customData["CinematicControl_WorldMovieSeen"] = "true";
			}
			string text = ConfigSeenCharacters.Value ?? "";
			List<string> list = new List<string>(text.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries));
			if (!string.IsNullOrEmpty(characterName) && !list.Contains(characterName))
			{
				list.Add(characterName);
			}
			ConfigSeenCharacters.Value = string.Join(",", list.ToArray());
			((BaseUnityPlugin)Instance).Config.Save();
			Log.LogInfo((object)("Character '" + characterName + "' (ID: " + playerID + ") recorded as having seen maiden Valkyrie / world intro."));
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Exception in RecordCharacterSeen: " + ex));
		}
	}

	public static void ResetAllSeenHistory()
	{
		try
		{
			ConfigSeenLaunchMovie.Value = false;
			ConfigSeenStartupLogos.Value = false;
			ConfigSeenEndingMovie.Value = false;
			ConfigSeenCharacters.Value = "";
			if (ConfigResetSeenHistory != null)
			{
				ConfigResetSeenHistory.Value = false;
			}
			((BaseUnityPlugin)Instance).Config.Save();
			try
			{
				if (PlatformPrefs.GetBool("SkipIntroCinematic", false))
				{
					PlatformPrefs.SetBool("SkipIntroCinematic", false);
				}
			}
			catch
			{
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				localPlayer.m_customData.Remove("CinematicControl_ValkyrieSeen");
				localPlayer.m_customData.Remove("CinematicControl_WorldMovieSeen");
				localPlayer.m_customData["CinematicControl_ForceReplayValkyrie"] = "true";
				List<string> list = new List<string>();
				foreach (string key in localPlayer.m_customData.Keys)
				{
					if (key.StartsWith("CinematicControl_DreamSeen_"))
					{
						list.Add(key);
					}
				}
				foreach (string item in list)
				{
					localPlayer.m_customData.Remove(item);
				}
				((Character)localPlayer).Message((MessageType)2, "All cinematic history reset to unplayed!", 0, (Sprite)null, false);
			}
			Log.LogInfo((object)"All cinematic 'Seen' history flags have been reset to unplayed.");
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Exception in ResetAllSeenHistory: " + ex));
		}
	}

	private void OnDestroy()
	{
		if (_harmony != null)
		{
			_harmony.UnpatchSelf();
		}
	}

	private static void RevealFlightCorridor(Vector3 startPos, Vector3 descentStart, Vector3 targetPoint)
	{
		//IL_006e: 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_0099: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0117: Unknown result type (might be due to invalid IL or missing references)
		//IL_0118: Unknown result type (might be due to invalid IL or missing references)
		//IL_011b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		if (!ConfigRevealValkyrieMapPath.Value || (Object)(object)Minimap.instance == (Object)null)
		{
			return;
		}
		try
		{
			float num = 100f;
			Traverse val = Traverse.Create((object)Minimap.instance);
			Traverse<float> val2 = val.Field<float>("m_exploreRadius");
			if (val2 != null && val2.Value > 10f)
			{
				num = val2.Value;
			}
			float num2 = Vector3.Distance(startPos, descentStart);
			int num3 = Mathf.Max(2, Mathf.CeilToInt(num2 / 20f));
			for (int i = 0; i <= num3; i++)
			{
				float num4 = (float)i / (float)num3;
				Vector3 val3 = Vector3.Lerp(startPos, descentStart, num4);
				val.Method("Explore", new object[2] { val3, num }).GetValue();
			}
			float num5 = Vector3.Distance(descentStart, targetPoint);
			int num6 = Mathf.Max(2, Mathf.CeilToInt(num5 / 20f));
			for (int i = 0; i <= num6; i++)
			{
				float num4 = (float)i / (float)num6;
				Vector3 val3 = Vector3.Lerp(descentStart, targetPoint, num4);
				val.Method("Explore", new object[2] { val3, num }).GetValue();
			}
			Log.LogInfo((object)("Full flight corridor explored on world map: Leg 1 = " + num2.ToString("F0") + "m, Leg 2 = " + num5.ToString("F0") + "m (Total: " + (num2 + num5).ToString("F0") + "m)."));
		}
		catch (Exception ex)
		{
			Log.LogWarning((object)("Could not explore flight path on minimap: " + ex));
		}
	}

	private static IEnumerator WaitForAreaAndCompleteDrop(Player player, Valkyrie valkyrie, Vector3 targetPoint)
	{
		//IL_0016: 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)
		_isWaitingForSpawnArea = true;
		float timeout = 10f;
		float elapsed = 0f;
		bool areaReady = false;
		float num = default(float);
		while (elapsed < timeout)
		{
			if ((Object)(object)player == (Object)null || (Object)(object)Game.instance == (Object)null || Game.instance.IsShuttingDown())
			{
				_isWaitingForSpawnArea = false;
				yield break;
			}
			elapsed += Time.deltaTime;
			if ((Object)(object)ZNetScene.instance != (Object)null && ZNetScene.instance.IsAreaReady(targetPoint) && (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.FindFloor(targetPoint, ref num))
			{
				targetPoint.y = num + 0.15f;
				areaReady = true;
				break;
			}
			yield return null;
		}
		if (!areaReady)
		{
			Log.LogWarning((object)("Spawn area readiness timed out after " + elapsed.ToString("F1") + "s. Snapping to estimated ground height."));
			float num2 = default(float);
			if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGroundHeight(targetPoint, ref num2))
			{
				targetPoint.y = num2 + 0.25f;
			}
		}
		else
		{
			Log.LogInfo((object)("Spawn area fully populated and stone floor confirmed in " + elapsed.ToString("F1") + "s."));
		}
		if ((Object)(object)player != (Object)null)
		{
			((Component)player).transform.position = targetPoint;
			Rigidbody component = ((Component)player).GetComponent<Rigidbody>();
			if ((Object)(object)component != (Object)null)
			{
				component.position = targetPoint;
				component.linearVelocity = Vector3.zero;
			}
			player.SetIntro(false);
		}
		if ((Object)(object)valkyrie != (Object)null)
		{
			valkyrie.DropPlayer(true);
		}
		if ((Object)(object)TextViewer.instance != (Object)null)
		{
			TextViewer.instance.HideIntro();
		}
		if ((Object)(object)Game.instance != (Object)null)
		{
			Traverse.Create((object)Game.instance).Field("m_inIntro").SetValue((object)false);
			Traverse.Create((object)Game.instance).Field("m_queuedIntro").SetValue((object)false);
		}
		yield return (object)new WaitForSeconds(0.2f);
		_isWaitingForSpawnArea = false;
		Log.LogInfo((object)"Loading screen dismissed. Player arrived safely at spawn stones with all structures and flora loaded.");
	}
}
public class ConfigurationManagerAttributes
{
	public Action<ConfigEntryBase> CustomDrawer;

	public bool? Browsable;

	public bool? ReadOnly;

	public bool? HideDefaultButton;

	public bool? HideSettingName;

	public string Description;

	public string DispName;

	public int? Order;
}