using Microsoft.Xna.Framework; using System; using System.Collections.Generic; using System.Xml.Linq; using SpriteParams = Barotrauma.RagdollParams.SpriteParams; namespace Barotrauma { class DecorativeSprite : ISerializableEntity { public string Name => $"Decorative Sprite"; public Dictionary SerializableProperties { get; set; } public Sprite Sprite { get; private set; } public enum AnimationType { None, Sine, Noise } [Serialize("0,0", true), Editable] public Vector2 Offset { get; private set; } [Serialize(AnimationType.None, false), Editable] public AnimationType OffsetAnim { get; private set; } [Serialize(0.0f, true), Editable] public float OffsetAnimSpeed { get; private set; } private float rotationSpeedRadians; [Serialize(0.0f, true), Editable] public float RotationSpeed { get { return MathHelper.ToDegrees(rotationSpeedRadians); } private set { rotationSpeedRadians = MathHelper.ToRadians(value); } } private float rotationRadians; [Serialize(0.0f, true), Editable] public float Rotation { get { return MathHelper.ToDegrees(rotationRadians); } private set { rotationRadians = MathHelper.ToRadians(value); } } [Serialize(AnimationType.None, false), Editable] public AnimationType RotationAnim { get; private set; } /// /// If > 0, only one sprite of the same group is used (chosen randomly) /// [Serialize(0, false, description: "If > 0, only one sprite of the same group is used (chosen randomly)"), Editable(ReadOnly = true)] public int RandomGroupID { get; private set; } /// /// The sprite is only drawn if these conditions are fulfilled /// internal List IsActiveConditionals { get; private set; } = new List(); /// /// The sprite is only animated if these conditions are fulfilled /// internal List AnimationConditionals { get; private set; } = new List(); public DecorativeSprite(XElement element, string path = "", string file = "", bool lazyLoad = false) { Sprite = new Sprite(element, path, file, lazyLoad: lazyLoad); SerializableProperties = SerializableProperty.DeserializeProperties(this, element); foreach (XElement subElement in element.Elements()) { List conditionalList = null; switch (subElement.Name.ToString().ToLowerInvariant()) { case "conditional": case "isactiveconditional": conditionalList = IsActiveConditionals; break; case "animationconditional": conditionalList = AnimationConditionals; break; default: continue; } foreach (XAttribute attribute in subElement.Attributes()) { if (PropertyConditional.IsValid(attribute)) { conditionalList.Add(new PropertyConditional(attribute)); } } } } public Vector2 GetOffset(ref float offsetState) { if (OffsetAnimSpeed <= 0.0f) { return Offset; } switch (OffsetAnim) { case AnimationType.Sine: offsetState = offsetState % (MathHelper.TwoPi / OffsetAnimSpeed); return Offset * (float)Math.Sin(offsetState * OffsetAnimSpeed); case AnimationType.Noise: offsetState = offsetState % (1.0f / (OffsetAnimSpeed * 0.1f)); float t = offsetState * 0.1f * OffsetAnimSpeed; return new Vector2( Offset.X * (PerlinNoise.GetPerlin(t, t) - 0.5f), Offset.Y * (PerlinNoise.GetPerlin(t + 0.5f, t + 0.5f) - 0.5f)); default: return Offset; } } public float GetRotation(ref float rotationState) { if (rotationSpeedRadians <= 0.0f) { return rotationRadians; } switch (RotationAnim) { case AnimationType.Sine: rotationState = rotationState % (MathHelper.TwoPi / rotationSpeedRadians); return rotationRadians * (float)Math.Sin(rotationState * rotationSpeedRadians); case AnimationType.Noise: rotationState = rotationState % (1.0f / rotationSpeedRadians); return rotationRadians * (PerlinNoise.GetPerlin(rotationState * rotationSpeedRadians, rotationState * rotationSpeedRadians) - 0.5f); default: return rotationState * rotationSpeedRadians; } } public void Remove() { Sprite?.Remove(); Sprite = null; } } }