using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DominionBase.Piles;
using DominionBase.Players;
namespace DominionBase.Cards
{
public class OwnerChangedEventArgs : EventArgs
{
public Player OldOwner;
public Player NewOwner;
public OwnerChangedEventArgs(Player oldOwner, Player newOwner)
{
this.OldOwner = oldOwner;
this.NewOwner = newOwner;
}
}
public enum CardBack
{
Standard,
Red
}
///
/// This is the standard abstract class for defining a card and declaring what it is, what happens when it is played, and what benefits it may provide.
/// See the standard constructor for more detailed information about basic setup.
///
public abstract class Card : IComparable, ICard, IDisposable
{
public delegate void OwnerChangedEventHandler(object sender, OwnerChangedEventArgs e);
public event OwnerChangedEventHandler OwnerChanged = null;
private String _Name = String.Empty;
private String _ActionText = "";
private String _ExtraText = String.Empty;
private Category _Category = Category.Unknown;
private Source _Source = Source.All;
private Location _Location = Location.General;
private Group _GroupMembership = Group.Basic;
private Cost _BaseCost = new Cost(0);
private CardBack _CardBack = CardBack.Standard;
private CardBenefit _Benefit;
private CardBenefit _DurationBenefit;
private int _VictoryPoints = 0;
private Card _ModifiedBy = null;
private Dictionary _IsAttackBlocked = new Dictionary();
private Guid _UniqueId = Guid.NewGuid();
private Player _Owner = null;
private Token.TokenActionEventHandler _TokenEventHandler = null;
internal Card(String name, Category category, Source source, Location location)
{
_Name = name;
_Category = category;
_Source = source;
_Location = location;
Boolean isTreasure = (_Category & Category.Treasure) == Category.Treasure;
_Benefit = new CardBenefit(isTreasure);
_DurationBenefit = new CardBenefit(isTreasure);
if ((category & Cards.Category.Attack) == Cards.Category.Attack)
_GroupMembership |= Group.AffectOthers;
Boolean isAction = (category & Cards.Category.Action) == Cards.Category.Action;
Boolean isVictory = (category & Cards.Category.Victory) == Cards.Category.Victory;
Boolean isReaction = (category & Cards.Category.Reaction) == Cards.Category.Reaction;
Boolean isShelter = (category & Cards.Category.Shelter) == Cards.Category.Shelter;
if (((isAction && isTreasure) || (isAction && isVictory) || (isAction && isShelter)) ||
((isTreasure && isVictory) || (isTreasure && isReaction) || (isTreasure && isShelter)) ||
((isVictory && isReaction) || (isVictory && isShelter)) ||
(isReaction && isShelter))
_GroupMembership |= Group.MultiType;
}
internal Card(String name, Category category, Source source, Location location, Group group)
: this(name, category, source, location)
{
if (group == Group.None)
_GroupMembership = group;
else
_GroupMembership |= group;
}
internal Card(String name, Category category, Source source, Location location, CardBack cardBack)
: this(name, category, source, location)
{
_CardBack = cardBack;
}
internal Card(String name, Category category, Source source, Location location, Group group, CardBack cardBack)
: this(name, category, source, location, group)
{
_CardBack = cardBack;
}
public static Card CreateInstance(Type type)
{
return (Card)type.GetConstructor(Type.EmptyTypes).Invoke(null);
}
public virtual List GetSerializingTypes()
{
return new List();
}
public virtual void CheckSetup(Preset preset, Table table)
{
return;
}
public virtual void CheckSetup(Preset preset, Card card)
{
return;
}
public virtual CardSettingCollection GenerateSettings()
{
return new CardSettingCollection();
}
public virtual void FinalizeSettings(CardSettingCollection settings)
{
return;
}
public void TestFireAllEvents()
{
if (OwnerChanged != null)
OwnerChanged(this, new OwnerChangedEventArgs(null, null));
}
internal virtual void TearDown()
{
this.Owner = null;
}
#region IDisposable variables, properties, & methods
// Track whether Dispose has been called.
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
// Check to see if Dispose has already been called.
if (!this.disposed)
{
// If disposing equals true, dispose all managed
// and unmanaged resources.
if (disposing)
{
// Dispose managed resources.
_BaseCost = null;
_Benefit = null;
_DurationBenefit = null;
_ModifiedBy = null;
_Owner = 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;
}
}
~Card()
{
Dispose(false);
}
#endregion
public Guid UniqueId { get { return _UniqueId; } }
public Type CardType { get { return this.GetType(); } }
public virtual Type BaseType { get { return this.CardType; } }
public virtual Boolean IsStackable { get { return true; } }
public virtual String SpecialPresetKey { get { return null; } }
public String Name
{
get { return _Name; }
protected set { _Name = value; }
}
public String Text
{
get
{
StringBuilder sb = new StringBuilder();
StringBuilder sbBenefitText = new StringBuilder();
if (_Benefit.Any && _Benefit.Equals(_DurationBenefit))
{
sbBenefitText.AppendLine("Now and at the start of your next turn:");
sbBenefitText.Append(_Benefit.Text);
}
else
{
if (_Benefit.Any || (_Category & Category.Treasure) == Category.Treasure)
{
sbBenefitText.Append(_Benefit.Text);
}
if (_DurationBenefit.Any)
{
if (sbBenefitText.Length > 0)
{
sbBenefitText.AppendLine();
sbBenefitText.AppendLine();
}
sbBenefitText.AppendLine("At the start of your next turn:");
sbBenefitText.Append(_DurationBenefit.Text);
}
}
if (!String.IsNullOrEmpty(_ActionText))
{
if (sb.Length > 0 && !_ActionText.StartsWith("
"))
{
sb.AppendLine();
sb.AppendLine();
}
sb.Append(_ActionText.Replace("", sbBenefitText.ToString()));
}
if (_VictoryPoints != 0 || ((this.Category & Cards.Category.Victory) == Cards.Category.Victory && (this.GroupMembership & Group.VariableVPs) != Group.VariableVPs))
{
if (sb.Length > 0)
{
if ((this.Category & Cards.Category.Treasure) != Cards.Category.Treasure)
sb.Append("
");
else
{
sb.AppendLine();
sb.AppendLine();
}
}
sb.Append(String.Format("{0}", _VictoryPoints));
}
if (!String.IsNullOrEmpty(_ExtraText))
{
sb.Append("
");
sb.AppendLine();
sb.Append(_ExtraText);
}
return sb.ToString();
}
protected set
{
string[] strings = value.Split(new string[] { "
" }, StringSplitOptions.None);
if (strings.Length > 0)
{
_ActionText = strings[0].Replace("", System.Environment.NewLine);
if (strings.Length > 1)
_ExtraText = strings[1].Replace("", System.Environment.NewLine);
}
if (!_ActionText.Contains(""))
_ActionText = String.Format("{1}{0}", _ActionText, (String.IsNullOrEmpty(_ActionText) ? "" : System.Environment.NewLine));
}
}
public Category Category
{
get { return _Category; }
}
public Source Source
{
get { return _Source; }
}
public Location Location
{
get { return _Location; }
}
public Group GroupMembership
{
get { return _GroupMembership; }
}
public Cost BaseCost
{
get { return _BaseCost; }
protected set { _BaseCost = value; }
}
public CardBack CardBack
{
get { return _CardBack; }
}
public CardBenefit Benefit
{
get { return _Benefit; }
}
public CardBenefit DurationBenefit
{
get { return _DurationBenefit; }
}
public int VictoryPoints
{
get { return _VictoryPoints; }
protected set { _VictoryPoints = value; }
}
public Card ModifiedBy
{
get { return _ModifiedBy; }
internal set { _ModifiedBy = value; }
}
protected Dictionary IsAttackBlocked
{
get { return _IsAttackBlocked; }
}
public Player Owner
{
get { return _Owner; }
set
{
Player oldOwner = _Owner;
_Owner = value;
if (oldOwner != _Owner && OwnerChanged != null)
{
OwnerChangedEventArgs ocea = new OwnerChangedEventArgs(oldOwner, _Owner);
OwnerChanged(this, ocea);
}
}
}
public virtual Boolean IsEndgameTriggered(Supply supply)
{
return false;
}
public virtual int GetVictoryPoints(IEnumerable cards)
{
return _VictoryPoints;
}
public virtual void ObtainedBy(Player player)
{
this.Owner = player;
}
public virtual void LostBy(Player player)
{
this.Owner = null;
}
public virtual void AddedTo(DeckLocation location, Player player)
{
if (location == DeckLocation.Hand)
{
if (player._Game.Table.Supplies.ContainsKey(this))
{
if (player._Game.Table.Supplies[this].Tokens.Any(token => token.ActDefined))
{
_TokenEventHandler = new Token.TokenActionEventHandler(token_TokenAction);
player.TokenActedOn += _TokenEventHandler;
}
}
}
}
private void token_TokenAction(object sender, TokenActionEventArgs e)
{
e.Actor._Game.Table.Supplies[this].Tokens.ForEach(delegate(Token t) { t.Act(this, e); });
}
public virtual void AddedTo(Type deckType, Player player)
{
}
public virtual void RemovedFrom(DeckLocation location, Player player)
{
if (_TokenEventHandler != null)
player.TokenActedOn -= _TokenEventHandler;
_TokenEventHandler = null;
}
public virtual void RemovedFrom(Type deckType, Player player)
{
}
// Stub for Attacks, so they can get called during an existing attack
internal virtual void player_Attacked(object sender, AttackedEventArgs e)
{
}
public virtual void Setup(Game game, Supply supply)
{
}
public virtual void AddedToSupply(Game game, Supply supply)
{
}
///
/// Very basic card playing -- anything special needs to happen in the override for the specific card class
///
/// Game this card is associated with
public virtual void Play(Player player)
{
PlaySetup(player);
PlayRest(player);
}
protected virtual void PlaySetup(Player player)
{
if (player.Phase == PhaseEnum.Action &&
(this.Category & Category.Action) != Category.Action)
throw new Exception("Cannot play this card right now!");
if (player.Phase == PhaseEnum.Treasure &&
(this.Category & Category.Treasure) != Category.Treasure)
throw new Exception("Cannot play this card right now!");
if (player.Phase == PhaseEnum.Buy ||
player.Phase == PhaseEnum.Waiting ||
player.Phase == PhaseEnum.Cleanup ||
player.Phase == PhaseEnum.Choosing ||
player.Phase == PhaseEnum.Endgame ||
player.Phase == PhaseEnum.Starting)
throw new Exception("Cannot play cards right now!");
// This is an Attack card, so React-to-Attack cards must trigger before anything else
if ((this.Category & Cards.Category.Attack) == Cards.Category.Attack)
{
// Check Attack play reactions
IEnumerator enumerator = player._Game.GetPlayersStartingWithEnumerator(player);
enumerator.MoveNext();
this.IsAttackBlocked[enumerator.Current] = false;
while (enumerator.MoveNext())
this.IsAttackBlocked[enumerator.Current] = !enumerator.Current.AttackedBy(player, this);
}
}
protected virtual void PlayRest(Player player)
{
player.ReceiveBenefit(this, this.Benefit, true);
if ((this.Category & Category.Action) == Category.Action)
player.ActionPlayed();
}
public virtual void PlayFinished(Player player)
{
this.IsAttackBlocked.Clear();
}
public virtual Boolean CanCleanUp { get { return true; } }
public virtual void PlayDuration(Player player)
{
if (this.ModifiedBy != null)
this.ModifiedBy.Modify(player, this);
else
GainDurationBenefits(player);
}
protected virtual void GainDurationBenefits(Player player)
{
player.ReceiveBenefit(this, this.DurationBenefit, true);
}
protected virtual void Modify(Player player, Card card)
{
card.GainDurationBenefits(player);
}
public override string ToString()
{
return Name;
}
///
/// Returns true if the card can be bought
///
///
///
internal virtual Boolean CanBuy(Player player)
{
return CanGain();
}
internal virtual Boolean CanGain()
{
return true;
}
internal virtual CardCollection Gaining(Game game, Supply supplyPile)
{
return new CardCollection();
}
internal virtual CardCollection Buying(Game game, Supply supplyPile)
{
return new CardCollection();
}
internal virtual void PhaseChanged(object sender, PhaseChangedEventArgs e)
{
}
public int CompareTo(Card card)
{
if (ReferenceEquals(this, card))
return 0;
else if (card.CardType == Cards.Prosperity.TypeClass.Colony)
return 1;
else if (this.CardType == Cards.Prosperity.TypeClass.Colony)
return -1;
else if (card.CardType == Cards.Universal.TypeClass.Province)
return 1;
else if (this.CardType == Cards.Universal.TypeClass.Province)
return -1;
else if (card.CardType == Cards.Universal.TypeClass.Duchy)
return 1;
else if (this.CardType == Cards.Universal.TypeClass.Duchy)
return -1;
else if (card.CardType == Cards.Universal.TypeClass.Estate)
return 1;
else if (this.CardType == Cards.Universal.TypeClass.Estate)
return -1;
else if (card.CardType == Cards.Universal.TypeClass.Curse)
return 1;
else if (this.CardType == Cards.Universal.TypeClass.Curse)
return -1;
else if (card.CardType == Cards.Prosperity.TypeClass.Platinum)
return 1;
else if (this.CardType == Cards.Prosperity.TypeClass.Platinum)
return -1;
else if (card.CardType == Cards.Universal.TypeClass.Gold)
return 1;
else if (this.CardType == Cards.Universal.TypeClass.Gold)
return -1;
else if (card.CardType == Cards.Alchemy.TypeClass.Potion)
return 1;
else if (this.CardType == Cards.Alchemy.TypeClass.Potion)
return -1;
else if (card.CardType == Cards.Universal.TypeClass.Silver)
return 1;
else if (this.CardType == Cards.Universal.TypeClass.Silver)
return -1;
else if (card.CardType == Cards.Universal.TypeClass.Copper)
return 1;
else if (this.CardType == Cards.Universal.TypeClass.Copper)
return -1;
else if (card.BaseCost.Coin.Value < this.BaseCost.Coin.Value)
return -1;
else if (card.BaseCost.Coin.Value > this.BaseCost.Coin.Value)
return 1;
else if (card.BaseCost.Potion.Value < this.BaseCost.Potion.Value)
return -1;
else if (card.BaseCost.Potion.Value > this.BaseCost.Potion.Value)
return 1;
else
return this.Name.CompareTo(card.Name);
}
internal virtual void End(Player player, Deck deck)
{
}
internal virtual void Bought(Player player)
{
}
internal virtual void Gaining(Player player, ref DeckLocation location, ref DeckPosition position)
{
Receiving(player, ref location, ref position);
}
internal virtual void Gained(Player player)
{
ReceivedBy(player);
}
internal virtual void Receiving(Player player, ref DeckLocation location, ref DeckPosition position)
{
}
internal virtual void ReceivedBy(Player player)
{
this.ObtainedBy(player);
}
internal virtual void TrashedBy(Player player)
{
this.LostBy(player);
}
public virtual CardCollection CardStack()
{
return new CardCollection() { this };
}
}
}