using NewHorizons.Utility; using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Runtime.Serialization; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using System; using NewHorizons.External.Modules.VariableSize; namespace NewHorizons.External.Modules { [JsonObject] public class PropModule { /// /// Place props in predefined positions on the planet /// public DetailInfo[] details; /// /// Add dialogue triggers to this planet /// public DialogueInfo[] dialogue; /// /// Add ship log entry locations on this planet /// public EntryLocationInfo[] entryLocation; /// /// Add Geysers to this planet /// public GeyserInfo[] geysers; /// /// Add translatable text to this planet. (LEGACY - for use with pre-autospirals configs) /// [Obsolete("nomaiText is deprecated as of the release of auto spirals, instead please use translatorText with new configs.")] public NomaiTextInfo[] nomaiText; /// /// Add translatable text to this planet /// public NomaiTextInfo[] translatorText; /// /// Details which will be shown from 50km away. Meant to be lower resolution. /// public DetailInfo[] proxyDetails; /// /// Add rafts to this planet /// public RaftInfo[] rafts; /// /// Scatter props around this planet's surface /// public ScatterInfo[] scatter; /// /// Add slideshows (from the DLC) to the planet /// public ProjectionInfo[] slideShows; /// /// A list of quantum groups that props can be added to. An example of a group would be a list of possible locations for a QuantumSocketedObject. /// public QuantumGroupInfo[] quantumGroups; /// /// Add tornadoes to this planet /// public TornadoInfo[] tornados; /// /// Add volcanoes to this planet /// public VolcanoInfo[] volcanoes; /// /// Add black/white-holes to this planet /// public SingularityModule[] singularities; /// /// Add signalscope signals to this planet /// public SignalModule.SignalInfo[] signals; /// /// Add projection pools/platforms, whiteboards, and stones to this planet /// public RemoteInfo[] remotes; [Obsolete("reveal is deprecated. Use Volumes->revealVolumes instead.")] public VolumesModule.RevealVolumeInfo[] reveal; [Obsolete("audioVolumes is deprecated. Use Volumes->audioVolumes instead.")] public VolumesModule.AudioVolumeInfo[] audioVolumes; [JsonObject] public abstract class GeneralPointPropInfo { /// /// Position of the object /// public MVector3 position; /// /// The relative path from the planet to the parent of this object. Optional (will default to the root sector). /// public string parentPath; /// /// Whether the positional and rotational coordinates are relative to parent instead of the root planet object. /// public bool isRelativeToParent; /// /// An optional rename of this object /// public string rename; } [JsonObject] public abstract class GeneralPropInfo : GeneralPointPropInfo { /// /// Rotation of the object /// public MVector3 rotation; } [JsonObject] public abstract class GeneralSolarSystemPropInfo : GeneralPropInfo { /// /// The name of the planet that will be used with `parentPath`. Must be set if `parentPath` is set. /// public string parentBody; } [JsonObject] public class ScatterInfo { /// /// Relative filepath to an asset-bundle /// public string assetBundle; /// /// Number of props to scatter /// public int count; /// /// Offset this prop once it is placed /// public MVector3 offset; /// /// Either the path in the scene hierarchy of the item to copy or the path to the object in the supplied asset bundle /// public string path; /// /// Rotate this prop once it is placed /// public MVector3 rotation; /// /// Scale this prop once it is placed /// [DefaultValue(1f)] public float scale = 1f; /// /// Scale each axis of the prop. Overrides `scale`. /// public MVector3 stretch; /// /// The number used as entropy for scattering the props /// public int seed; /// /// The lowest height that these object will be placed at (only relevant if there's a heightmap) /// public float? minHeight; /// /// The highest height that these objects will be placed at (only relevant if there's a heightmap) /// public float? maxHeight; /// /// Should we try to prevent overlap between the scattered details? True by default. If it's affecting load times turn it off. /// [DefaultValue(true)] public bool preventOverlap = true; /// /// Should this detail stay loaded even if you're outside the sector (good for very large props) /// public bool keepLoaded; } [JsonObject] public class DetailInfo : GeneralPropInfo { /// /// Do we override rotation and try to automatically align this object to stand upright on the body's surface? /// public bool alignToNormal; /// /// Relative filepath to an asset-bundle to load the prefab defined in `path` from /// public string assetBundle; /// /// Either the path in the scene hierarchy of the item to copy or the path to the object in the supplied asset bundle /// public string path; /// /// A list of children to remove from this detail /// public string[] removeChildren; /// /// Do we reset all the components on this object? Useful for certain props that have dialogue components attached to /// them. /// public bool removeComponents; /// /// Scale the prop /// [DefaultValue(1f)] public float scale = 1f; /// /// Scale each axis of the prop. Overrides `scale`. /// public MVector3 stretch; /// /// If this value is not null, this prop will be quantum. Assign this field to the id of the quantum group it should be a part of. The group it is assigned to determines what kind of quantum object it is /// public string quantumGroupID; /// /// Should this detail stay loaded even if you're outside the sector (good for very large props) /// public bool keepLoaded; /// /// Should this object dynamically move around? /// This tries to make all mesh colliders convex, as well as adding a sphere collider in case the detail has no others. /// public bool hasPhysics; /// /// The mass of the physics object. /// Most pushable props use the default value, which matches the player mass. /// [DefaultValue(0.001f)] public float physicsMass = 0.001f; /// /// The radius that the added sphere collider will use for physics collision. /// If there's already good colliders on the detail, you can make this 0. /// [DefaultValue(1f)] public float physicsRadius = 1f; } [JsonObject] public class RaftInfo : GeneralPointPropInfo { /// /// Acceleration of the raft. Default acceleration is 5. /// [DefaultValue(5f)] public float acceleration = 5f; } [JsonObject] public class GeyserInfo : GeneralPointPropInfo { /// /// Vertical offset of the geyser. From 0, the bubbles start at a height of 10, the shaft at 67, and the spout at 97.5. /// [DefaultValue(-97.5f)] public float offset = -97.5f; /// /// Force of the geyser on objects /// [DefaultValue(55f)] public float force = 55f; /// /// Time in seconds eruptions last for /// [DefaultValue(10f)] public float activeDuration = 10f; /// /// Time in seconds between eruptions /// [DefaultValue(19f)] public float inactiveDuration = 19f; /// /// Color of the geyser. Alpha sets the particle density. /// public MColor tint; /// /// Disable the individual particle systems of the geyser /// public bool disableBubbles, disableShaft, disableSpout; /// /// Loudness of the geyser /// [DefaultValue(0.7f)] public float volume = 0.7f; } [JsonObject] public class TornadoInfo : GeneralPointPropInfo { [JsonConverter(typeof(StringEnumConverter))] public enum TornadoType { [EnumMember(Value = @"upwards")] Upwards = 0, [EnumMember(Value = @"downwards")] Downwards = 1, [EnumMember(Value = @"hurricane")] Hurricane = 2 } [Obsolete("Downwards is deprecated. Use Type instead.")] public bool downwards; /// /// Alternative to setting the position. Will choose a random place at this elevation. /// public float elevation; /// /// The height of this tornado. /// [DefaultValue(30f)] public float height = 30f; /// /// The colour of the tornado. /// public MColor tint; /// /// What type of cyclone should this be? Upwards and downwards are both tornados and will push in that direction. /// [DefaultValue("upwards")] public TornadoType type = TornadoType.Upwards; /// /// Angular distance from the starting position that it will wander, in terms of the angle around the x-axis. /// [DefaultValue(45f)] public float wanderDegreesX = 45f; /// /// Angular distance from the starting position that it will wander, in terms of the angle around the z-axis. /// [DefaultValue(45f)] public float wanderDegreesZ = 45f; /// /// The rate at which the tornado will wander around the planet. Set to 0 for it to be stationary. Should be around /// 0.1. /// public float wanderRate; /// /// The maximum distance at which you'll hear the sounds of the cyclone. If not set it will scale relative to the size of the cyclone. /// public float audioDistance; /// /// Fluid type for sounds/effects when colliding with this tornado. /// [DefaultValue("cloud")] public FluidType fluidType = FluidType.Cloud; } [JsonObject] public class VolcanoInfo : GeneralPointPropInfo { /// /// The colour of the meteor's lava. /// public MColor lavaTint; /// /// Maximum time between meteor launches. /// [DefaultValue(20f)] public float maxInterval = 20f; /// /// Maximum random speed at which meteors are launched. /// [DefaultValue(150f)] public float maxLaunchSpeed = 150f; /// /// Minimum time between meteor launches. /// [DefaultValue(5f)] public float minInterval = 5f; /// /// Minimum random speed at which meteors are launched. /// [DefaultValue(50f)] public float minLaunchSpeed = 50f; /// /// Scale of the meteors. /// public float scale = 1; /// /// The colour of the meteor's stone. /// public MColor stoneTint; } [JsonObject] public class DialogueInfo : GeneralPointPropInfo { /// /// Prevents the dialogue from being created after a specific persistent condition is set. Useful for remote dialogue /// triggers that you want to have happen only once. /// public string blockAfterPersistentCondition; /// /// If a pathToAnimController is supplied, if you are within this distance the character will look at you. If it is set /// to 0, they will only look at you when spoken to. /// public float lookAtRadius; /// /// If this dialogue is meant for a character, this is the relative path from the planet to that character's /// CharacterAnimController, TravelerController, TravelerEyeController (eye of the universe), FacePlayerWhenTalking, or SolanumAnimController. /// /// If none of those components are present it will add a FacePlayerWhenTalking component. /// public string pathToAnimController; /// /// Radius of the spherical collision volume where you get the "talk to" prompt when looking at. If you use a /// remoteTrigger, you can set this to 0 to make the dialogue only trigger remotely. /// public float radius = 1f; /// /// Distance from radius the prompt appears /// [DefaultValue(2f)] public float range = 2f; /// /// Allows you to trigger dialogue from a distance when you walk into an area. /// public RemoteTriggerInfo remoteTrigger; [Obsolete("remoteTriggerPosition is deprecated. Use remoteTrigger.position instead")] public MVector3 remoteTriggerPosition; [Obsolete("remoteTriggerRadius is deprecated. Use remoteTrigger.radius instead")] public float remoteTriggerRadius; [Obsolete("remoteTriggerPrereqCondition is deprecated. Use remoteTrigger.prereqCondition instead")] public string remoteTriggerPrereqCondition; /// /// Relative path to the xml file defining the dialogue. /// public string xmlFile; /// /// What type of flashlight toggle to do when dialogue is interacted with /// [DefaultValue("none")] public FlashlightToggle flashlightToggle = FlashlightToggle.None; [JsonConverter(typeof(StringEnumConverter))] public enum FlashlightToggle { [EnumMember(Value = @"none")] None = -1, [EnumMember(Value = @"turnOff")] TurnOff = 0, [EnumMember(Value = @"turnOffThenOn")] TurnOffThenOn = 1, } [JsonObject] public class RemoteTriggerInfo : GeneralPointPropInfo { /// /// The radius of the remote trigger volume. /// public float radius; /// /// This condition must be met for the remote trigger volume to trigger. /// public string prereqCondition; } } [JsonObject] public class EntryLocationInfo : GeneralPointPropInfo { /// /// Whether this location is cloaked /// public bool cloaked; /// /// ID of the entry this location relates to /// public string id; } [JsonObject] public class NomaiTextInfo : GeneralPointPropInfo { [JsonConverter(typeof(StringEnumConverter))] public enum NomaiTextType { [EnumMember(Value = @"wall")] Wall = 0, [EnumMember(Value = @"scroll")] Scroll = 1, [EnumMember(Value = @"computer")] Computer = 2, [EnumMember(Value = @"cairn")] Cairn = 3, [EnumMember(Value = @"recorder")] Recorder = 4, [EnumMember(Value = @"preCrashRecorder")] PreCrashRecorder = 5, [EnumMember(Value = @"preCrashComputer")] PreCrashComputer = 6, [EnumMember(Value = @"trailmarker")] Trailmarker = 7, [EnumMember(Value = @"cairnVariant")] CairnVariant = 8, } [JsonConverter(typeof(StringEnumConverter))] public enum NomaiTextLocation { [EnumMember(Value = @"unspecified")] UNSPECIFIED = 0, [EnumMember(Value = @"a")] A = 1, [EnumMember(Value = @"b")] B = 2 } /// /// Additional information about each arc in the text /// public NomaiTextArcInfo[] arcInfo; /// /// The normal vector for this object. Used for writing on walls and positioning computers. /// public MVector3 normal; /// /// The euler angle rotation of this object. Not required if setting the normal. Computers and cairns will orient /// themselves to the surface of the planet automatically. /// public MVector3 rotation; /// /// The random seed used to pick what the text arcs will look like. /// public int seed; // For randomizing arcs /// /// The type of object this is. /// [DefaultValue("wall")] public NomaiTextType type = NomaiTextType.Wall; /// /// The location of this object. /// [DefaultValue("unspecified")] public NomaiTextLocation location = NomaiTextLocation.UNSPECIFIED; /// /// The relative path to the xml file for this object. /// public string xmlFile; } [JsonObject] public class NomaiTextArcInfo { [JsonConverter(typeof(StringEnumConverter))] public enum NomaiTextArcType { [EnumMember(Value = @"adult")] Adult = 0, [EnumMember(Value = @"child")] Child = 1, [EnumMember(Value = @"stranger")] Stranger = 2 } /// /// Whether to skip modifying this spiral's placement, and instead keep the automatically determined placement. /// public bool keepAutoPlacement; /// /// Whether to flip the spiral from left-curling to right-curling or vice versa. /// public bool mirror; /// /// The local position of this object on the wall. /// public MVector2 position; /// /// The type of text to display. /// [DefaultValue("adult")] public NomaiTextArcType type = NomaiTextArcType.Adult; /// /// Which variation of the chosen type to place. If not specified, a random variation will be selected based on the seed provided in the parent module. /// [DefaultValue(-1)] public int variation = -1; /// /// The z euler angle for this arc. /// [Range(0f, 360f)] public float zRotation; } [JsonObject] public class ProjectionInfo : GeneralPropInfo { [JsonConverter(typeof(StringEnumConverter))] public enum SlideShowType { [EnumMember(Value = @"slideReel")] SlideReel = 0, [EnumMember(Value = @"autoProjector")] AutoProjector = 1, [EnumMember(Value = @"visionTorchTarget")] VisionTorchTarget = 2, [EnumMember(Value = @"standingVisionTorch")] StandingVisionTorch = 3, } /// /// The ship log facts revealed after finishing this slide reel. /// public string[] reveals; /// /// The ship log facts that make the reel play when they are displayed in the computer (by selecting entries or arrows). /// You should probably include facts from `reveals` here. /// If you only specify a rumor fact, then it would only play in its ship log entry if this has revealed only /// rumor facts because an entry with revealed explore facts doesn't display rumor facts. /// public string[] playWithShipLogFacts; /// /// The list of slides for this object. /// public SlideInfo[] slides; /// /// The type of object this is. /// [DefaultValue("slideReel")] public SlideShowType type = SlideShowType.SlideReel; } [JsonObject] public class SlideInfo { /// /// Ambient light colour when viewing this slide. /// public MColor ambientLightColor; // SlideAmbientLightModule /// /// Ambient light intensity when viewing this slide. /// public float ambientLightIntensity; /// /// Ambient light range when viewing this slide. /// public float ambientLightRange; // SlideBackdropAudioModule /// /// The name of the AudioClip that will continuously play while watching these slides /// public string backdropAudio; /// /// The time to fade into the backdrop audio /// public float backdropFadeTime; // SlideBeatAudioModule /// /// The name of the AudioClip for a one-shot sound when opening the slide. /// public string beatAudio; /// /// The time delay until the one-shot audio /// public float beatDelay; // SlideBlackFrameModule /// /// Before viewing this slide, there will be a black frame for this many seconds. /// public float blackFrameDuration; /// /// The path to the image file for this slide. /// public string imagePath; // SlidePlayTimeModule /// /// Play-time duration for auto-projector slides. /// public float playTimeDuration; // SlideShipLogEntryModule /// /// Ship log fact revealed when viewing this slide /// public string reveal; /// /// Spotlight intensity modifier when viewing this slide. /// public float spotIntensityMod; } [JsonConverter(typeof(StringEnumConverter))] public enum QuantumGroupType { [EnumMember(Value = @"sockets")] Sockets = 0, [EnumMember(Value = @"states")] States = 1, FailedValidation = 10 } [JsonObject] public class QuantumGroupInfo { /// /// What type of group this is: does it define a list of states a single quantum object could take or a list of sockets one or more quantum objects could share? /// public QuantumGroupType type; /// /// A unique string used by props (that are marked as quantum) use to refer back to this group /// public string id; /// /// Only required if type is `sockets`. This lists all the possible locations for any props assigned to this group. /// public QuantumSocketInfo[] sockets; /// /// Optional. Only used if type is `states`. If this is true, then the first prop made part of this group will be used to construct a visibility box for an empty game object, which will be considered one of the states. /// public bool hasEmptyState; /// /// Optional. Only used if type is `states`. If this is true, then the states will be presented in order, rather than in a random order /// public bool sequential; /// /// Optional. Only used if type is `states` and `sequential` is true. If this is false, then after the last state has appeared, the object will no longer change state /// [DefaultValue(true)] public bool loop = true; } [JsonObject] public class QuantumSocketInfo : GeneralPropInfo { /// /// Whether the socket will be placed relative to the group it belongs to. Overrides `isRelativeToParent` /// [DefaultValue(true)] public bool isRelativeToGroup = true; /// /// The probability any props that are part of this group will occupy this socket /// [DefaultValue(1f)] public float probability = 1f; } [JsonObject] public class RemoteInfo { /// /// The unique remote id /// public string id; /// /// Icon that the will show on the stone, pedastal of the whiteboard, and pedastal of the platform. /// public string decalPath; /// /// Whiteboard that the stones can put text onto /// public WhiteboardInfo whiteboard; /// /// Camera platform that the stones can project to and from /// public PlatformInfo platform; /// /// Projection stones /// public StoneInfo[] stones; [JsonObject] public class WhiteboardInfo : GeneralPropInfo { /// /// The text for each stone /// public SharedNomaiTextInfo[] nomaiText; /// /// Disable the wall, leaving only the pedestal and text. /// public bool disableWall; [JsonObject] public class SharedNomaiTextInfo { /// /// The id of the stone this text will appear for /// public string id; /// /// Additional information about each arc in the text /// public NomaiTextArcInfo[] arcInfo; /// /// The random seed used to pick what the text arcs will look like. /// public int seed; // For randomizing arcs /// /// The location of this object. /// [DefaultValue("unspecified")] public NomaiTextInfo.NomaiTextLocation location = NomaiTextInfo.NomaiTextLocation.UNSPECIFIED; /// /// The relative path to the xml file for this object. /// public string xmlFile; /// /// An optional rename of this object /// public string rename; } } [JsonObject] public class PlatformInfo : GeneralPropInfo { /// /// A ship log fact to reveal when the platform is connected to. /// [DefaultValue("")] public string reveals = ""; /// /// Disable the structure, leaving only the pedestal. /// public bool disableStructure; /// /// Disable the pool that rises when you place a stone. /// public bool disablePool; } [JsonObject] public class StoneInfo : GeneralPropInfo { } } } }