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 boon and declaring what it is, what happens when it is taken, and what benefits it may provide. /// See the standard constructor for more detailed information about basic setup. /// public abstract class Boon : IBoon, IComparable, IDisposable, IRandomizable, ITableable { public virtual event PileChangedEventHandler PileChanged; public virtual event TokensChangedEventHandler TokensChanged; internal IGame _Game; private string _ActionText = ""; private string _ExtraText = string.Empty; private readonly Traits _Traits = Traits.Basic; private bool _AsynchronousChanging; private PileChangedEventArgs _AsynchronousPileChangedEventArgs; private CardBenefit _Benefit; internal Boon(Source source, Traits traits, Edition edition = Edition.All) { Name = ResourcesHelper.Get($"{source}_{Type.Name}_Name"); Source = source; _Benefit = new CardBenefit(); if (traits == Traits.None) _Traits = traits; else _Traits |= traits; Edition = edition; Text = ResourcesHelper.Get($"{source}_{Type.Name}_Text"); } public void Init(IGame game, PlayerCollection players) { _Game = game; } public static Boon CreateInstance(Type type) { return (Boon)Activator.CreateInstance(type); } #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. _Benefit = null; } // 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; } } ~Boon() { Dispose(false); } #endregion public virtual List GetSerializingTypes() { return new List(); } 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(); #region ICardBase Properties public virtual Cost BaseCost { get; } = new Cost(); public Type BaseType => GetType(); public virtual Categories Category { get; } = Categories.Boon; public virtual bool HasCost => false; public bool HasVPs => false; public virtual string SetupText => string.Empty; public virtual Source Source { get; } = Source.All; public string Text { get { var sb = new StringBuilder(); var sbBenefitText = new StringBuilder(); if (_Benefit.Any) sbBenefitText.Append(_Benefit.Text); if (!string.IsNullOrEmpty(_ActionText)) { if (sb.Length > 0 && !_ActionText.StartsWith("
", StringComparison.CurrentCulture)) { sb.AppendLine(); sb.AppendLine(); } sb.Append(_ActionText.Replace("", sbBenefitText.ToString())); } 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); } if (!_ActionText.Contains("")) _ActionText = $"{(string.IsNullOrEmpty(_ActionText) ? "" : Environment.NewLine)}{_ActionText}"; } } #endregion #region IDisplayable Properties public CardBack CardBack { get; } = CardBack.Standard; public IDisplayable DisplayCard => this; public Edition Edition { get; } public virtual Facing Facing { get; private set; } = Facing.FaceUp; public virtual bool IsStackable => true; public virtual Location Location { get; } = Location.Special; public Orientation Orientation { get; } = Orientation.Landscape; public virtual Traits Traits => _Traits; #endregion #region ITableable Properties public virtual bool CanUndo => false; public int Count => 1; public IDisplayable Randomizer => this; public Type TableableType => Type; public IEnumerable Types => new List { Type }; #endregion public Type Type => GetType(); public string Name { get; protected set; } public string ImageName => Type.Name; public IDisplayable RootCard => this; public virtual string SpecialPresetKey => null; public virtual CardBenefit Benefit => _Benefit; public virtual DisplayableCollection Stack() { return new DisplayableCollection { this }; } public virtual void Clear() { } public virtual int GetVictoryPoints(IPlayer player, IEnumerable collection) { return 0; } public virtual void End(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(Boon boonCard) { if (ReferenceEquals(this, boonCard)) return 0; if (boonCard is null) return -1; var nc = string.Compare(Name, boonCard.Name, StringComparison.InvariantCulture); if (nc == 0) nc = UniqueId.CompareTo(boonCard.UniqueId); return nc; } public int CompareTo(IDisplayable obj) { if (ReferenceEquals(this, obj)) return 0; if (obj is null) return -1; if (obj is Boon oBoon) return CompareTo(oBoon); if (obj is Card || obj is ISupply || obj is Event || obj is Project || obj is Landmark || obj is State) return 1; if (obj is Hex || obj is Artifact || obj is Way) return -1; var nc = string.Compare(Name, obj.Name, StringComparison.InvariantCulture); if (nc == 0) nc = UniqueId.CompareTo(obj.UniqueId); return nc; } public int CompareTo(ITableable obj) { Contract.Requires(obj != default(ITableable), "obj cannot be null"); if (obj is IDisplayable oDisp) return CompareTo(oDisp); return string.Compare(Name, obj.Name, StringComparison.CurrentCulture); } public override string ToString() { return Name; } /// /// The specified player receives the Boon /// /// The player receiving the Boon public virtual bool Receive(IPlayer player) { Contract.Requires(player != null, "player cannot be null"); player._Game.SendMessage(player, this, "Receive"); player.ReceiveBenefit(this, Benefit); return true; } 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 XmlNode GenerateXml(XmlDocument doc) { if (doc == null) throw new ArgumentNullException(nameof(doc)); var xeBoon = doc.CreateElement("boon"); return xeBoon; } public static Boon Load(IGame game, XmlNode xnEntity) { if (xnEntity == null) throw new ArgumentNullException(nameof(xnEntity)); var xnType = xnEntity.SelectSingleNode("type"); if (xnType == null) return null; var type = Type.GetType(xnType.InnerText); var boon = CreateInstance(type); boon.Load(xnEntity); return boon; } public void Load(XmlNode xnEntity) { if (xnEntity == null) return; var boonType = Type.GetType(xnEntity.Attributes["type"].Value); var boon = CreateInstance(boonType); //boon.LoadInstance(xnEntity); } } }