using System; using System.Linq; using Artemis.Storage.Entities.Profile.Abstract; using Artemis.Storage.Entities.Profile.Conditions; namespace Artemis.Core; /// /// Represents a condition that is based on a data model value /// public class StaticCondition : CorePropertyChanged, INodeScriptCondition { private readonly string _displayName; private readonly StaticConditionEntity _entity; private StaticPlayMode _playMode; private StaticStopMode _stopMode; private bool _wasMet; /// /// Creates a new instance of the class /// public StaticCondition(RenderProfileElement profileElement) { _entity = new StaticConditionEntity(); _displayName = profileElement.GetType().Name; ProfileElement = profileElement; Script = new NodeScript($"Activate {_displayName}", $"Whether or not this {_displayName} should be active", profileElement.Profile); } internal StaticCondition(StaticConditionEntity entity, RenderProfileElement profileElement) { _entity = entity; _displayName = profileElement.GetType().Name; ProfileElement = profileElement; Script = null!; Load(); } /// /// Gets the script that drives the static condition /// public NodeScript Script { get; private set; } /// /// Gets or sets the mode in which the render element starts its timeline when display conditions are met /// public StaticPlayMode PlayMode { get => _playMode; set => SetAndNotify(ref _playMode, value); } /// /// Gets or sets the mode in which the render element stops its timeline when display conditions are no longer met /// public StaticStopMode StopMode { get => _stopMode; set => SetAndNotify(ref _stopMode, value); } /// public IConditionEntity Entity => _entity; /// public RenderProfileElement ProfileElement { get; } /// public bool IsMet { get; private set; } /// public void Update() { _wasMet = IsMet; // No need to run the script if the parent isn't met anyway bool parentConditionMet = ProfileElement.Parent is not RenderProfileElement renderProfileElement || renderProfileElement.DisplayConditionMet; if (!parentConditionMet) { IsMet = false; return; } if (!Script.ExitNodeConnected) { IsMet = true; } else { Script.Run(); IsMet = Script.Result; } } /// public void UpdateTimeline(double deltaTime) { if (IsMet && !_wasMet && ProfileElement.Timeline.IsFinished) ProfileElement.Timeline.JumpToStart(); else if (!IsMet && _wasMet && StopMode == StaticStopMode.SkipToEnd) ProfileElement.Timeline.JumpToEndSegment(); ProfileElement.Timeline.Update(TimeSpan.FromSeconds(deltaTime), PlayMode == StaticPlayMode.Repeat && IsMet); } /// public void OverrideTimeline(TimeSpan position) { ProfileElement.Timeline.Override(position, PlayMode == StaticPlayMode.Repeat && position > ProfileElement.Timeline.Length); } /// public void Dispose() { Script.Dispose(); } #region Storage /// public void Load() { PlayMode = (StaticPlayMode) _entity.PlayMode; StopMode = (StaticStopMode) _entity.StopMode; Script = _entity.Script != null ? new NodeScript($"Activate {_displayName}", $"Whether or not this {_displayName} should be active", _entity.Script, ProfileElement.Profile) : new NodeScript($"Activate {_displayName}", $"Whether or not this {_displayName} should be active", ProfileElement.Profile); } /// public void Save() { _entity.PlayMode = (int) PlayMode; _entity.StopMode = (int) StopMode; // If the exit node isn't connected and there is only the exit node, don't save the script if (!Script.ExitNodeConnected && Script.Nodes.Count() == 1) { _entity.Script = null; } else { Script.Save(); _entity.Script = Script.Entity; } } /// public INodeScript? NodeScript => Script; /// public void LoadNodeScript() { Script.Load(); } #endregion } /// /// Represents a mode for render elements to start their timeline when display conditions are met /// public enum StaticPlayMode { /// /// Continue repeating the main segment of the timeline while the condition is met /// Repeat, /// /// Only play the timeline once when the condition is met /// Once } /// /// Represents a mode for render elements to stop their timeline when display conditions are no longer met /// public enum StaticStopMode { /// /// When conditions are no longer met, finish the the current run of the main timeline /// Finish, /// /// When conditions are no longer met, skip to the end segment of the timeline /// SkipToEnd }