Multiple spawn points (#947)

## Minor features

- The spawn module now has `playerSpawnPoints` and `shipSpawnPoints`
allowing you to define multiple possible spawns on one planet.
- Spawn points now have `makeDefaultIfFactRevealed` and
`makeDefaultIfPersistentCondition` allowing you to change which spawn
the player uses. Priority goes fact -> persistent condition -> default
- Black holes and change star system volumes now have `spawnPointID`. If
this is set, entering one of these volumes will send you to the spawn
with a matching `id` (fixes #917)

## Bug fixes:
- Fix empty warp drive ship log page appearing
- Use save data directly when checking for facts for ship log warp drive
This commit is contained in:
xen-42 2024-10-04 21:26:41 -04:00 committed by GitHub
commit fad1cd82c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 267 additions and 86 deletions

View File

@ -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.Builder.Props;
using NewHorizons.Utility.OWML;
using NewHorizons.Utility.OuterWilds;
using NewHorizons.External.SerializableData;
using NewHorizons.Builder.Volumes; 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;
using System.Collections.Generic;
using UnityEngine;
using Color = UnityEngine.Color;
namespace NewHorizons.Builder.Body namespace NewHorizons.Builder.Body
{ {
@ -88,7 +87,7 @@ namespace NewHorizons.Builder.Body
Vector3 localRotation = singularity?.rotation == null ? Vector3.zero : singularity.rotation; Vector3 localRotation = singularity?.rotation == null ? Vector3.zero : singularity.rotation;
GameObject newSingularity = MakeSingularity(go, sector, localPosition, localRotation, polarity, horizonRadius, distortRadius, 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; 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, 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 // polarity true = black, false = white
@ -233,6 +232,7 @@ namespace NewHorizons.Builder.Body
{ {
var wormholeVolume = destructionVolumeGO.AddComponent<BlackHoleWarpVolume>(); var wormholeVolume = destructionVolumeGO.AddComponent<BlackHoleWarpVolume>();
wormholeVolume.TargetSolarSystem = targetStarSystem; wormholeVolume.TargetSolarSystem = targetStarSystem;
wormholeVolume.TargetSpawnID = targetSpawnID;
} }
} }
else else

View File

@ -14,17 +14,32 @@ namespace NewHorizons.Builder.General
public static class SpawnPointBuilder public static class SpawnPointBuilder
{ {
private static bool suitUpQueued = false; private static bool suitUpQueued = false;
// Ship
public static SpawnModule.ShipSpawnPoint ShipSpawnInfo { get; private set; }
public static SpawnPoint ShipSpawn { get; private set; } public static SpawnPoint ShipSpawn { get; private set; }
public static Vector3 ShipSpawnOffset { 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) public static SpawnPoint Make(GameObject planetGO, SpawnModule module, OWRigidbody owRigidBody)
{ {
SpawnPoint playerSpawn = null; SpawnPoint playerSpawn = null;
// Make the spawn point even if it won't be used this loop // 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); foreach (var point in module.playerSpawnPoints)
{
GameObject spawnGO = GeneralPropBuilder.MakeNew("PlayerSpawnPoint", planetGO, null, point);
spawnGO.layer = Layer.PlayerSafetyCollider; spawnGO.layer = Layer.PlayerSafetyCollider;
playerSpawn = spawnGO.AddComponent<SpawnPoint>(); playerSpawn = spawnGO.AddComponent<SpawnPoint>();
@ -34,32 +49,57 @@ namespace NewHorizons.Builder.General
playerSpawn._triggerVolumes = new OWTriggerVolume[0]; 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 // 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); 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); foreach (var point in module.shipSpawnPoints)
{
var spawnGO = GeneralPropBuilder.MakeNew("ShipSpawnPoint", planetGO, null, point);
spawnGO.SetActive(false); spawnGO.SetActive(false);
spawnGO.layer = Layer.PlayerSafetyCollider; spawnGO.layer = Layer.PlayerSafetyCollider;
ShipSpawn = spawnGO.AddComponent<SpawnPoint>(); var shipSpawn = spawnGO.AddComponent<SpawnPoint>();
ShipSpawn._isShipSpawn = true; shipSpawn._isShipSpawn = true;
ShipSpawn._attachedBody = owRigidBody; shipSpawn._attachedBody = owRigidBody;
ShipSpawn._spawnLocation = SpawnLocation.None; shipSpawn._spawnLocation = SpawnLocation.None;
// #601 we need to actually set the right trigger volumes here // #601 we need to actually set the right trigger volumes here
ShipSpawn._triggerVolumes = new OWTriggerVolume[0]; 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);
if (ShipSpawn == null || point.GetPriority() > ShipSpawnInfo.GetPriority())
{
ShipSpawn = shipSpawn;
ShipSpawnOffset = shipSpawnOffset;
ShipSpawnInfo = point;
}
spawnGO.SetActive(true); 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; 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}]"); NHLogger.Log($"Made spawnpoint on [{planetGO.name}]");
@ -69,7 +109,6 @@ namespace NewHorizons.Builder.General
public static void SuitUp() public static void SuitUp()
{ {
suitUpQueued = false;
if (!Locator.GetPlayerController()._isWearingSuit) if (!Locator.GetPlayerController()._isWearingSuit)
{ {
Locator.GetPlayerSuit().SuitUp(false, true, true); Locator.GetPlayerSuit().SuitUp(false, true, true);

View File

@ -11,6 +11,7 @@ namespace NewHorizons.Builder.Volumes
var volume = VolumeBuilder.Make<WarpVolume>(planetGO, sector, info); var volume = VolumeBuilder.Make<WarpVolume>(planetGO, sector, info);
volume.TargetSolarSystem = info.targetStarSystem; volume.TargetSolarSystem = info.targetStarSystem;
volume.TargetSpawnID = info.spawnPointID;
return volume; return volume;
} }

View File

@ -211,7 +211,7 @@ namespace NewHorizons.Components.ShipLog
{ {
if (_starSystemCards.Count == 0) 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; return;
} }

View File

@ -1,8 +1,11 @@
using NewHorizons.Handlers;
namespace NewHorizons.Components.Volumes namespace NewHorizons.Components.Volumes
{ {
public class BlackHoleWarpVolume : BlackHoleDestructionVolume public class BlackHoleWarpVolume : BlackHoleDestructionVolume
{ {
public string TargetSolarSystem { get; set; } public string TargetSolarSystem { get; set; }
public string TargetSpawnID { get; set; }
public override void Awake() public override void Awake()
{ {
@ -19,6 +22,7 @@ namespace NewHorizons.Components.Volumes
{ {
Locator.GetPlayerAudioController().PlayOneShotInternal(AudioType.BH_BlackHoleEmission); Locator.GetPlayerAudioController().PlayOneShotInternal(AudioType.BH_BlackHoleEmission);
Main.Instance.ChangeCurrentStarSystem(TargetSolarSystem, PlayerState.AtFlightConsole()); Main.Instance.ChangeCurrentStarSystem(TargetSolarSystem, PlayerState.AtFlightConsole());
PlayerSpawnHandler.TargetSpawnID = TargetSpawnID;
} }
} }
} }

View File

@ -1,3 +1,4 @@
using NewHorizons.Handlers;
using UnityEngine; using UnityEngine;
namespace NewHorizons.Components.Volumes namespace NewHorizons.Components.Volumes
@ -5,6 +6,7 @@ namespace NewHorizons.Components.Volumes
internal class WarpVolume : BaseVolume internal class WarpVolume : BaseVolume
{ {
public string TargetSolarSystem; public string TargetSolarSystem;
public string TargetSpawnID;
public override void OnTriggerVolumeEntry(GameObject hitObj) 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 if (Main.Instance.CurrentStarSystem != TargetSolarSystem) // Otherwise it really breaks idk why
{ {
Main.Instance.ChangeCurrentStarSystem(TargetSolarSystem, PlayerState.AtFlightConsole()); Main.Instance.ChangeCurrentStarSystem(TargetSolarSystem, PlayerState.AtFlightConsole());
PlayerSpawnHandler.TargetSpawnID = TargetSpawnID;
} }
} }
} }

View File

@ -1,3 +1,4 @@
using Epic.OnlineServices;
using NewHorizons.External.Modules; using NewHorizons.External.Modules;
using NewHorizons.External.Modules.Props; using NewHorizons.External.Modules.Props;
using NewHorizons.External.Modules.Props.Audio; 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 // Remote dialogue trigger reorganized to use GeneralPointPropInfo
if (Props?.dialogue != null) if (Props?.dialogue != null)
{ {

View File

@ -1,4 +1,6 @@
using NewHorizons.Builder.General;
using NewHorizons.External.SerializableData; using NewHorizons.External.SerializableData;
using NewHorizons.Handlers;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
@ -9,12 +11,20 @@ namespace NewHorizons.External.Modules
{ {
/// <summary> /// <summary>
/// If you want the player to spawn on the new body, set a value for this. /// 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
/// </summary> /// </summary>
public PlayerSpawnPoint playerSpawn; public PlayerSpawnPoint[] playerSpawnPoints;
/// <summary> /// <summary>
/// Required for the system to be accessible by warp drive. /// Required for the system to be accessible by warp drive.
/// Different spawns can be unlocked with persistent conditions and facts
/// </summary> /// </summary>
public ShipSpawnPoint[] shipSpawnPoints;
[Obsolete("Use playerSpawnPoints instead")]
public PlayerSpawnPoint playerSpawn;
[Obsolete("Use shipSpawnPoints instead")]
public ShipSpawnPoint shipSpawn; public ShipSpawnPoint shipSpawn;
[Obsolete("playerSpawnPoint is deprecated. Use playerSpawn.position instead")] public MVector3 playerSpawnPoint; [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). /// Offsets the player/ship by this local vector when spawning. Used to prevent spawning in the floor. Optional: defaults to (0, 4, 0).
/// </summary> /// </summary>
public MVector3 offset; public MVector3 offset;
/// <summary>
/// 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
/// </summary>
public bool isDefault;
/// <summary>
/// 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
/// </summary>
public string makeDefaultIfFactRevealed;
/// <summary>
/// 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
/// </summary>
public string makeDefaultIfPersistentCondition;
/// <summary>
/// ID used to have a black hole or warp volume bring the player to this spawn specifically
/// </summary>
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] [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 ;;) /// If you spawn on a planet with no oxygen, you probably want to set this to true ;;)
/// </summary> /// </summary>
public bool startWithSuit; public bool startWithSuit;
/// <summary>
/// Whether this planet's spawn point is the one the player will initially spawn at, if multiple spawn points exist.
/// </summary>
public bool isDefault;
} }
[JsonObject] [JsonObject]

View File

@ -54,6 +54,12 @@ namespace NewHorizons.External.Modules.VariableSize
/// </summary> /// </summary>
public string targetStarSystem; public string targetStarSystem;
/// <summary>
/// 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
/// </summary>
public string spawnPointID;
/// <summary> /// <summary>
/// Type of singularity (white hole or black hole) /// Type of singularity (white hole or black hole)
/// </summary> /// </summary>

View File

@ -10,5 +10,11 @@ namespace NewHorizons.External.Modules.Volumes.VolumeInfos
/// The star system that entering this volume will send you to. /// The star system that entering this volume will send you to.
/// </summary> /// </summary>
[DefaultValue("SolarSystem")] public string targetStarSystem; [DefaultValue("SolarSystem")] public string targetStarSystem;
/// <summary>
/// ID assigned to a spawn point in the other system that the player will be sent to
/// Uses the default spawn if not set
/// </summary>
public string spawnPointID;
} }
} }

View File

@ -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 #endregion

View File

@ -1,5 +1,4 @@
using NewHorizons.External.Configs; using NewHorizons.External.Configs;
using NewHorizons.External.Modules;
using OWML.Common; using OWML.Common;
using System.Linq; using System.Linq;
@ -9,10 +8,9 @@ namespace NewHorizons.External
{ {
public string UniqueID; public string UniqueID;
public string RelativePath; public string RelativePath;
public SpawnModule Spawn = null;
public SpawnPoint SpawnPoint = null;
public StarSystemConfig Config; public StarSystemConfig Config;
public IModBehaviour Mod; public IModBehaviour Mod;
public bool HasShipSpawn;
public NewHorizonsSystem(string uniqueID, StarSystemConfig config, string relativePath, IModBehaviour mod) public NewHorizonsSystem(string uniqueID, StarSystemConfig config, string relativePath, IModBehaviour mod)
{ {

View File

@ -502,13 +502,6 @@ namespace NewHorizons.Handlers
{ {
NHLogger.LogVerbose($"Making spawn point on {body.Config.name}"); NHLogger.LogVerbose($"Making spawn point on {body.Config.name}");
var spawnPoint = SpawnPointBuilder.Make(go, body.Config.Spawn, owRigidBody); 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) if (body.Config.Orbit.showOrbitLine && !body.Config.Orbit.isStatic)

View File

@ -9,6 +9,11 @@ namespace NewHorizons.Handlers
{ {
public static class PlayerSpawnHandler public static class PlayerSpawnHandler
{ {
/// <summary>
/// Set during the previous loop, force the player to spawn here
/// </summary>
public static string TargetSpawnID { get; set; }
public static void SetUpPlayerSpawn() public static void SetUpPlayerSpawn()
{ {
if (UsingCustomSpawn()) if (UsingCustomSpawn())
@ -146,6 +151,9 @@ namespace NewHorizons.Handlers
FixPlayerVelocity(); FixPlayerVelocity();
InvulnerabilityHandler.MakeInvulnerable(false); InvulnerabilityHandler.MakeInvulnerable(false);
// Done spawning
TargetSpawnID = null;
} }
private static void FixPlayerVelocity(bool recenter = true) private static void FixPlayerVelocity(bool recenter = true)
@ -200,8 +208,8 @@ namespace NewHorizons.Handlers
return vector; 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<PlayerSpawner>(); public static PlayerSpawner GetPlayerSpawner() => GameObject.FindObjectOfType<PlayerSpawner>();
public static SpawnPoint GetDefaultSpawn() => Main.SystemDict[Main.Instance.CurrentStarSystem].SpawnPoint ?? GetPlayerSpawner().GetSpawnPoint(SpawnLocation.TimberHearth); public static SpawnPoint GetDefaultSpawn() => SpawnPointBuilder.PlayerSpawn ?? GetPlayerSpawner().GetSpawnPoint(SpawnLocation.TimberHearth);
} }
} }

View File

@ -114,10 +114,8 @@ namespace NewHorizons.Handlers
public static bool KnowsFact(string fact) public static bool KnowsFact(string fact)
{ {
// Works normally in the main system, else check save data directly // Use save data directly so stuff works between systems
var shipLogManager = Locator.GetShipLogManager(); return PlayerData.GetShipLogFactSave(fact)?.revealOrder > -1;
if (Main.Instance.CurrentStarSystem == "SolarSystem" && shipLogManager != null) return shipLogManager.IsFactRevealed(fact);
else return PlayerData.GetShipLogFactSave(fact)?.revealOrder > -1;
} }
} }
} }

View File

@ -130,7 +130,7 @@ namespace NewHorizons.Handlers
var canWarpTo = false; var canWarpTo = false;
if (system.Equals("SolarSystem")) canWarpTo = true; if (system.Equals("SolarSystem")) canWarpTo = true;
else if (system.Equals("EyeOfTheUniverse")) canWarpTo = false; 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"; var canEnterViaWarpDrive = Main.SystemDict[system].Config.canEnterViaWarpDrive || system == "SolarSystem";
@ -156,15 +156,20 @@ namespace NewHorizons.Handlers
_canExitViaWarpDrive = true; _canExitViaWarpDrive = true;
if (!Main.HasWarpDrive) if (!Main.HasWarpDrive)
{ {
Main.Instance.EnableWarpDrive(); var flagActuallyAddedACard = false;
// Add all cards that now work // Add all cards that now work
foreach (var starSystem in Main.SystemDict.Keys) foreach (var starSystem in Main.SystemDict.Keys)
{ {
if (CanWarpToSystem(starSystem)) if (CanWarpToSystem(starSystem))
{ {
ShipLogStarChartMode.AddSystemCard(starSystem); ShipLogStarChartMode.AddSystemCard(starSystem);
flagActuallyAddedACard = true;
} }
} }
if (flagActuallyAddedACard)
{
Main.Instance.EnableWarpDrive();
}
} }
else else
{ {

View File

@ -1,3 +1,4 @@
using NewHorizons.Builder.General;
using NewHorizons.Builder.Props; using NewHorizons.Builder.Props;
using NewHorizons.Components; using NewHorizons.Components;
using NewHorizons.Components.EyeOfTheUniverse; using NewHorizons.Components.EyeOfTheUniverse;
@ -240,7 +241,7 @@ namespace NewHorizons.Handlers
VesselSpawnPoint spawnPoint = vesselObject.GetComponentInChildren<VesselSpawnPoint>(true); VesselSpawnPoint spawnPoint = vesselObject.GetComponentInChildren<VesselSpawnPoint>(true);
if (ShouldSpawnAtVessel()) if (ShouldSpawnAtVessel())
{ {
system.SpawnPoint = spawnPoint; SpawnPointBuilder.OverridePlayerSpawn(spawnPoint);
} }
vesselObject.SetActive(true); vesselObject.SetActive(true);

View File

@ -214,5 +214,12 @@ namespace NewHorizons
/// <param name="mod"></param> /// <param name="mod"></param>
/// <param name="filePath"></param> /// <param name="filePath"></param>
void AddSubtitle(IModBehaviour mod, string filePath); void AddSubtitle(IModBehaviour mod, string filePath);
/// <summary>
/// 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`
/// </summary>
/// <param name="id"></param>
void SetNextSpawnID(string id);
} }
} }

View File

@ -789,9 +789,6 @@ namespace NewHorizons
if (body != null) 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 // Add the new planet to the planet dictionary
if (!BodyDict.ContainsKey(body.Config.starSystem)) BodyDict[body.Config.starSystem] = new List<NewHorizonsBody>(); if (!BodyDict.ContainsKey(body.Config.starSystem)) BodyDict[body.Config.starSystem] = new List<NewHorizonsBody>();
BodyDict[body.Config.starSystem].Add(body); BodyDict[body.Config.starSystem].Add(body);
@ -924,6 +921,12 @@ namespace NewHorizons
config.Validate(); config.Validate();
config.Migrate(); 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); return new NewHorizonsBody(config, mod, relativePath);
} }
@ -1071,7 +1074,7 @@ namespace NewHorizons
{ {
IsWarpingFromVessel = true; 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; IsWarpingFromShip = true;
} }

View File

@ -342,5 +342,7 @@ namespace NewHorizons
public string GetTranslationForOtherText(string text) => TranslationHandler.GetTranslation(text, TranslationHandler.TextType.OTHER); public string GetTranslationForOtherText(string text) => TranslationHandler.GetTranslation(text, TranslationHandler.TextType.OTHER);
public void AddSubtitle(IModBehaviour mod, string filePath) => SubtitlesHandler.RegisterAdditionalSubtitle(mod, filePath); public void AddSubtitle(IModBehaviour mod, string filePath) => SubtitlesHandler.RegisterAdditionalSubtitle(mod, filePath);
public void SetNextSpawnID(string id) => PlayerSpawnHandler.TargetSpawnID = id;
} }
} }

View File

@ -2722,6 +2722,10 @@
"type": "string", "type": "string",
"description": "If you want a black hole to load a new star system scene, put its name here." "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": { "type": {
"description": "Type of singularity (white hole or black hole)", "description": "Type of singularity (white hole or black hole)",
"$ref": "#/definitions/SingularityType" "$ref": "#/definitions/SingularityType"
@ -3619,15 +3623,21 @@
"type": "object", "type": "object",
"additionalProperties": false, "additionalProperties": false,
"properties": { "properties": {
"playerSpawn": { "playerSpawnPoints": {
"description": "If you want the player to spawn on the new body, set a value for this.", "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" "$ref": "#/definitions/PlayerSpawnPoint"
}
}, },
"shipSpawn": { "shipSpawnPoints": {
"description": "Required for the system to be accessible by warp drive.", "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" "$ref": "#/definitions/ShipSpawnPoint"
} }
} }
}
}, },
"PlayerSpawnPoint": { "PlayerSpawnPoint": {
"type": "object", "type": "object",
@ -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).", "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" "$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": { "rotation": {
"description": "Rotation of the object", "description": "Rotation of the object",
"$ref": "#/definitions/MVector3" "$ref": "#/definitions/MVector3"
@ -3667,10 +3693,6 @@
"startWithSuit": { "startWithSuit": {
"type": "boolean", "type": "boolean",
"description": "If you spawn on a planet with no oxygen, you probably want to set this to true ;;)" "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).", "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" "$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": { "rotation": {
"description": "Rotation of the object", "description": "Rotation of the object",
"$ref": "#/definitions/MVector3" "$ref": "#/definitions/MVector3"
@ -5168,6 +5206,10 @@
"type": "string", "type": "string",
"description": "The star system that entering this volume will send you to.", "description": "The star system that entering this volume will send you to.",
"default": "SolarSystem" "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"
} }
} }
}, },