using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; using System.Text; using System.Xml; using DominionBase.Enums; using DominionBase.Piles; using DominionBase.Players; namespace DominionBase.Cards { /// /// This is the standard abstract class for defining a state and declaring what it is and what benefits it may provide. /// See the standard constructor for more detailed information about basic setup. /// public abstract class State : IState, IComparable, ITableable, IDisposable, IRandomizable, IPoints { public virtual event PileChangedEventHandler PileChanged; public virtual event TokensChangedEventHandler TokensChanged; internal IGame _Game; private string _ActionText = string.Empty; private string _ExtraText = string.Empty; private readonly Traits _Traits = Traits.Basic; protected bool _AsynchronousChanging { get; private set; } protected PileChangedEventArgs _AsynchronousPileChangedEventArgs { get; private set; } private int _VictoryPoints; internal State(Source source, Traits traits, Edition edition = Edition.All) { Name = ResourcesHelper.Get($"{source}_{Type.Name}_Name"); Source = source; if (traits == Traits.None) _Traits = traits; else _Traits |= traits; Edition = edition; var text = ResourcesHelper.Get($"{source}_{Type.Name}_{Edition}_Text"); if (string.IsNullOrEmpty(text)) text = ResourcesHelper.Get($"{source}_{Type.Name}_Text"); Text = text; SetupText = ResourcesHelper.Get($"{source}_{Type.Name}_Setup"); } internal void Init(IGame game, PlayerCollection players) { _Game = game; } public static State CreateInstance(Type type) { return (State)Activator.CreateInstance(type); } #region ICardBase variables, properties, & methods public virtual Cost BaseCost { get; } = new Cost(); public Type BaseType => GetType(); public virtual Categories Category { get; } = Categories.State; public virtual bool HasCost => false; public virtual bool HasVPs => VictoryPoints != 0; public virtual string SetupText { get; } = string.Empty; public virtual Source Source { get; } = Source.All; public string Text { get { var sb = new StringBuilder(); if (!string.IsNullOrEmpty(_ActionText)) { if (sb.Length > 0 && !_ActionText.StartsWith("
")) { sb.AppendLine(); sb.AppendLine(); } sb.Append(_ActionText); } if (!string.IsNullOrEmpty(_ExtraText)) { sb.Append("
"); sb.AppendLine(); sb.Append(_ExtraText); } return sb.ToString(); } protected set { if (value == null) value = string.Empty; var strings = value.Split(new[] { "
" }, StringSplitOptions.None); if (strings.Length > 0) { _ActionText = strings[0].Replace("", Environment.NewLine); if (strings.Length > 1) _ExtraText = strings[1].Replace("", Environment.NewLine); } } } public virtual List GetSerializingTypes() { return new List(); } #endregion #region IDisplayable public virtual Facing Facing { get; private set; } = Facing.FaceUp; public int CompareTo(IDisplayable obj) { if (obj is ITableable oTable) return CompareTo(oTable); return -1; } #endregion #region IDisposable variables, properties, & methods // Track whether Dispose has been called. private bool disposed; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { // Check to see if Dispose has already been called. if (!disposed) { // If disposing equals true, dispose all managed // and unmanaged resources. if (disposing) { // Dispose managed resources. } // Call the appropriate methods to clean up // unmanaged resources here. // If disposing is false, // only the following code is executed. // Note disposing has been done. disposed = true; } } ~State() { Dispose(false); } #endregion #region IPoints public virtual int VictoryPoints { get { return _VictoryPoints; } protected set { _VictoryPoints = value; } } public virtual int ComputeVictoryPoints(IPlayer player, IEnumerable collection) { return _VictoryPoints; } #endregion #region ITableable Properties public virtual bool CanUndo => true; public int Count => 1; public Orientation Orientation { get; } = Orientation.Landscape; public IDisplayable Randomizer => this; public Type TableableType => Type; public IEnumerable Types => new List { Type }; #endregion public virtual void CheckSetup(Preset preset, ITable table) { } public virtual void CheckSetup(Preset preset, string cardName, IRandomizable card) { } public virtual CardSettingCollection GenerateSettings() { return new CardSettingCollection(); } public virtual void FinalizeSettings(CardSettingCollection settings) { } public Guid UniqueId { get; } = Guid.NewGuid(); public Type Type => GetType(); public string Name { get; protected set; } public string ImageName => Type.Name; public IDisplayable RootCard => this; public IDisplayable DisplayCard => this; public virtual bool CanBeMultiples => true; public virtual Location Location { get; } = Location.Invisible; public virtual Traits Traits => _Traits; public virtual string SpecialPresetKey => null; public CardBack CardBack { get; } = CardBack.Standard; public virtual bool IsStackable => false; public virtual DisplayableCollection Stack() { return new DisplayableCollection { this }; } public virtual void Clear() { } public virtual int GetVictoryPoints(IPlayer player, IEnumerable collection) { return 0; } public Edition Edition { get; } public virtual void PerformEndgameCalculations(IPlayer player, PointsCollection collection) { } public void AddPlayer(IPlayer player) { Contract.Requires(player != null, "player cannot be null"); player.PhaseChanged += Player_PhaseChangedEvent; player.PlayerModeChanged += Player_PlayerModeChangedEvent; } public void RemovePlayer(IPlayer player) { Contract.Requires(player != null, "player cannot be null"); player.PhaseChanged -= Player_PhaseChangedEvent; player.PlayerModeChanged -= Player_PlayerModeChangedEvent; } void Player_PhaseChangedEvent(object sender, PhaseChangedEventArgs e) { PhaseChanged(sender, e); } void Player_PlayerModeChangedEvent(object sender, PlayerModeChangedEventArgs e) { PlayerModeChanged(sender, e); } internal virtual void PhaseChanged(object sender, PhaseChangedEventArgs e) { } internal virtual void PlayerModeChanged(object sender, PlayerModeChangedEventArgs e) { } public TokenCollection Tokens { get; } = new TokenCollection(); public void AddToken(Token token) { Tokens.Add(token); if (TokensChanged != null) { var etcea = new TokensChangedEventArgs(token); TokensChanged(this, etcea); } var pcea = new PileChangedEventArgs(Operation.Refresh); if (_AsynchronousChanging) _AsynchronousPileChangedEventArgs = pcea; else PileChanged?.Invoke(this, pcea); } public Token RemoveToken(Type tokenType) { var foundToken = Tokens.FirstOrDefault(t => t.GetType() == tokenType); return foundToken != null ? RemoveToken(foundToken) : null; } public Token RemoveToken(Token token) { Tokens.Remove(token); if (TokensChanged != null) { var etcea = new TokensChangedEventArgs(token); TokensChanged(this, etcea); } var pcea = new PileChangedEventArgs(Operation.Refresh); if (_AsynchronousChanging) _AsynchronousPileChangedEventArgs = pcea; else PileChanged?.Invoke(this, pcea); return token; } public int CompareTo(State stateCard) { Contract.Requires(stateCard != default(State), "stateCard cannot be null"); if (ReferenceEquals(this, stateCard)) return 0; var nc = string.Compare(Name, stateCard.Name, StringComparison.CurrentCulture); if (nc == 0) nc = UniqueId.CompareTo(stateCard.UniqueId); return nc; } public int CompareTo(ITableable obj) { Contract.Requires(obj != default(ITableable), "obj cannot be null"); if (ReferenceEquals(this, obj)) return 0; if (obj is State oState) return CompareTo(oState); if (obj is Card || obj is ISupply || obj is Event || obj is Project || obj is Landmark) return 1; if (obj is Boon || obj is Hex || obj is Artifact || obj is Way) return -1; var nc = string.Compare(Name, obj.Name, StringComparison.CurrentCulture); if (nc == 0) nc = UniqueId.CompareTo(obj.UniqueId); return nc; } public override string ToString() { return Name; } public virtual void TearDown(IGame game) { } public virtual void BeginChanges() { _AsynchronousChanging = true; _AsynchronousPileChangedEventArgs = null; } public virtual void EndChanges() { _AsynchronousChanging = false; if (_AsynchronousPileChangedEventArgs != null) { PileChanged?.Invoke(this, _AsynchronousPileChangedEventArgs); } _AsynchronousPileChangedEventArgs = null; } public virtual void Reset() { } public void FullSetup() { Setup(); SnapshotSetup(); FinalizeSetup(); } public virtual void Setup() { } public virtual void SnapshotSetup() { } public virtual void FinalizeSetup() { Finalize(_Game); } public virtual void Finalize(IGame game) { } public virtual void TakenBy(IPlayer player) { Contract.Requires(player != null, "player cannot be null"); player._Game.SendMessage(player, this, "Taken"); } public virtual void ReturnedBy(IPlayer player) { Contract.Requires(player != null, "player cannot be null"); player._Game.SendMessage(player, this, "Returned"); } public XmlNode GenerateXml(XmlDocument doc) { Contract.Requires(doc != null, "doc cannot be null"); var xeState = doc.CreateElement("state"); return xeState; } public static State Load(IGame game, XmlNode xnEntity) { Contract.Requires(xnEntity != null, "xnEntity cannot be null"); var xnType = xnEntity.SelectSingleNode("type"); if (xnType == null) return null; var type = Type.GetType(xnType.InnerText); var state = CreateInstance(type); state.Load(xnEntity); return state; } public void Load(XmlNode xnEntity) { if (xnEntity == null) return; var stateType = Type.GetType(xnEntity.Attributes["type"].Value); var state = CreateInstance(stateType); //state.LoadInstance(xnEntity); } } }