using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using NewHorizons.Utility;
using Newtonsoft.Json;
using static NewHorizons.External.Modules.ShipLogModule;
namespace NewHorizons.External.Configs
{
///
/// Configuration for a specific star system
///
[JsonObject]
public class StarSystemConfig
{
///
/// Whether this system can be warped to via the warp drive. If you set factRequiredForWarp, this will be true.
///
[DefaultValue(true)] public bool canEnterViaWarpDrive = true;
///
/// Do you want a clean slate for this star system? Or will it be a modified version of the original.
///
[DefaultValue(true)] public bool destroyStockPlanets = true;
///
/// Should the time loop be enabled in this system?
///
[DefaultValue(true)] public bool enableTimeLoop = true;
///
/// The FactID that must be revealed before it can be warped to. Don't set `canEnterViaWarpDrive` to `false` if
/// you're using this, because it will be overwritten.
///
public string factRequiredForWarp;
///
/// The duration of the time loop in minutes. This is the time the sun explodes. End Times plays 85 seconds before this time, and your memories get sent back about 40 seconds after this time.
///
[DefaultValue(22f)] public float loopDuration = 22f;
///
/// Should the player not be able to view the map in this system?
///
public bool mapRestricted;
///
/// Customize the skybox for this system
///
public SkyboxModule Skybox;
///
/// Set to `true` if you want to spawn here after dying, not Timber Hearth. You can still warp back to the main star
/// system.
///
public bool startHere;
[Obsolete("travelAudioClip is deprecated, please use travelAudio instead")]
public string travelAudioClip;
[Obsolete("travelAudioFilePath is deprecated, please use travelAudio instead")]
public string travelAudioFilePath;
///
/// The audio that will play when travelling in space. Can be a path to a .wav/.ogg/.mp3 file, or taken from the AudioClip list.
///
public string travelAudio;
///
/// Configure warping to this system with the vessel
///
public VesselModule Vessel;
[Obsolete("coords is deprecated, please use Vessel.coords instead")]
public NomaiCoordinates coords;
[Obsolete("vesselPosition is deprecated, please use Vessel.vesselPosition instead")]
public MVector3 vesselPosition;
[Obsolete("vesselRotation is deprecated, please use Vessel.vesselRotation instead")]
public MVector3 vesselRotation;
[Obsolete("warpExitPosition is deprecated, please use Vessel.warpExitPosition instead")]
public MVector3 warpExitPosition;
[Obsolete("warpExitRotation is deprecated, please use Vessel.warpExitRotation instead")]
public MVector3 warpExitRotation;
///
/// Manually layout ship log entries in detective mode
///
public EntryPositionInfo[] entryPositions;
///
/// A list of fact IDs to reveal when the game starts.
///
public string[] initialReveal;
///
/// List colors of curiosity entries
///
public CuriosityColorInfo[] curiosities;
public class NomaiCoordinates
{
[MinLength(2)]
[MaxLength(6)]
public int[] x;
[MinLength(2)]
[MaxLength(6)]
public int[] y;
[MinLength(2)]
[MaxLength(6)]
public int[] z;
}
[JsonObject]
public class SkyboxModule
{
///
/// Whether to destroy the star field around the player
///
public bool destroyStarField;
///
/// Whether to use a cube for the skybox instead of a smooth sphere
///
public bool useCube;
///
/// Relative filepath to the texture to use for the skybox's positive X direction
///
public string rightPath;
///
/// Relative filepath to the texture to use for the skybox's negative X direction
///
public string leftPath;
///
/// Relative filepath to the texture to use for the skybox's positive Y direction
///
public string topPath;
///
/// Relative filepath to the texture to use for the skybox's negative Y direction
///
public string bottomPath;
///
/// Relative filepath to the texture to use for the skybox's positive Z direction
///
public string frontPath;
///
/// Relative filepath to the texture to use for the skybox's negative Z direction
///
public string backPath;
}
[JsonObject]
public class VesselModule
{
///
/// Coordinates that the vessel can use to warp to your solar system.
///
public NomaiCoordinates coords;
///
/// The position in the solar system the vessel will warp to.
///
public MVector3 vesselPosition;
///
/// Euler angles by which the vessel will be oriented.
///
public MVector3 vesselRotation;
///
/// The relative position to the vessel that you will be teleported to when you exit the vessel through the black hole.
///
public MVector3 warpExitPosition;
///
/// Euler angles by which the warp exit will be oriented.
///
public MVector3 warpExitRotation;
///
/// A ship log fact which will make a prompt appear showing the coordinates when you're in the Vessel.
///
public string promptFact;
}
///
/// Makes sure they are all numbers are unique and between 0 and 5.
///
private static int[] FixAxis(int[] axis) => axis.Distinct().Where(i => (i >= 0 && i <= 5)).ToArray();
public void FixCoordinates()
{
if (Vessel?.coords != null)
{
Vessel.coords.x = FixAxis(Vessel.coords.x);
Vessel.coords.y = FixAxis(Vessel.coords.y);
Vessel.coords.z = FixAxis(Vessel.coords.z);
}
}
public void Merge(StarSystemConfig otherConfig)
{
// Imagine if this used reflection
// True by default so if one is false go false
canEnterViaWarpDrive = canEnterViaWarpDrive && otherConfig.canEnterViaWarpDrive;
destroyStockPlanets = destroyStockPlanets && otherConfig.destroyStockPlanets;
enableTimeLoop = enableTimeLoop && otherConfig.enableTimeLoop;
loopDuration = loopDuration == 22f ? otherConfig.loopDuration : loopDuration;
// If current one is null take the other
factRequiredForWarp = string.IsNullOrEmpty(factRequiredForWarp) ? otherConfig.factRequiredForWarp : factRequiredForWarp;
Skybox = Skybox == null ? otherConfig.Skybox : Skybox;
travelAudio = string.IsNullOrEmpty(travelAudio) ? otherConfig.travelAudio : travelAudio;
// False by default so if one is true go true
mapRestricted = mapRestricted || otherConfig.mapRestricted;
mapRestricted = mapRestricted || otherConfig.mapRestricted;
startHere = startHere || otherConfig.startHere;
Vessel = Vessel == null ? otherConfig.Vessel : Vessel;
entryPositions = Concatenate(entryPositions, otherConfig.entryPositions);
curiosities = Concatenate(curiosities, otherConfig.curiosities);
initialReveal = Concatenate(initialReveal, otherConfig.initialReveal);
}
private T[] Concatenate(T[] array1, T[] array2)
{
return (array1 ?? new T[0]).Concat(array2 ?? new T[0]).ToArray();
}
public void Migrate()
{
// Backwards compatability
// Should be the only place that obsolete things are referenced
#pragma warning disable 612, 618
if (!string.IsNullOrEmpty(travelAudioClip)) travelAudio = travelAudioClip;
if (!string.IsNullOrEmpty(travelAudioFilePath)) travelAudio = travelAudioFilePath;
if (coords != null || vesselPosition != null || vesselRotation != null || warpExitPosition != null || warpExitRotation != null)
{
if (Vessel == null)
{
Vessel = new VesselModule();
}
Vessel.coords = Vessel.coords ?? coords;
Vessel.vesselPosition = Vessel.vesselPosition ?? vesselPosition;
Vessel.vesselRotation = Vessel.vesselRotation ?? vesselRotation;
Vessel.warpExitPosition = Vessel.warpExitPosition ?? warpExitPosition;
Vessel.warpExitRotation = Vessel.warpExitRotation ?? warpExitRotation;
}
}
}
}