diff --git a/NewHorizons/Builder/Body/SingularityBuilder.cs b/NewHorizons/Builder/Body/SingularityBuilder.cs index a961c9d5..eb8863c8 100644 --- a/NewHorizons/Builder/Body/SingularityBuilder.cs +++ b/NewHorizons/Builder/Body/SingularityBuilder.cs @@ -1,18 +1,17 @@ -using NewHorizons.External.Configs; -using NewHorizons.Utility; -using NewHorizons.External.Modules.VariableSize; -using UnityEngine; - -using System.Collections.Generic; -using NewHorizons.Components.SizeControllers; -using Color = UnityEngine.Color; -using NewHorizons.Components.Volumes; using NewHorizons.Builder.Props; -using NewHorizons.Utility.OWML; -using NewHorizons.Utility.OuterWilds; -using NewHorizons.External.SerializableData; using NewHorizons.Builder.Volumes; +using NewHorizons.Components.SizeControllers; +using NewHorizons.Components.Volumes; +using NewHorizons.External.Configs; +using NewHorizons.External.Modules.VariableSize; +using NewHorizons.External.SerializableData; +using NewHorizons.Utility; +using NewHorizons.Utility.OuterWilds; +using NewHorizons.Utility.OWML; using System; +using System.Collections.Generic; +using UnityEngine; +using Color = UnityEngine.Color; namespace NewHorizons.Builder.Body { @@ -88,7 +87,7 @@ namespace NewHorizons.Builder.Body Vector3 localRotation = singularity?.rotation == null ? Vector3.zero : singularity.rotation; GameObject newSingularity = MakeSingularity(go, sector, localPosition, localRotation, polarity, horizonRadius, distortRadius, - hasHazardVolume, singularity.targetStarSystem, singularity.curve, singularity.hasWarpEffects, singularity.renderQueueOverride, singularity.rename, singularity.parentPath, singularity.isRelativeToParent); + hasHazardVolume, singularity.targetStarSystem, singularity.spawnPointID, singularity.curve, singularity.hasWarpEffects, singularity.renderQueueOverride, singularity.rename, singularity.parentPath, singularity.isRelativeToParent); var uniqueID = string.IsNullOrEmpty(singularity.uniqueID) ? config.name : singularity.uniqueID; @@ -161,7 +160,7 @@ namespace NewHorizons.Builder.Body } public static GameObject MakeSingularity(GameObject planetGO, Sector sector, Vector3 position, Vector3 rotation, bool polarity, float horizon, float distort, - bool hasDestructionVolume, string targetStarSystem = null, TimeValuePair[] curve = null, bool warpEffects = true, int renderQueue = 2985, string rename = null, string parentPath = null, bool isRelativeToParent = false) + bool hasDestructionVolume, string targetStarSystem = null, string targetSpawnID = null, TimeValuePair[] curve = null, bool warpEffects = true, int renderQueue = 2985, string rename = null, string parentPath = null, bool isRelativeToParent = false) { // polarity true = black, false = white @@ -233,6 +232,7 @@ namespace NewHorizons.Builder.Body { var wormholeVolume = destructionVolumeGO.AddComponent(); wormholeVolume.TargetSolarSystem = targetStarSystem; + wormholeVolume.TargetSpawnID = targetSpawnID; } } else diff --git a/NewHorizons/Builder/General/SpawnPointBuilder.cs b/NewHorizons/Builder/General/SpawnPointBuilder.cs index 460350f1..0e1eee40 100644 --- a/NewHorizons/Builder/General/SpawnPointBuilder.cs +++ b/NewHorizons/Builder/General/SpawnPointBuilder.cs @@ -14,52 +14,92 @@ namespace NewHorizons.Builder.General public static class SpawnPointBuilder { private static bool suitUpQueued = false; + + // Ship + public static SpawnModule.ShipSpawnPoint ShipSpawnInfo { get; private set; } public static SpawnPoint ShipSpawn { get; private set; } public static Vector3 ShipSpawnOffset { get; private set; } + // Player + public static SpawnModule.PlayerSpawnPoint PlayerSpawnInfo { get; private set; } + public static SpawnPoint PlayerSpawn { get; private set; } + + public static void OverridePlayerSpawn(SpawnPoint newSpawn) + { + PlayerSpawn = newSpawn; + PlayerSpawnInfo = null; + } + public static SpawnPoint Make(GameObject planetGO, SpawnModule module, OWRigidbody owRigidBody) { SpawnPoint playerSpawn = null; // Make the spawn point even if it won't be used this loop - if (module.playerSpawn != null) + if (module.playerSpawnPoints != null) { - GameObject spawnGO = GeneralPropBuilder.MakeNew("PlayerSpawnPoint", planetGO, null, module.playerSpawn); - spawnGO.layer = Layer.PlayerSafetyCollider; + foreach (var point in module.playerSpawnPoints) + { + GameObject spawnGO = GeneralPropBuilder.MakeNew("PlayerSpawnPoint", planetGO, null, point); + spawnGO.layer = Layer.PlayerSafetyCollider; - playerSpawn = spawnGO.AddComponent(); - playerSpawn._attachedBody = owRigidBody; - playerSpawn._spawnLocation = SpawnLocation.None; - // #601 we need to actually set the right trigger volumes here - playerSpawn._triggerVolumes = new OWTriggerVolume[0]; + playerSpawn = spawnGO.AddComponent(); + playerSpawn._attachedBody = owRigidBody; + playerSpawn._spawnLocation = SpawnLocation.None; + // #601 we need to actually set the right trigger volumes here + playerSpawn._triggerVolumes = new OWTriggerVolume[0]; - // This was a stupid hack to stop players getting stuck in the ground and now we have to keep it forever - spawnGO.transform.position += spawnGO.transform.TransformDirection(module.playerSpawn.offset ?? Vector3.up * 4f); + // This was a stupid hack to stop players getting stuck in the ground and now we have to keep it forever + spawnGO.transform.position += spawnGO.transform.TransformDirection(point.offset ?? Vector3.up * 4f); + + if (PlayerSpawn == null || point.GetPriority() > PlayerSpawnInfo.GetPriority()) + { + PlayerSpawn = playerSpawn; + PlayerSpawnInfo = point; + } + } } - if (module.shipSpawn != null) + if (module.shipSpawnPoints != null) { - var spawnGO = GeneralPropBuilder.MakeNew("ShipSpawnPoint", planetGO, null, module.shipSpawn); - spawnGO.SetActive(false); - spawnGO.layer = Layer.PlayerSafetyCollider; + foreach (var point in module.shipSpawnPoints) + { + var spawnGO = GeneralPropBuilder.MakeNew("ShipSpawnPoint", planetGO, null, point); + spawnGO.SetActive(false); + spawnGO.layer = Layer.PlayerSafetyCollider; - ShipSpawn = spawnGO.AddComponent(); - ShipSpawn._isShipSpawn = true; - ShipSpawn._attachedBody = owRigidBody; - ShipSpawn._spawnLocation = SpawnLocation.None; + var shipSpawn = spawnGO.AddComponent(); + shipSpawn._isShipSpawn = true; + shipSpawn._attachedBody = owRigidBody; + shipSpawn._spawnLocation = SpawnLocation.None; - // #601 we need to actually set the right trigger volumes here - ShipSpawn._triggerVolumes = new OWTriggerVolume[0]; + // #601 we need to actually set the right trigger volumes here + shipSpawn._triggerVolumes = new OWTriggerVolume[0]; - ShipSpawnOffset = module.shipSpawn.offset ?? (module.shipSpawn.alignRadial.GetValueOrDefault() ? Vector3.up * 4 : Vector3.zero); + var shipSpawnOffset = point.offset ?? (point.alignRadial.GetValueOrDefault() ? Vector3.up * 4 : Vector3.zero); - spawnGO.SetActive(true); + if (ShipSpawn == null || point.GetPriority() > ShipSpawnInfo.GetPriority()) + { + ShipSpawn = shipSpawn; + ShipSpawnOffset = shipSpawnOffset; + ShipSpawnInfo = point; + } + + spawnGO.SetActive(true); + } } - if ((Main.Instance.IsWarpingFromVessel || (!Main.Instance.IsWarpingFromShip && (module.playerSpawn?.startWithSuit ?? false))) && !suitUpQueued) + // Make sure to queue this up if any spawn point building is happening + if (!suitUpQueued) { suitUpQueued = true; - Delay.RunWhen(() => Main.IsSystemReady, SuitUp); + Delay.RunWhen(() => Main.IsSystemReady, () => + { + suitUpQueued = false; + if (Main.Instance.IsWarpingFromVessel || (!Main.Instance.IsWarpingFromShip && (PlayerSpawnInfo?.startWithSuit ?? false))) + { + SuitUp(); + } + }); } NHLogger.Log($"Made spawnpoint on [{planetGO.name}]"); @@ -69,7 +109,6 @@ namespace NewHorizons.Builder.General public static void SuitUp() { - suitUpQueued = false; if (!Locator.GetPlayerController()._isWearingSuit) { Locator.GetPlayerSuit().SuitUp(false, true, true); diff --git a/NewHorizons/Builder/Volumes/ChangeStarSystemVolumeBuilder.cs b/NewHorizons/Builder/Volumes/ChangeStarSystemVolumeBuilder.cs index c3b8c5db..5557da98 100644 --- a/NewHorizons/Builder/Volumes/ChangeStarSystemVolumeBuilder.cs +++ b/NewHorizons/Builder/Volumes/ChangeStarSystemVolumeBuilder.cs @@ -11,6 +11,7 @@ namespace NewHorizons.Builder.Volumes var volume = VolumeBuilder.Make(planetGO, sector, info); volume.TargetSolarSystem = info.targetStarSystem; + volume.TargetSpawnID = info.spawnPointID; return volume; } diff --git a/NewHorizons/Components/ShipLog/ShipLogStarChartMode.cs b/NewHorizons/Components/ShipLog/ShipLogStarChartMode.cs index 86d6cfa8..cc5636eb 100644 --- a/NewHorizons/Components/ShipLog/ShipLogStarChartMode.cs +++ b/NewHorizons/Components/ShipLog/ShipLogStarChartMode.cs @@ -211,7 +211,7 @@ namespace NewHorizons.Components.ShipLog { if (_starSystemCards.Count == 0) { - NHLogger.LogWarning("Showing star chart mode when there are no avaialble systems"); + NHLogger.LogWarning("Showing star chart mode when there are no available systems"); return; } diff --git a/NewHorizons/Components/Volumes/BlackHoleWarpVolume.cs b/NewHorizons/Components/Volumes/BlackHoleWarpVolume.cs index bd99fee5..941bff2b 100644 --- a/NewHorizons/Components/Volumes/BlackHoleWarpVolume.cs +++ b/NewHorizons/Components/Volumes/BlackHoleWarpVolume.cs @@ -1,8 +1,11 @@ +using NewHorizons.Handlers; + namespace NewHorizons.Components.Volumes { public class BlackHoleWarpVolume : BlackHoleDestructionVolume { public string TargetSolarSystem { get; set; } + public string TargetSpawnID { get; set; } public override void Awake() { @@ -19,6 +22,7 @@ namespace NewHorizons.Components.Volumes { Locator.GetPlayerAudioController().PlayOneShotInternal(AudioType.BH_BlackHoleEmission); Main.Instance.ChangeCurrentStarSystem(TargetSolarSystem, PlayerState.AtFlightConsole()); + PlayerSpawnHandler.TargetSpawnID = TargetSpawnID; } } } diff --git a/NewHorizons/Components/Volumes/WarpVolume.cs b/NewHorizons/Components/Volumes/WarpVolume.cs index fa07d6e4..25892833 100644 --- a/NewHorizons/Components/Volumes/WarpVolume.cs +++ b/NewHorizons/Components/Volumes/WarpVolume.cs @@ -1,3 +1,4 @@ +using NewHorizons.Handlers; using UnityEngine; namespace NewHorizons.Components.Volumes @@ -5,6 +6,7 @@ namespace NewHorizons.Components.Volumes internal class WarpVolume : BaseVolume { public string TargetSolarSystem; + public string TargetSpawnID; public override void OnTriggerVolumeEntry(GameObject hitObj) { @@ -13,6 +15,7 @@ namespace NewHorizons.Components.Volumes if (Main.Instance.CurrentStarSystem != TargetSolarSystem) // Otherwise it really breaks idk why { Main.Instance.ChangeCurrentStarSystem(TargetSolarSystem, PlayerState.AtFlightConsole()); + PlayerSpawnHandler.TargetSpawnID = TargetSpawnID; } } } diff --git a/NewHorizons/External/Configs/PlanetConfig.cs b/NewHorizons/External/Configs/PlanetConfig.cs index f7331dc6..723b36b0 100644 --- a/NewHorizons/External/Configs/PlanetConfig.cs +++ b/NewHorizons/External/Configs/PlanetConfig.cs @@ -1,3 +1,4 @@ +using Epic.OnlineServices; using NewHorizons.External.Modules; using NewHorizons.External.Modules.Props; using NewHorizons.External.Modules.Props.Audio; @@ -540,6 +541,22 @@ namespace NewHorizons.External.Configs }; } + // Spawn points are now a list + if (Spawn != null && Spawn.playerSpawn != null && Spawn.playerSpawnPoints == null) + { + Spawn.playerSpawnPoints = new SpawnModule.PlayerSpawnPoint[] { Spawn.playerSpawn }; + } + if (Spawn != null && Spawn.shipSpawn != null && Spawn.shipSpawnPoints == null) + { + Spawn.shipSpawnPoints = new SpawnModule.ShipSpawnPoint[] { Spawn.shipSpawn }; + } + + // Because these guys put TWO spawn points + if (starSystem == "2walker2.OogaBooga" && name == "The Campground") + { + Spawn.playerSpawnPoints[0].isDefault = true; + } + // Remote dialogue trigger reorganized to use GeneralPointPropInfo if (Props?.dialogue != null) { diff --git a/NewHorizons/External/Modules/SpawnModule.cs b/NewHorizons/External/Modules/SpawnModule.cs index f8af3fa1..3c62766a 100644 --- a/NewHorizons/External/Modules/SpawnModule.cs +++ b/NewHorizons/External/Modules/SpawnModule.cs @@ -1,4 +1,6 @@ +using NewHorizons.Builder.General; using NewHorizons.External.SerializableData; +using NewHorizons.Handlers; using Newtonsoft.Json; using System; @@ -9,12 +11,20 @@ namespace NewHorizons.External.Modules { /// /// If you want the player to spawn on the new body, set a value for this. + /// Different spawns can be unlocked with persistent conditions and facts /// - public PlayerSpawnPoint playerSpawn; + public PlayerSpawnPoint[] playerSpawnPoints; /// /// Required for the system to be accessible by warp drive. + /// Different spawns can be unlocked with persistent conditions and facts /// + public ShipSpawnPoint[] shipSpawnPoints; + + [Obsolete("Use playerSpawnPoints instead")] + public PlayerSpawnPoint playerSpawn; + + [Obsolete("Use shipSpawnPoints instead")] public ShipSpawnPoint shipSpawn; [Obsolete("playerSpawnPoint is deprecated. Use playerSpawn.position instead")] public MVector3 playerSpawnPoint; @@ -30,6 +40,56 @@ namespace NewHorizons.External.Modules /// Offsets the player/ship by this local vector when spawning. Used to prevent spawning in the floor. Optional: defaults to (0, 4, 0). /// public MVector3 offset; + + /// + /// Whether this planet's spawn point is the one the player/ship will initially spawn at, if multiple spawn points exist. + /// Do not use at the same time as makeDefaultIfFactRevealed or makeDefaultIfPersistentCondition + /// Spawns unlocked with this have lowest priority + /// + public bool isDefault; + + /// + /// If the given ship log fact is revealed, this spawn point will be used + /// Do not use at the same time as isDefault or makeDefaultIfPersistentCondition + /// Spawns unlocked with this have highest priority + /// + public string makeDefaultIfFactRevealed; + + /// + /// If the given persistent condition is true, this spawn point will be used + /// Do not use at the same time as isDefault or makeDefaultIfFactRevealed + /// Spawns unlocked with this have second highest priority + /// + public string makeDefaultIfPersistentCondition; + + /// + /// ID used to have a black hole or warp volume bring the player to this spawn specifically + /// + public string id; + + public int GetPriority() + { + if (!string.IsNullOrEmpty(id) && !string.IsNullOrEmpty(PlayerSpawnHandler.TargetSpawnID) && id == PlayerSpawnHandler.TargetSpawnID) + { + return 3; + } + if (!string.IsNullOrEmpty(makeDefaultIfFactRevealed) && ShipLogHandler.KnowsFact(makeDefaultIfFactRevealed)) + { + return 2; + } + if (!string.IsNullOrEmpty(makeDefaultIfPersistentCondition) && PlayerData.GetPersistentCondition(makeDefaultIfPersistentCondition)) + { + return 1; + } + if (isDefault) + { + return 0; + } + else + { + return -1; + } + } } [JsonObject] @@ -39,12 +99,6 @@ namespace NewHorizons.External.Modules /// If you spawn on a planet with no oxygen, you probably want to set this to true ;;) /// public bool startWithSuit; - /// - /// Whether this planet's spawn point is the one the player will initially spawn at, if multiple spawn points exist. - /// - public bool isDefault; - - } [JsonObject] diff --git a/NewHorizons/External/Modules/VariableSize/SingularityModule.cs b/NewHorizons/External/Modules/VariableSize/SingularityModule.cs index d85a399c..042cbe02 100644 --- a/NewHorizons/External/Modules/VariableSize/SingularityModule.cs +++ b/NewHorizons/External/Modules/VariableSize/SingularityModule.cs @@ -54,6 +54,12 @@ namespace NewHorizons.External.Modules.VariableSize /// public string targetStarSystem; + /// + /// If this is a black hole loading a new star system, set the ID of the spawn point you want to use + /// Otherwise, will use the default spawn + /// + public string spawnPointID; + /// /// Type of singularity (white hole or black hole) /// diff --git a/NewHorizons/External/Modules/Volumes/VolumeInfos/ChangeStarSystemVolumeInfo.cs b/NewHorizons/External/Modules/Volumes/VolumeInfos/ChangeStarSystemVolumeInfo.cs index 969a5945..24b492db 100644 --- a/NewHorizons/External/Modules/Volumes/VolumeInfos/ChangeStarSystemVolumeInfo.cs +++ b/NewHorizons/External/Modules/Volumes/VolumeInfos/ChangeStarSystemVolumeInfo.cs @@ -10,5 +10,11 @@ namespace NewHorizons.External.Modules.Volumes.VolumeInfos /// The star system that entering this volume will send you to. /// [DefaultValue("SolarSystem")] public string targetStarSystem; + + /// + /// ID assigned to a spawn point in the other system that the player will be sent to + /// Uses the default spawn if not set + /// + public string spawnPointID; } } diff --git a/NewHorizons/External/NewHorizonBody.cs b/NewHorizons/External/NewHorizonBody.cs index a38af522..14da7b49 100644 --- a/NewHorizons/External/NewHorizonBody.cs +++ b/NewHorizons/External/NewHorizonBody.cs @@ -106,12 +106,6 @@ namespace NewHorizons.External } } } - - // Because these guys put TWO spawn points - if (Mod.ModHelper.Manifest.UniqueName == "2walker2.Evacuation" && Config.name == "The Campground") - { - Config.Spawn.playerSpawn.isDefault = true; - } } #endregion diff --git a/NewHorizons/External/NewHorizonsSystem.cs b/NewHorizons/External/NewHorizonsSystem.cs index 07f1ba08..f4928f17 100644 --- a/NewHorizons/External/NewHorizonsSystem.cs +++ b/NewHorizons/External/NewHorizonsSystem.cs @@ -1,5 +1,4 @@ using NewHorizons.External.Configs; -using NewHorizons.External.Modules; using OWML.Common; using System.Linq; @@ -9,10 +8,9 @@ namespace NewHorizons.External { public string UniqueID; public string RelativePath; - public SpawnModule Spawn = null; - public SpawnPoint SpawnPoint = null; public StarSystemConfig Config; public IModBehaviour Mod; + public bool HasShipSpawn; public NewHorizonsSystem(string uniqueID, StarSystemConfig config, string relativePath, IModBehaviour mod) { diff --git a/NewHorizons/Handlers/PlanetCreationHandler.cs b/NewHorizons/Handlers/PlanetCreationHandler.cs index 380e4673..42fd5533 100644 --- a/NewHorizons/Handlers/PlanetCreationHandler.cs +++ b/NewHorizons/Handlers/PlanetCreationHandler.cs @@ -502,13 +502,6 @@ namespace NewHorizons.Handlers { NHLogger.LogVerbose($"Making spawn point on {body.Config.name}"); var spawnPoint = SpawnPointBuilder.Make(go, body.Config.Spawn, owRigidBody); - var isVanillaSystem = body.Config.starSystem == "SolarSystem" || body.Config.starSystem == "EyeOfTheUniverse"; - var needsSpawnPoint = Main.SystemDict[body.Config.starSystem].SpawnPoint == null || isVanillaSystem; - var isDefaultSpawn = body.Config.Spawn.playerSpawn?.isDefault ?? true; // Backwards compat - if (needsSpawnPoint || isDefaultSpawn) - { - Main.SystemDict[body.Config.starSystem].SpawnPoint = spawnPoint; - } } if (body.Config.Orbit.showOrbitLine && !body.Config.Orbit.isStatic) diff --git a/NewHorizons/Handlers/PlayerSpawnHandler.cs b/NewHorizons/Handlers/PlayerSpawnHandler.cs index dd4f4f27..8ee1a007 100644 --- a/NewHorizons/Handlers/PlayerSpawnHandler.cs +++ b/NewHorizons/Handlers/PlayerSpawnHandler.cs @@ -9,6 +9,11 @@ namespace NewHorizons.Handlers { public static class PlayerSpawnHandler { + /// + /// Set during the previous loop, force the player to spawn here + /// + public static string TargetSpawnID { get; set; } + public static void SetUpPlayerSpawn() { if (UsingCustomSpawn()) @@ -146,6 +151,9 @@ namespace NewHorizons.Handlers FixPlayerVelocity(); InvulnerabilityHandler.MakeInvulnerable(false); + + // Done spawning + TargetSpawnID = null; } private static void FixPlayerVelocity(bool recenter = true) @@ -200,8 +208,8 @@ namespace NewHorizons.Handlers return vector; } - public static bool UsingCustomSpawn() => Main.SystemDict[Main.Instance.CurrentStarSystem].SpawnPoint != null; + public static bool UsingCustomSpawn() => SpawnPointBuilder.PlayerSpawn != null; public static PlayerSpawner GetPlayerSpawner() => GameObject.FindObjectOfType(); - public static SpawnPoint GetDefaultSpawn() => Main.SystemDict[Main.Instance.CurrentStarSystem].SpawnPoint ?? GetPlayerSpawner().GetSpawnPoint(SpawnLocation.TimberHearth); + public static SpawnPoint GetDefaultSpawn() => SpawnPointBuilder.PlayerSpawn ?? GetPlayerSpawner().GetSpawnPoint(SpawnLocation.TimberHearth); } } diff --git a/NewHorizons/Handlers/ShipLogHandler.cs b/NewHorizons/Handlers/ShipLogHandler.cs index 84cbb203..7f9a6e14 100644 --- a/NewHorizons/Handlers/ShipLogHandler.cs +++ b/NewHorizons/Handlers/ShipLogHandler.cs @@ -114,10 +114,8 @@ namespace NewHorizons.Handlers public static bool KnowsFact(string fact) { - // Works normally in the main system, else check save data directly - var shipLogManager = Locator.GetShipLogManager(); - if (Main.Instance.CurrentStarSystem == "SolarSystem" && shipLogManager != null) return shipLogManager.IsFactRevealed(fact); - else return PlayerData.GetShipLogFactSave(fact)?.revealOrder > -1; + // Use save data directly so stuff works between systems + return PlayerData.GetShipLogFactSave(fact)?.revealOrder > -1; } } } diff --git a/NewHorizons/Handlers/StarChartHandler.cs b/NewHorizons/Handlers/StarChartHandler.cs index d063abcc..27844c5b 100644 --- a/NewHorizons/Handlers/StarChartHandler.cs +++ b/NewHorizons/Handlers/StarChartHandler.cs @@ -130,7 +130,7 @@ namespace NewHorizons.Handlers var canWarpTo = false; if (system.Equals("SolarSystem")) canWarpTo = true; else if (system.Equals("EyeOfTheUniverse")) canWarpTo = false; - else if (config.Spawn?.shipSpawn != null) canWarpTo = true; + else if (config.HasShipSpawn) canWarpTo = true; var canEnterViaWarpDrive = Main.SystemDict[system].Config.canEnterViaWarpDrive || system == "SolarSystem"; @@ -156,15 +156,20 @@ namespace NewHorizons.Handlers _canExitViaWarpDrive = true; if (!Main.HasWarpDrive) { - Main.Instance.EnableWarpDrive(); + var flagActuallyAddedACard = false; // Add all cards that now work foreach (var starSystem in Main.SystemDict.Keys) { if (CanWarpToSystem(starSystem)) { ShipLogStarChartMode.AddSystemCard(starSystem); + flagActuallyAddedACard = true; } } + if (flagActuallyAddedACard) + { + Main.Instance.EnableWarpDrive(); + } } else { diff --git a/NewHorizons/Handlers/VesselWarpHandler.cs b/NewHorizons/Handlers/VesselWarpHandler.cs index 26195e5c..bac8fdf7 100644 --- a/NewHorizons/Handlers/VesselWarpHandler.cs +++ b/NewHorizons/Handlers/VesselWarpHandler.cs @@ -1,3 +1,4 @@ +using NewHorizons.Builder.General; using NewHorizons.Builder.Props; using NewHorizons.Components; using NewHorizons.Components.EyeOfTheUniverse; @@ -240,7 +241,7 @@ namespace NewHorizons.Handlers VesselSpawnPoint spawnPoint = vesselObject.GetComponentInChildren(true); if (ShouldSpawnAtVessel()) { - system.SpawnPoint = spawnPoint; + SpawnPointBuilder.OverridePlayerSpawn(spawnPoint); } vesselObject.SetActive(true); diff --git a/NewHorizons/INewHorizons.cs b/NewHorizons/INewHorizons.cs index 71337802..12002b1e 100644 --- a/NewHorizons/INewHorizons.cs +++ b/NewHorizons/INewHorizons.cs @@ -214,5 +214,12 @@ namespace NewHorizons /// /// void AddSubtitle(IModBehaviour mod, string filePath); + + /// + /// Whatever system the player is warping to next, they will spawn at the spawn point with this ID + /// Gets reset after warping. Is also overriden by entering a system-changing black hole or warp volume by their `spawnPointID` + /// + /// + void SetNextSpawnID(string id); } } diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs index f8f18718..7b540e69 100644 --- a/NewHorizons/Main.cs +++ b/NewHorizons/Main.cs @@ -789,9 +789,6 @@ namespace NewHorizons if (body != null) { - // Wanna track the spawn point of each system - if (body.Config.Spawn != null) SystemDict[body.Config.starSystem].Spawn = body.Config.Spawn; - // Add the new planet to the planet dictionary if (!BodyDict.ContainsKey(body.Config.starSystem)) BodyDict[body.Config.starSystem] = new List(); BodyDict[body.Config.starSystem].Add(body); @@ -924,6 +921,12 @@ namespace NewHorizons config.Validate(); config.Migrate(); + // Check if this system can be warped to + if (config.Spawn?.shipSpawnPoints?.Any() ?? false) + { + SystemDict[config.starSystem].HasShipSpawn = true; + } + return new NewHorizonsBody(config, mod, relativePath); } @@ -1071,7 +1074,7 @@ namespace NewHorizons { IsWarpingFromVessel = true; } - else if (BodyDict.TryGetValue(DefaultSystemOverride, out var bodies) && bodies.Any(x => x.Config?.Spawn?.shipSpawn != null)) + else if (BodyDict.TryGetValue(DefaultSystemOverride, out var bodies) && bodies.Any(x => x.Config?.Spawn?.shipSpawnPoints?.Any() ?? false)) { IsWarpingFromShip = true; } diff --git a/NewHorizons/NewHorizonsApi.cs b/NewHorizons/NewHorizonsApi.cs index c9193f61..348991c0 100644 --- a/NewHorizons/NewHorizonsApi.cs +++ b/NewHorizons/NewHorizonsApi.cs @@ -342,5 +342,7 @@ namespace NewHorizons public string GetTranslationForOtherText(string text) => TranslationHandler.GetTranslation(text, TranslationHandler.TextType.OTHER); public void AddSubtitle(IModBehaviour mod, string filePath) => SubtitlesHandler.RegisterAdditionalSubtitle(mod, filePath); + + public void SetNextSpawnID(string id) => PlayerSpawnHandler.TargetSpawnID = id; } } diff --git a/NewHorizons/Schemas/body_schema.json b/NewHorizons/Schemas/body_schema.json index 04979b31..cafe5fb9 100644 --- a/NewHorizons/Schemas/body_schema.json +++ b/NewHorizons/Schemas/body_schema.json @@ -2722,6 +2722,10 @@ "type": "string", "description": "If you want a black hole to load a new star system scene, put its name here." }, + "spawnPointID": { + "type": "string", + "description": "If this is a black hole loading a new star system, set the ID of the spawn point you want to use\nOtherwise, will use the default spawn" + }, "type": { "description": "Type of singularity (white hole or black hole)", "$ref": "#/definitions/SingularityType" @@ -3619,13 +3623,19 @@ "type": "object", "additionalProperties": false, "properties": { - "playerSpawn": { - "description": "If you want the player to spawn on the new body, set a value for this.", - "$ref": "#/definitions/PlayerSpawnPoint" + "playerSpawnPoints": { + "type": "array", + "description": "If you want the player to spawn on the new body, set a value for this.\nDifferent spawns can be unlocked with persistent conditions and facts", + "items": { + "$ref": "#/definitions/PlayerSpawnPoint" + } }, - "shipSpawn": { - "description": "Required for the system to be accessible by warp drive.", - "$ref": "#/definitions/ShipSpawnPoint" + "shipSpawnPoints": { + "type": "array", + "description": "Required for the system to be accessible by warp drive.\nDifferent spawns can be unlocked with persistent conditions and facts", + "items": { + "$ref": "#/definitions/ShipSpawnPoint" + } } } }, @@ -3637,6 +3647,22 @@ "description": "Offsets the player/ship by this local vector when spawning. Used to prevent spawning in the floor. Optional: defaults to (0, 4, 0).", "$ref": "#/definitions/MVector3" }, + "isDefault": { + "type": "boolean", + "description": "Whether this planet's spawn point is the one the player/ship will initially spawn at, if multiple spawn points exist.\nDo not use at the same time as makeDefaultIfFactRevealed or makeDefaultIfPersistentCondition\nSpawns unlocked with this have lowest priority" + }, + "makeDefaultIfFactRevealed": { + "type": "string", + "description": "If the given ship log fact is revealed, this spawn point will be used\nDo not use at the same time as isDefault or makeDefaultIfPersistentCondition\nSpawns unlocked with this have highest priority" + }, + "makeDefaultIfPersistentCondition": { + "type": "string", + "description": "If the given persistent condition is true, this spawn point will be used\nDo not use at the same time as isDefault or makeDefaultIfFactRevealed\nSpawns unlocked with this have second highest priority" + }, + "id": { + "type": "string", + "description": "ID used to have a black hole or warp volume bring the player to this spawn specifically" + }, "rotation": { "description": "Rotation of the object", "$ref": "#/definitions/MVector3" @@ -3667,10 +3693,6 @@ "startWithSuit": { "type": "boolean", "description": "If you spawn on a planet with no oxygen, you probably want to set this to true ;;)" - }, - "isDefault": { - "type": "boolean", - "description": "Whether this planet's spawn point is the one the player will initially spawn at, if multiple spawn points exist." } } }, @@ -3682,6 +3704,22 @@ "description": "Offsets the player/ship by this local vector when spawning. Used to prevent spawning in the floor. Optional: defaults to (0, 4, 0).", "$ref": "#/definitions/MVector3" }, + "isDefault": { + "type": "boolean", + "description": "Whether this planet's spawn point is the one the player/ship will initially spawn at, if multiple spawn points exist.\nDo not use at the same time as makeDefaultIfFactRevealed or makeDefaultIfPersistentCondition\nSpawns unlocked with this have lowest priority" + }, + "makeDefaultIfFactRevealed": { + "type": "string", + "description": "If the given ship log fact is revealed, this spawn point will be used\nDo not use at the same time as isDefault or makeDefaultIfPersistentCondition\nSpawns unlocked with this have highest priority" + }, + "makeDefaultIfPersistentCondition": { + "type": "string", + "description": "If the given persistent condition is true, this spawn point will be used\nDo not use at the same time as isDefault or makeDefaultIfFactRevealed\nSpawns unlocked with this have second highest priority" + }, + "id": { + "type": "string", + "description": "ID used to have a black hole or warp volume bring the player to this spawn specifically" + }, "rotation": { "description": "Rotation of the object", "$ref": "#/definitions/MVector3" @@ -5168,6 +5206,10 @@ "type": "string", "description": "The star system that entering this volume will send you to.", "default": "SolarSystem" + }, + "spawnPointID": { + "type": "string", + "description": "ID assigned to a spawn point in the other system that the player will be sent to\nUses the default spawn if not set" } } },