using DominionBase.Cards; using DominionBase.Piles; using DominionBase.Properties; using System; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.Linq; namespace DominionBase { public enum ChoiceType { Unknown, Cards, Options, Supplies, SuppliesAndCards, Boons } public enum ChoiceOutcome { Gain, Discard, Trash, Select } public delegate void Choose(IPlayer player, Choice choice); public class Choice { public Guid UniqueId { get; } = Guid.NewGuid(); public string Text { get; } public IGameObject Source { get; } public ICardBaseCollection Triggers { get; } public IPlayer PlayerSource { get; } public Visibility Visibility { get; } = Visibility.All; public OptionCollection Options { get; } public SupplyCollection Supplies { get; } public bool IsOrdered { get; } public bool IsSpecific { get; } public int Minimum { get; } public int Maximum { get; } public EventArgs EventArgs { get; } public ChoiceOutcome ChoiceOutcome { get; } private Choice(string text, IGameObject source, ICardBaseCollection triggers, ChoiceType type, ChoiceOutcome outcome, IPlayer playerSource, EventArgs eventArgs, bool isOrdered, bool isSpecific, int minimum, int maximum) { Text = text; Source = source; Triggers = triggers; ChoiceType = type; ChoiceOutcome = outcome; PlayerSource = playerSource; EventArgs = eventArgs; IsOrdered = isOrdered; IsSpecific = isSpecific; Minimum = minimum < 0 ? 0 : minimum; Maximum = maximum < Minimum ? Minimum : maximum; } #region Cards public Choice(string text, IGameObject source, ICardBase trigger, ChoiceOutcome outcome, IEnumerable cards, IPlayer playerSource, bool optional, EventArgs eventArgs) : this(text, source, new ICardBaseCollection { trigger }, ChoiceType.Cards, outcome, playerSource, eventArgs, false, false, optional ? 0 : 1, 1) { Cards = cards; } public Choice(string text, IGameObject source, ICardBase trigger, IEnumerable cards, ChoiceOutcome outcome, IPlayer playerSource, bool isOrdered = false, int minimum = 1, int maximum = 1) : this(text, source, new ICardBaseCollection { trigger }, ChoiceType.Cards, outcome, playerSource, null, isOrdered, false, minimum, maximum) { Cards = cards; } public Choice(string text, IGameObject source, IEnumerable cards, ChoiceOutcome outcome, IPlayer playerSource, bool isOrdered = false, bool isSpecific = false, int minimum = 1, int maximum = 1, Visibility visibility = Visibility.All) : this(text, source, new ICardBaseCollection(), ChoiceType.Cards, outcome, playerSource, null, isOrdered, false, minimum, maximum) { Cards = cards; Visibility = visibility; } public Choice(string text, IGameObject source, ISupply supply, ChoiceOutcome outcome, IPlayer playerSource, int minimum, int maximum) : this(text, source, new ICardBaseCollection(), ChoiceType.Cards, outcome, playerSource, null, false, false, minimum, maximum) { Contract.Requires(supply != null, "supply cannot be null"); Cards = new ItemCollection(supply.Types.Where(supply.CanGain).Select(Card.CreateInstance)); } #endregion #region String Options public Choice(string text, IGameObject source, OptionCollection options, IPlayer playerSource) : this(text, source, new ICardBaseCollection(), ChoiceType.Options, ChoiceOutcome.Select, playerSource, null, false, false, options.IsAnyRequired ? 1 : 0, 1) { Options = options; } public Choice(string text, OptionCollection options, IPlayer playerSource, EventArgs eventArgs, ICardBaseCollection triggers = null) : this(text, null, triggers == null ? new ICardBaseCollection() : triggers, ChoiceType.Options, ChoiceOutcome.Select, playerSource, eventArgs, false, false, options.IsAnyRequired ? 1 : 0, 1) { Options = options; } public Choice(string text, IGameObject source, ICardBase trigger, List options, IPlayer playerSource, EventArgs eventArgs = null, bool isOrdered = false, int minimum = 1, int maximum = 1) : this(text, source, new ICardBaseCollection { trigger }, ChoiceType.Options, ChoiceOutcome.Select, playerSource, eventArgs, isOrdered, false, minimum, maximum) { Options = new OptionCollection(options, source); } public Choice(string text, IGameObject source, ICardBaseCollection triggers, List options, IPlayer playerSource, EventArgs eventArgs = null, bool isOrdered = false, int minimum = 1, int maximum = 1) : this(text, source, triggers, ChoiceType.Options, ChoiceOutcome.Select, playerSource, eventArgs, isOrdered, false, minimum, maximum) { Options = new OptionCollection(options, source); } #endregion #region Supplies public Choice(string text, IGameObject source, SupplyCollection supplies, ChoiceOutcome outcome, IPlayer playerSource, bool optional) : this(text, source, new ICardBaseCollection(), ChoiceType.Supplies, outcome, playerSource, null, false, false, optional ? 0 : 1, 1) { Supplies = supplies; } #endregion #region Boons public Choice(string text, IGameObject source, IEnumerable boons, IPlayer playerSource) : this(text, source, new ICardBaseCollection(), ChoiceType.Boons, ChoiceOutcome.Select, playerSource, null, false, true, 1, 1) { Boons = boons; } #endregion public void AddCard(Card card) { switch (ChoiceType) { case ChoiceType.Cards: case ChoiceType.SuppliesAndCards: Cards = Cards.Concat(new ItemCollection { card }); break; case ChoiceType.Supplies: Cards = Cards.Concat(new ItemCollection { card }); ChoiceType = ChoiceType.SuppliesAndCards; break; default: throw new ArgumentException(Resource.ExceptionCannotAddCardsToChoiceType); } } public void AddCards(IEnumerable cards) { switch (ChoiceType) { case ChoiceType.Cards: case ChoiceType.SuppliesAndCards: Cards = Cards.Concat(cards); break; case ChoiceType.Supplies: Cards = cards; ChoiceType = ChoiceType.SuppliesAndCards; break; default: throw new ArgumentException(Resource.ExceptionCannotAddCardsToChoiceType); } } public IEnumerable Cards { get; private set; } public IEnumerable Boons { get; private set; } public ChoiceType ChoiceType { get; private set; } public static Choice CreateYesNoChoice(string text, IGameObject source, IPlayer playerSource) { return new Choice(text, source, new ICardBaseCollection(), new List { Resource.Yes, Resource.No }, playerSource); } public static Choice CreateYesNoChoice(string text, IGameObject source, ICardBase trigger, IPlayer playerSource, EventArgs eventArgs) { return new Choice(text, source, trigger, new List { Resource.Yes, Resource.No }, playerSource, eventArgs); } } public class ChoiceResult { private ChoiceResult(ChoiceType choiceType) { ChoiceType = choiceType; } public ChoiceResult(ItemCollection cards) : this(ChoiceType.Cards) { Cards = cards; } public ChoiceResult(Card card) : this(ChoiceType.Cards) { Cards = new ItemCollection { card }; } public ChoiceResult(ItemCollection boons) : this(ChoiceType.Boons) { Boons = boons; } public ChoiceResult(string option) : this(ChoiceType.Options) { Options = new List { option }; } public ChoiceResult(IEnumerable options) : this(ChoiceType.Options) { Options = new List(options); } public ChoiceResult(OptionCollection options) : this(ChoiceType.Options) { Options = new List(options.Select(o => o.Text)); } public ChoiceResult(Option option) : this(ChoiceType.Options) { Contract.Requires(option != null, "option cannot be null"); Options = new List { option.Text }; } public ChoiceResult(ISupply supply) : this(ChoiceType.Supplies) { Supply = supply; } public ChoiceResult() : this(ChoiceType.Unknown) { } public ChoiceType ChoiceType { get; } public ItemCollection Cards { get; } public ItemCollection Boons { get; } public List Options { get; } public ISupply Supply { get; } } }