mirror of
https://github.com/Outer-Wilds-New-Horizons/new-horizons.git
synced 2025-12-11 20:15:44 +01:00
Add support to addon manifest
This commit is contained in:
parent
37c43d0104
commit
929b463c47
@ -11,11 +11,8 @@ namespace NewHorizons.Builder.Volumes
|
|||||||
{
|
{
|
||||||
var volume = VolumeBuilder.Make<LoadCreditsVolume>(planetGO, sector, info);
|
var volume = VolumeBuilder.Make<LoadCreditsVolume>(planetGO, sector, info);
|
||||||
|
|
||||||
volume.creditsType = info.creditsType;
|
volume.gameOver = info.gameOver;
|
||||||
volume.gameOverText = info.gameOver?.text;
|
|
||||||
volume.deathType = info.deathType == null ? null : EnumUtils.Parse(info.deathType.ToString(), DeathType.Default);
|
volume.deathType = info.deathType == null ? null : EnumUtils.Parse(info.deathType.ToString(), DeathType.Default);
|
||||||
volume.colour = info.gameOver?.colour?.ToColor();
|
|
||||||
volume.condition = info.gameOver?.condition;
|
|
||||||
|
|
||||||
return volume;
|
return volume;
|
||||||
}
|
}
|
||||||
|
|||||||
138
NewHorizons/Components/NHGameOverManager.cs
Normal file
138
NewHorizons/Components/NHGameOverManager.cs
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
using NewHorizons.External.Modules;
|
||||||
|
using NewHorizons.External.SerializableEnums;
|
||||||
|
using NewHorizons.Handlers;
|
||||||
|
using NewHorizons.Utility.OWML;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NewHorizons.Components
|
||||||
|
{
|
||||||
|
public class NHGameOverManager : MonoBehaviour
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Mod unique id to game over module list
|
||||||
|
/// Done as a dictionary so that Reload Configs can overwrite entries per mod
|
||||||
|
/// </summary>
|
||||||
|
public static Dictionary<string, GameOverModule[]> gameOvers = new();
|
||||||
|
|
||||||
|
public static NHGameOverManager Instance { get; private set; }
|
||||||
|
|
||||||
|
private GameOverController _gameOverController;
|
||||||
|
private PlayerCameraEffectController _playerCameraEffectController;
|
||||||
|
|
||||||
|
private GameOverModule[] _gameOvers;
|
||||||
|
|
||||||
|
private bool _gameOverSequenceStarted;
|
||||||
|
|
||||||
|
public void Awake()
|
||||||
|
{
|
||||||
|
Instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
_gameOverController = FindObjectOfType<GameOverController>();
|
||||||
|
_playerCameraEffectController = FindObjectOfType<PlayerCameraEffectController>();
|
||||||
|
|
||||||
|
_gameOvers = gameOvers.SelectMany(x => x.Value).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void TryHijackDeathSequence()
|
||||||
|
{
|
||||||
|
var gameOver = _gameOvers.FirstOrDefault(x => !string.IsNullOrEmpty(x.condition) && DialogueConditionManager.SharedInstance.GetConditionState(x.condition));
|
||||||
|
if (!_gameOverSequenceStarted && gameOver != null && !Locator.GetDeathManager()._finishedDLC)
|
||||||
|
{
|
||||||
|
StartGameOverSequence(gameOver, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartGameOverSequence(GameOverModule gameOver, DeathType? deathType)
|
||||||
|
{
|
||||||
|
_gameOverSequenceStarted = true;
|
||||||
|
Delay.StartCoroutine(GameOver(gameOver, deathType));
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerator GameOver(GameOverModule gameOver, DeathType? deathType)
|
||||||
|
{
|
||||||
|
OWInput.ChangeInputMode(InputMode.None);
|
||||||
|
ReticleController.Hide();
|
||||||
|
Locator.GetPromptManager().SetPromptsVisible(false);
|
||||||
|
Locator.GetPauseCommandListener().AddPauseCommandLock();
|
||||||
|
|
||||||
|
// The PlayerCameraEffectController is what actually kills us, so convince it we're already dead
|
||||||
|
Locator.GetDeathManager()._isDead = true;
|
||||||
|
|
||||||
|
var fadeLength = 2f;
|
||||||
|
|
||||||
|
if (Locator.GetDeathManager()._isDying)
|
||||||
|
{
|
||||||
|
// Player already died at this point, so don't fade
|
||||||
|
fadeLength = 0f;
|
||||||
|
}
|
||||||
|
else if (deathType is DeathType nonNullDeathType)
|
||||||
|
{
|
||||||
|
_playerCameraEffectController.OnPlayerDeath(nonNullDeathType);
|
||||||
|
fadeLength = _playerCameraEffectController._deathFadeLength;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Wake up relaxed next loop
|
||||||
|
PlayerData.SetLastDeathType(DeathType.Meditation);
|
||||||
|
FadeHandler.FadeOut(fadeLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return new WaitForSeconds(fadeLength);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(gameOver.text) && _gameOverController != null)
|
||||||
|
{
|
||||||
|
_gameOverController._deathText.text = TranslationHandler.GetTranslation(gameOver.text, TranslationHandler.TextType.UI);
|
||||||
|
_gameOverController.SetupGameOverScreen(5f);
|
||||||
|
|
||||||
|
if (gameOver.colour != null)
|
||||||
|
{
|
||||||
|
_gameOverController._deathText.color = gameOver.colour.ToColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the fade handler is off now
|
||||||
|
FadeHandler.FadeIn(0f);
|
||||||
|
|
||||||
|
// We set this to true to stop it from loading the credits scene, so we can do it ourselves
|
||||||
|
_gameOverController._loading = true;
|
||||||
|
|
||||||
|
yield return new WaitUntil(ReadytoLoadCreditsScene);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadCreditsScene(gameOver);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ReadytoLoadCreditsScene() => _gameOverController._fadedOutText && _gameOverController._textAnimator.IsComplete();
|
||||||
|
|
||||||
|
private void LoadCreditsScene(GameOverModule gameOver)
|
||||||
|
{
|
||||||
|
NHLogger.LogVerbose($"Load credits {gameOver.creditsType}");
|
||||||
|
|
||||||
|
switch (gameOver.creditsType)
|
||||||
|
{
|
||||||
|
case NHCreditsType.Fast:
|
||||||
|
LoadManager.LoadScene(OWScene.Credits_Fast, LoadManager.FadeType.ToBlack);
|
||||||
|
break;
|
||||||
|
case NHCreditsType.Final:
|
||||||
|
LoadManager.LoadScene(OWScene.Credits_Final, LoadManager.FadeType.ToBlack);
|
||||||
|
break;
|
||||||
|
case NHCreditsType.Kazoo:
|
||||||
|
TimelineObliterationController.s_hasRealityEnded = true;
|
||||||
|
LoadManager.LoadScene(OWScene.Credits_Fast, LoadManager.FadeType.ToBlack);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// GameOverController disables post processing
|
||||||
|
_gameOverController._flashbackCamera.postProcessing.enabled = true;
|
||||||
|
// For some reason this isn't getting set sometimes
|
||||||
|
AudioListener.volume = 1;
|
||||||
|
GlobalMessenger.FireEvent("TriggerFlashback");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,4 @@
|
|||||||
using NewHorizons.External.SerializableEnums;
|
using NewHorizons.External.Modules;
|
||||||
using NewHorizons.Handlers;
|
|
||||||
using NewHorizons.Utility;
|
|
||||||
using NewHorizons.Utility.OWML;
|
|
||||||
using System.Collections;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
|
|
||||||
@ -10,108 +6,17 @@ namespace NewHorizons.Components.Volumes
|
|||||||
{
|
{
|
||||||
internal class LoadCreditsVolume : BaseVolume
|
internal class LoadCreditsVolume : BaseVolume
|
||||||
{
|
{
|
||||||
public NHCreditsType creditsType = NHCreditsType.None;
|
public GameOverModule gameOver;
|
||||||
|
public DeathType? deathType;
|
||||||
public string gameOverText;
|
|
||||||
public DeathType? deathType = DeathType.Default;
|
|
||||||
|
|
||||||
public Color? colour;
|
|
||||||
public string condition;
|
|
||||||
|
|
||||||
private GameOverController _gameOverController;
|
|
||||||
private PlayerCameraEffectController _playerCameraEffectController;
|
|
||||||
|
|
||||||
public void Start()
|
|
||||||
{
|
|
||||||
_gameOverController = FindObjectOfType<GameOverController>();
|
|
||||||
_playerCameraEffectController = FindObjectOfType<PlayerCameraEffectController>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void OnTriggerVolumeEntry(GameObject hitObj)
|
public override void OnTriggerVolumeEntry(GameObject hitObj)
|
||||||
{
|
{
|
||||||
if (hitObj.CompareTag("PlayerDetector") && enabled && (string.IsNullOrEmpty(condition) || DialogueConditionManager.SharedInstance.GetConditionState(condition)))
|
if (hitObj.CompareTag("PlayerDetector") && enabled && (string.IsNullOrEmpty(gameOver.condition) || DialogueConditionManager.SharedInstance.GetConditionState(gameOver.condition)))
|
||||||
{
|
{
|
||||||
// Have to run it off the mod behaviour since the game over controller disables everything
|
NHGameOverManager.Instance.StartGameOverSequence(gameOver, deathType);
|
||||||
Delay.StartCoroutine(GameOver());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerator GameOver()
|
|
||||||
{
|
|
||||||
OWInput.ChangeInputMode(InputMode.None);
|
|
||||||
ReticleController.Hide();
|
|
||||||
Locator.GetPromptManager().SetPromptsVisible(false);
|
|
||||||
Locator.GetPauseCommandListener().AddPauseCommandLock();
|
|
||||||
|
|
||||||
// The PlayerCameraEffectController is what actually kills us, so convince it we're already dead
|
|
||||||
Locator.GetDeathManager()._isDead = true;
|
|
||||||
|
|
||||||
var fadeLength = 2f;
|
|
||||||
|
|
||||||
if (deathType is DeathType nonNullDeathType)
|
|
||||||
{
|
|
||||||
_playerCameraEffectController.OnPlayerDeath(nonNullDeathType);
|
|
||||||
fadeLength = _playerCameraEffectController._deathFadeLength;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Wake up relaxed next loop
|
|
||||||
PlayerData.SetLastDeathType(DeathType.Meditation);
|
|
||||||
FadeHandler.FadeOut(fadeLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return new WaitForSeconds(fadeLength);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(gameOverText) && _gameOverController != null)
|
|
||||||
{
|
|
||||||
_gameOverController._deathText.text = TranslationHandler.GetTranslation(gameOverText, TranslationHandler.TextType.UI);
|
|
||||||
_gameOverController.SetupGameOverScreen(5f);
|
|
||||||
|
|
||||||
if (colour != null)
|
|
||||||
{
|
|
||||||
_gameOverController._deathText.color = (Color)colour;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the fade handler is off now
|
|
||||||
FadeHandler.FadeIn(0f);
|
|
||||||
|
|
||||||
// We set this to true to stop it from loading the credits scene, so we can do it ourselves
|
|
||||||
_gameOverController._loading = true;
|
|
||||||
|
|
||||||
yield return new WaitUntil(ReadytoLoadCreditsScene);
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadCreditsScene();
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ReadytoLoadCreditsScene() => _gameOverController._fadedOutText && _gameOverController._textAnimator.IsComplete();
|
|
||||||
|
|
||||||
public override void OnTriggerVolumeExit(GameObject hitObj) { }
|
public override void OnTriggerVolumeExit(GameObject hitObj) { }
|
||||||
|
|
||||||
private void LoadCreditsScene()
|
|
||||||
{
|
|
||||||
NHLogger.LogVerbose($"Load credits {creditsType}");
|
|
||||||
|
|
||||||
switch (creditsType)
|
|
||||||
{
|
|
||||||
case NHCreditsType.Fast:
|
|
||||||
LoadManager.LoadScene(OWScene.Credits_Fast, LoadManager.FadeType.ToBlack);
|
|
||||||
break;
|
|
||||||
case NHCreditsType.Final:
|
|
||||||
LoadManager.LoadScene(OWScene.Credits_Final, LoadManager.FadeType.ToBlack);
|
|
||||||
break;
|
|
||||||
case NHCreditsType.Kazoo:
|
|
||||||
TimelineObliterationController.s_hasRealityEnded = true;
|
|
||||||
LoadManager.LoadScene(OWScene.Credits_Fast, LoadManager.FadeType.ToBlack);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// GameOverController disables post processing
|
|
||||||
_gameOverController._flashbackCamera.postProcessing.enabled = true;
|
|
||||||
// For some reason this isn't getting set sometimes
|
|
||||||
AudioListener.volume = 1;
|
|
||||||
GlobalMessenger.FireEvent("TriggerFlashback");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
7
NewHorizons/External/Configs/AddonConfig.cs
vendored
7
NewHorizons/External/Configs/AddonConfig.cs
vendored
@ -1,3 +1,4 @@
|
|||||||
|
using NewHorizons.External.Modules;
|
||||||
using NewHorizons.OtherMods.AchievementsPlus;
|
using NewHorizons.OtherMods.AchievementsPlus;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
@ -44,5 +45,11 @@ namespace NewHorizons.External.Configs
|
|||||||
/// The dimensions of the Echoes of the Eye subtitle is 669 x 67, so aim for that size
|
/// The dimensions of the Echoes of the Eye subtitle is 669 x 67, so aim for that size
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string subtitlePath = "subtitle.png";
|
public string subtitlePath = "subtitle.png";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Custom game over messages for this mod. This can either display a title card before looping like in EOTE, or show a message and roll credits like the various time loop escape endings.
|
||||||
|
/// You must set a dialogue condition for the game over sequence to run.
|
||||||
|
/// </summary>
|
||||||
|
public GameOverModule[] gameOver;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
NewHorizons/External/Configs/PlanetConfig.cs
vendored
4
NewHorizons/External/Configs/PlanetConfig.cs
vendored
@ -670,6 +670,10 @@ namespace NewHorizons.External.Configs
|
|||||||
}
|
}
|
||||||
volume.gameOver.text = volume.gameOverText;
|
volume.gameOver.text = volume.gameOverText;
|
||||||
}
|
}
|
||||||
|
if (volume.creditsType != null)
|
||||||
|
{
|
||||||
|
volume.gameOver.creditsType = (SerializableEnums.NHCreditsType)volume.creditsType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
using NewHorizons.External.SerializableData;
|
using NewHorizons.External.SerializableData;
|
||||||
|
using NewHorizons.External.SerializableEnums;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace NewHorizons.External.Modules
|
namespace NewHorizons.External.Modules
|
||||||
{
|
{
|
||||||
@ -17,9 +19,14 @@ namespace NewHorizons.External.Modules
|
|||||||
public MColor colour;
|
public MColor colour;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Condition that must be true for this game over to trigger. Leave empty to always trigger this game over.
|
/// Condition that must be true for this game over to trigger. If this is on a LoadCreditsVolume, leave empty to always trigger this game over.
|
||||||
/// Note this is a regular dialogue condition, not a persistent condition.
|
/// Note this is a regular dialogue condition, not a persistent condition.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string condition;
|
public string condition;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The type of credits that will run after the game over message is shown
|
||||||
|
/// </summary>
|
||||||
|
[DefaultValue("fast")] public NHCreditsType creditsType = NHCreditsType.Fast;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,9 +8,10 @@ namespace NewHorizons.External.Modules.Volumes.VolumeInfos
|
|||||||
[JsonObject]
|
[JsonObject]
|
||||||
public class LoadCreditsVolumeInfo : VolumeInfo
|
public class LoadCreditsVolumeInfo : VolumeInfo
|
||||||
{
|
{
|
||||||
[DefaultValue("none")] public NHCreditsType creditsType = NHCreditsType.None;
|
[Obsolete("Use gameOver.creditsType")]
|
||||||
|
public NHCreditsType? creditsType;
|
||||||
|
|
||||||
[Obsolete("Use gameOver")]
|
[Obsolete("Use gameOver.text")]
|
||||||
public string gameOverText;
|
public string gameOverText;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -6,6 +6,7 @@ using NewHorizons.Builder.Props;
|
|||||||
using NewHorizons.Builder.Props.Audio;
|
using NewHorizons.Builder.Props.Audio;
|
||||||
using NewHorizons.Builder.Props.EchoesOfTheEye;
|
using NewHorizons.Builder.Props.EchoesOfTheEye;
|
||||||
using NewHorizons.Builder.Props.TranslatorText;
|
using NewHorizons.Builder.Props.TranslatorText;
|
||||||
|
using NewHorizons.Components;
|
||||||
using NewHorizons.Components.EOTE;
|
using NewHorizons.Components.EOTE;
|
||||||
using NewHorizons.Components.Fixers;
|
using NewHorizons.Components.Fixers;
|
||||||
using NewHorizons.Components.Ship;
|
using NewHorizons.Components.Ship;
|
||||||
@ -483,6 +484,8 @@ namespace NewHorizons
|
|||||||
// Fix spawn point
|
// Fix spawn point
|
||||||
PlayerSpawnHandler.SetUpPlayerSpawn();
|
PlayerSpawnHandler.SetUpPlayerSpawn();
|
||||||
|
|
||||||
|
new GameObject(nameof(NHGameOverManager)).AddComponent<NHGameOverManager>();
|
||||||
|
|
||||||
if (isSolarSystem)
|
if (isSolarSystem)
|
||||||
{
|
{
|
||||||
// Warp drive
|
// Warp drive
|
||||||
@ -835,6 +838,10 @@ namespace NewHorizons
|
|||||||
AssetBundleUtilities.PreloadBundle(bundle, mod);
|
AssetBundleUtilities.PreloadBundle(bundle, mod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (addonConfig.gameOver != null)
|
||||||
|
{
|
||||||
|
NHGameOverManager.gameOvers[mod.ModHelper.Manifest.UniqueName] = addonConfig.gameOver;
|
||||||
|
}
|
||||||
|
|
||||||
AddonConfigs[mod] = addonConfig;
|
AddonConfigs[mod] = addonConfig;
|
||||||
}
|
}
|
||||||
|
|||||||
15
NewHorizons/Patches/DeathManagerPatches.cs
Normal file
15
NewHorizons/Patches/DeathManagerPatches.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using NewHorizons.Components;
|
||||||
|
|
||||||
|
namespace NewHorizons.Patches;
|
||||||
|
|
||||||
|
[HarmonyPatch]
|
||||||
|
public static class DeathManagerPatches
|
||||||
|
{
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(typeof(DeathManager), nameof(DeathManager.FinishDeathSequence))]
|
||||||
|
public static void DeathManager_FinishDeathSequence()
|
||||||
|
{
|
||||||
|
NHGameOverManager.Instance.TryHijackDeathSequence();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user