quantum-space-buddies/QSB/DeathSync/RespawnOnDeath.cs
2023-08-03 00:36:08 +01:00

323 lines
10 KiB
C#

using OWML.Common;
using QSB.Localization;
using QSB.Player;
using QSB.Player.TransformSync;
using QSB.RespawnSync;
using QSB.ShipSync;
using QSB.Utility;
using QSB.WorldSync;
using System.Linq;
using UnityEngine;
namespace QSB.DeathSync;
public class RespawnOnDeath : MonoBehaviour
{
public static RespawnOnDeath Instance;
public readonly DeathType[] AllowedDeathTypes =
{
DeathType.BigBang,
DeathType.Supernova,
DeathType.TimeLoop
};
private SpawnPoint _playerSpawnPoint;
private PlayerSpawner _playerSpawner;
private FluidDetector _fluidDetector;
private PlayerResources _playerResources;
private PlayerSpacesuit _spaceSuit;
private SuitPickupVolume[] _suitPickupVolumes;
private Vector3 _deathPositionRelative;
private GUIStyle _deadTextStyle;
public Transform DeathClosestAstroObject { get; private set; }
public Vector3 DeathPositionWorld
=> DeathClosestAstroObject == null
? Vector3.zero
: DeathClosestAstroObject.TransformPoint(_deathPositionRelative);
public Vector3 DeathPlayerUpVector { get; private set; }
public Vector3 DeathPlayerForwardVector { get; private set; }
public void Awake() => Instance = this;
public void Init()
{
DebugLog.DebugWrite($"INIT");
var playerTransform = Locator.GetPlayerTransform();
_playerResources = playerTransform.GetComponent<PlayerResources>();
_spaceSuit = Locator.GetPlayerSuit();
_playerSpawner = FindObjectOfType<PlayerSpawner>();
_suitPickupVolumes = FindObjectsOfType<SuitPickupVolume>();
_fluidDetector = Locator.GetPlayerCamera().GetComponentInChildren<FluidDetector>();
_playerSpawnPoint = GetSpawnPoint();
_deadTextStyle = new();
_deadTextStyle.font = (Font)Resources.Load(@"fonts\english - latin\SpaceMono-Regular_Dynamic");
_deadTextStyle.alignment = TextAnchor.MiddleCenter;
_deadTextStyle.normal.textColor = Color.white;
_deadTextStyle.fontSize = 20;
}
public void ResetPlayer()
{
DebugLog.DebugWrite($"RESET PLAYER");
if (_playerSpawnPoint == null)
{
DebugLog.ToConsole("Warning - _playerSpawnPoint is null!", MessageType.Warning);
Init();
}
RespawnManager.Instance.TriggerRespawnMap();
SetupDeathPositions();
// do some exit dream world stuff since real deaths dont do that
if (PlayerState.InDreamWorld())
{
ResetPlayerDreamworld();
}
ResetCloak();
ResetPlayerComponents();
ResetCanvases();
var mixer = Locator.GetAudioMixer();
mixer._deathMixed = false;
mixer._nonEndTimesVolume.FadeTo(1, 0.5f);
mixer._endTimesVolume.FadeTo(1, 0.5f);
mixer.MixMap();
var playerBody = Locator.GetPlayerBody();
playerBody.WarpToPositionRotation(_playerSpawnPoint.transform.position, _playerSpawnPoint.transform.rotation);
playerBody.SetVelocity(_playerSpawnPoint.GetPointVelocity());
_playerSpawnPoint.AddObjectToTriggerVolumes(Locator.GetPlayerDetector().gameObject);
_playerSpawnPoint.AddObjectToTriggerVolumes(_fluidDetector.gameObject);
_playerSpawnPoint.OnSpawnPlayer();
_playerResources._isSuffocating = false;
_playerResources.DebugRefillResources();
// death by oxygen turns this off, so we gotta enable it again
Delay.RunNextFrame(() => _playerResources.enabled = true);
ResetSuitState();
QSBPlayerManager.LocalPlayer.LocalFlashlight.TurnOff(false);
}
private void SetupDeathPositions()
{
var inSpace = PlayerTransformSync.LocalInstance.SectorDetector.SectorList.Count == 0;
if (inSpace)
{
DeathClosestAstroObject = Locator.GetAstroObject(AstroObject.Name.Sun).transform;
}
else
{
var allAstroobjects = QSBWorldSync.GetUnityObjects<AstroObject>().Where(x => x.GetAstroObjectName() != AstroObject.Name.None && x.GetAstroObjectType() != AstroObject.Type.Satellite);
var closest = allAstroobjects.MinBy(x => Vector3.SqrMagnitude(x.transform.position));
DeathClosestAstroObject = closest.transform;
}
var deathPosition = Locator.GetPlayerTransform().position;
_deathPositionRelative = DeathClosestAstroObject.InverseTransformPoint(deathPosition);
DeathPlayerUpVector = Locator.GetPlayerTransform().up;
DeathPlayerForwardVector = Locator.GetPlayerTransform().forward;
}
private void ResetPlayerDreamworld()
{
var __instance = Locator.GetDreamWorldController();
var wakeType = DreamWakeType.Default; // TODO maybe get actual death type? idk
__instance._wakeType = wakeType;
__instance.CheckDreamZone2Completion();
__instance.CheckSleepWakeDieAchievement(wakeType);
__instance._activeGhostGrabController?.ReleasePlayer();
__instance._activeZoomPoint?.CancelZoom();
if (__instance._outsideLanternBounds)
{
__instance.EnterLanternBounds();
}
__instance._simulationCamera.OnExitDreamWorld();
SunLightController.UnregisterSunOverrider(__instance);
if (__instance._proxyShadowLight != null)
{
__instance._proxyShadowLight.enabled = true;
}
__instance._insideDream = false;
__instance._waitingToLightLantern = false;
__instance._playerLantern.OnExitDreamWorld();
// TODO : drop player lantern at campfire
Locator.GetPlayerSectorDetector().RemoveFromAllSectors();
__instance._playerLantern.OnExitDreamWorld();
__instance._dreamArrivalPoint.OnExitDreamWorld();
__instance._dreamCampfire.OnDreamCampfireExtinguished -= __instance.OnDreamCampfireExtinguished;
__instance._dreamCampfire = null;
__instance.ExtinguishDreamRaft();
Locator.GetAudioMixer().UnmixDreamWorld();
Locator.GetAudioMixer().UnmixSleepAtCampfire(1f);
if (__instance._playerCamAmbientLightRenderer != null)
{
__instance._playerCamAmbientLightRenderer.enabled = false;
}
__instance._playerCamera.cullingMask |= 1 << LayerMask.NameToLayer("Sun");
__instance._playerCamera.farClipPlane = __instance._prevPlayerCameraFarPlaneDist;
__instance._prevPlayerCameraFarPlaneDist = 0f;
__instance._playerCamera.mainCamera.backgroundColor = Color.black;
__instance._playerCamera.planetaryFog.enabled = true;
__instance._playerCamera.postProcessingSettings.screenSpaceReflectionAvailable = false;
__instance._playerCamera.postProcessingSettings.ambientOcclusionAvailable = true;
GlobalMessenger.FireEvent("ExitDreamWorld");
}
private void ResetCanvases()
{
foreach (var item in QSBWorldSync.GetUnityObjects<ScreenPromptList>())
{
item.OnPlayerResurrection();
}
foreach (var item in QSBWorldSync.GetUnityObjects<ThrustAndAttitudeIndicator>())
{
item.enabled = true;
}
foreach (var item in QSBWorldSync.GetUnityObjects<HUDCanvas>())
{
item.enabled = true;
}
foreach (var item in QSBWorldSync.GetUnityObjects<ReferenceFrameGUI>())
{
item.enabled = true;
item._activeCam = Locator.GetMapController()._mapCamera;
item._isMapView = true;
}
foreach (var item in QSBWorldSync.GetUnityObjects<AutopilotGUI>())
{
item.enabled = true;
}
}
private void ResetSuitState()
{
_spaceSuit.RemoveSuit(true);
foreach (var pickupVolume in _suitPickupVolumes)
{
if (!pickupVolume._containsSuit && pickupVolume._allowSuitReturn)
{
pickupVolume._containsSuit = true;
pickupVolume._interactVolume.ChangePrompt(UITextType.SuitUpPrompt, pickupVolume._pickupSuitCommandIndex);
pickupVolume._suitGeometry.SetActive(true);
pickupVolume._suitOWCollider.SetActivation(true);
foreach (var geo in pickupVolume._toolGeometry)
{
geo.SetActive(true);
}
}
}
}
private void ResetCloak()
{
if (!QSBCore.DLCInstalled)
{
return;
}
var cloak = Locator.GetCloakFieldController();
// visible stranger disables cloak
if (cloak)
{
cloak._playerInsideCloak = false;
cloak._playerCloakFactor = 0f;
cloak._worldFadeFactor = 0f;
cloak._interiorRevealFactor = 0f;
cloak._rendererFade = 1;
cloak.OnPlayerExit.Invoke();
}
GlobalMessenger.FireEvent("ExitCloak");
}
private void ResetPlayerComponents()
{
var sectorList = PlayerTransformSync.LocalInstance.SectorDetector.SectorList;
if (sectorList.All(x => x.Type != Sector.Name.TimberHearth))
{
// Spooky scary legacy code?
// Original comment was "stops sectors from breaking when you die on TH??"
// I think dying on TH used to break all the sectors. Something about you not technically re-entering TH when dying inside it.
// I commented out these lines, and everything seemed fine. But I'm not gonna touch them just in case. :P
Locator.GetPlayerSectorDetector().RemoveFromAllSectors();
Locator.GetPlayerCameraDetector().GetComponent<AudioDetector>().DeactivateAllVolumes(0f);
}
PlayerState._isDead = false;
Locator.GetPlayerController().OnPlayerResurrection();
QSBWorldSync.GetUnityObject<PlayerBreathingAudio>().enabled = true;
Locator.GetPlayerCamera().GetComponent<PlayerCameraEffectController>().OnPlayerResurrection();
Locator.GetPlayerAudioController().OnPlayerResurrection();
Locator.GetDeathManager()._isDying = false;
var visorEffect = QSBWorldSync.GetUnityObject<VisorEffectController>();
visorEffect._cracked = false;
visorEffect._crackStartTime = 0f;
visorEffect._crackEffectRenderer.enabled = false;
visorEffect._crackEffectRenderer.material.SetFloat(visorEffect._propID_Cutoff, 1f);
}
private SpawnPoint GetSpawnPoint()
{
var spawnList = _playerSpawner._spawnList;
if (spawnList == null)
{
DebugLog.ToConsole($"Warning - _spawnList was null for player spawner!", MessageType.Warning);
return null;
}
return spawnList.FirstOrDefault(spawnPoint =>
spawnPoint.GetSpawnLocation() == SpawnLocation.TimberHearth
&& spawnPoint.IsShipSpawn() == false);
}
void OnGUI()
{
if (PlayerTransformSync.LocalInstance == null || ShipManager.Instance.ShipCockpitUI == null)
{
return;
}
if (QSBPlayerManager.LocalPlayer.IsDead)
{
GUI.contentColor = Color.white;
var width = 200;
var height = 100;
// it is good day to be not dead
var secondText = ShipManager.Instance.IsShipWrecked
? string.Format(QSBLocalization.Current.WaitingForAllToDie, QSBPlayerManager.PlayerList.Count(x => !x.IsDead))
: QSBLocalization.Current.WaitingForRespawn;
GUI.Label(
new Rect((Screen.width / 2) - (width / 2), (Screen.height / 2) - (height / 2) + (height * 2), width, height),
$"{QSBLocalization.Current.YouAreDead}\n{secondText}",
_deadTextStyle);
}
}
}