public bool AskForCardUsage(Prompt prompt, ICardUsageVerifier verifier, out ISkill skill, out List<Card> cards, out List<Player> players) { line = "U JiJiang 1: 2 3"; Match m = Regex.Match(line, @"U\s(?<skill>[A-Za-z]*)(?<cards>(\s\d+)*):(?<players>(\s\d+)*)"); skill = null; cards = null; players = null; if (m.Success) { if (m.Groups["skill"].Success) { foreach (ISkill s in hostPlayer.Skills) { if (s is CardTransformSkill) { } if (s is ActiveSkill) { } } } return true; } else { return false; } }
public bool AskForCardUsage(Prompt prompt, ICardUsageVerifier verifier, out ISkill skill, out List<Card> cards, out List<Player> players, out Player respondingPlayer) { cards = null; skill = null; players = null; respondingPlayer = null; return false; }
protected bool AskForSkillUse(ICardUsageVerifier verifier, out List<Card> cards, out List<Player> players, Prompt prompt = null) { ISkill skill; if (prompt == null) prompt = new CardUsagePrompt(this.GetType().Name, this); var ret = Game.CurrentGame.UiProxies[Owner].AskForCardUsage( prompt, verifier, out skill, out cards, out players); Trace.Assert(skill == null); return ret; }
public bool AskForCardUsage(Prompt prompt, ICardUsageVerifier verifier, out ISkill skill, out List<Card> cards, out List<Player> players, out Player respondingPlayer) { this.prompt = prompt; this.verifier = verifier; foreach (var inactiveProxy in inactiveProxies) { if (inactiveProxy.HostPlayer != null && !inactiveProxy.HostPlayer.IsDead) { inactiveProxy.TryAskForCardUsage(prompt, new NullVerifier()); } } pendingUiThread = new Thread(AskUiThread) { IsBackground = true }; pendingUiThread.Start(); proxy.SimulateReplayDelay(); if (!proxy.TryAnswerForCardUsage(prompt, verifier, out skill, out cards, out players)) { cards = new List<Card>(); players = new List<Player>(); skill = null; } pendingUiThread.Abort(); pendingUiThread = null; foreach (var otherProxy in inactiveProxies) { otherProxy.Freeze(); } proxy.Freeze(); proxy.NextQuestion(); // try to determine who used this respondingPlayer = null; if (cards != null && cards.Count > 0) { respondingPlayer = cards[0].Place.Player; } else { foreach (var p in Game.CurrentGame.Players) { if (p.ActionableSkills.Contains(skill)) { respondingPlayer = p; break; } } } if (skill != null || (cards != null && cards.Count > 0)) { Trace.Assert(respondingPlayer != null); } if (verifier.Verify(respondingPlayer, skill, cards, players) == VerifierResult.Success) { return true; } return false; }
/// <summary> /// 询问用户从若干牌堆中选择卡牌,例如顺手牵羊,观星等等。 /// </summary> /// <param name="prompt"></param> /// <param name="sourceDecks"></param> /// <param name="resultDeckNames"></param> /// <param name="resultDeckMaximums"></param> /// <param name="verifier"></param> /// <param name="answer">用户选择结果。对应resultDeckNames,每个选出的牌堆占用一个list。</param> /// <returns>False if user cannot provide an answer.</returns> public static bool AskForCardChoice(this Player p, Prompt prompt, List<DeckPlace> sourceDecks, List<string> resultDeckNames, List<int> resultDeckMaximums, ICardChoiceVerifier verifier, out List<List<Card>> answer, AdditionalCardChoiceOptions helper = null, CardChoiceRearrangeCallback callback = null) { return Game.CurrentGame.UiProxies[p].AskForCardChoice(prompt, sourceDecks, resultDeckNames, resultDeckMaximums, verifier, out answer, helper, callback); }
public bool AskForCardUsage(Prompt prompt, ICardUsageVerifier verifier, out ISkill skill, out List<Card> cards, out List<Player> players) { answerPending = new Semaphore(0, 1); proxy.AskForCardUsage(prompt, verifier, TimeOutSeconds); skill = null; cards = null; players = null; if (answerPending.WaitOne(TimeOutSeconds * 1000)) { skill = answerSkill; cards = answerCards; players = answerPlayers; } cards = cards ?? new List<Card>(); players = players ?? new List<Player>(); return (verifier.FastVerify(HostPlayer, answerSkill, cards, players) == VerifierResult.Success); }
/// <summary> /// 某玩家对某玩家视为使用一张虚拟的杀,能被技能转化,影响选择的目标,如疠火,朱雀羽扇 /// </summary> public static void UseDummyShaTo(Player source, Player target, CardHandler shaType, Prompt prompt, CardAttribute helper = null, bool notifyShaSound = true) { CompositeCard sha = new CompositeCard() { Type = shaType }; var v1 = new DummyShaVerifier(target, shaType, helper); ISkill skill; List<Card> cards; List<Player> players; Game.CurrentGame.Emit(GameEvent.PlayerIsAboutToUseCard, new PlayerIsAboutToUseOrPlayCardEventArgs() { Source = source, Verifier = v1 }); source.AskForCardUsage(prompt, v1, out skill, out cards, out players); GameEventArgs args = new GameEventArgs(); args.Source = source; args.Targets = new List<Player>(players); if (target != null) args.Targets.Add(target); args.Skill = skill == null ? new CardWrapper(source, shaType, notifyShaSound) : skill; args.Cards = cards; CompositeCard card = null; if (skill != null) { List<Card> dummyCards = new List<Card>() { new Card() { Type = shaType, Place = new DeckPlace(null, DeckType.None) } }; (skill as CardTransformSkill).TryTransform(dummyCards, null, out card); //虚拟的杀是不能有子卡的。 card.Subcards.Clear(); } //在触发 CommitActionToTargets 的时候,只有在这里,args.Card才会被赋值,且为CompositeCard args.Card = card; if (args.Targets.Count == 0) { foreach (Player p in Game.CurrentGame.AlivePlayers) { if (p != source && v1.FastVerify(source, skill, cards, new List<Player>() { p }) != VerifierResult.Fail) { args.Targets.Add(p); break; } } } try { Game.CurrentGame.Emit(GameEvent.CommitActionToTargets, args); } catch (TriggerResultException) { //程序总是不应该执行到这里的 Trace.Assert(false); } }
public bool AskForCardChoice(Prompt prompt, List<DeckPlace> sourceDecks, List<string> resultDeckNames, List<int> resultDeckMaximums, ICardChoiceVerifier verifier, out List<List<Card>> answer, List<bool> rearrangeable, ref int windowId, CardChoiceRearrangeCallback callback) { answerPending = new Semaphore(0, 1); proxy.AskForCardChoice(prompt, sourceDecks, resultDeckNames, resultDeckMaximums, verifier, TimeOutSeconds, rearrangeable, ref windowId, callback); if (answerPending.WaitOne(TimeOutSeconds * 1000)) { answer = answerCardsOfCards; } else { answer = null; } if (verifier.Verify(answer) == VerifierResult.Success) { return true; } return false; }
public bool AskForCardChoice(Prompt prompt, List<DeckPlace> sourceDecks, List<string> resultDeckNames, List<int> resultDeckMaximums, ICardChoiceVerifier verifier, out List<List<Card>> answer, AdditionalCardChoiceOptions options, CardChoiceRearrangeCallback callback) { answerPending = new Semaphore(0, 1); proxy.AskForCardChoice(prompt, sourceDecks, resultDeckNames, resultDeckMaximums, verifier, TimeOutSeconds, options, callback); answer = null; if (answerPending.WaitOne(TimeOutSeconds * 1000)) { answer = answerCardsOfCards; } if (answer == null) { return false; } else { return (verifier.Verify(answer) == VerifierResult.Success); } }
public bool AskForCardChoice(Prompt prompt, List<DeckPlace> sourceDecks, List<string> resultDeckNames, List<int> resultDeckMaximums, ICardChoiceVerifier verifier, out List<List<Card>> answer, AdditionalCardChoiceOptions options = null, CardChoiceRearrangeCallback callback = null) { Trace.TraceInformation("Asking Card Choice to {0}.", HostPlayer.Id); TryAskForCardChoice(prompt, sourceDecks, resultDeckNames, resultDeckMaximums, verifier, options, callback); SimulateReplayDelay(); NextQuestion(); if (TryAnswerForCardChoice(prompt, verifier, out answer, options, callback)) { uiProxy.Freeze(); if (answer == null || answer.Count == 0) { return false; } #if DEBUG Trace.Assert(verifier.Verify(answer) == VerifierResult.Success); #endif return true; } uiProxy.Freeze(); return false; }
public bool AskForMultipleChoice(Prompt prompt, List<string> questions, out int answer) { /* Player p = hostPlayer; Console.Write("I AM PLAYER {0}: ", p.Id); Console.Write(prompt + ":"); foreach (string s in questions) { Console.Write(" " + s + ", "); } Console.Write("Choose:"); string ids = Console.ReadLine(); int id = int.Parse(ids); if (id > questions.Count || id < 0) { answer = 0; return false; } answer = id; return true;*/ answer = 0; return false; }
public bool AskForCardUsage(Prompt prompt, ICardUsageVerifier verifier, out ISkill skill, out List<Card> cards, out List<Player> players) { Trace.TraceInformation("Asking Card Usage to {0}.", HostPlayer.Id); TryAskForCardUsage(prompt, verifier); if (active) { NextQuestion(); } else { Trace.TraceInformation("Not active player, defaulting."); } if (TryAnswerForCardUsage(prompt, verifier, out skill, out cards, out players)) { proxy.Freeze(); #if DEBUG Trace.Assert(verifier.FastVerify(HostPlayer, skill, cards, players) == VerifierResult.Success); #endif return true; } proxy.Freeze(); return false; }
public bool AskForCardUsage(Prompt prompt, ICardUsageVerifier verifier, out ISkill skill, out List<Card> cards, out List<Player> players) { bool ret = true; if (!TryAskForCardUsage(prompt, verifier, out skill, out cards, out players)) { SendNoAnswer(); ret = false; } else { SendCardUsage(skill, cards, players, verifier); } NextQuestion(); if (cards == null) { cards = new List<Card>(); } if (players == null) { players = new List<Player>(); } return ret; }
public bool AskForCardChoice(Prompt prompt, List<DeckPlace> sourceDecks, List<string> resultDeckNames, List<int> resultDeckMaximums, ICardChoiceVerifier verifier, out List<List<Card>> answer, List<bool> rearrangeable, ref int windowId, CardChoiceRearrangeCallback callback) { Trace.TraceInformation("Asking Card Choice to {0}.", HostPlayer.Id); TryAskForCardChoice(prompt, sourceDecks, resultDeckNames, resultDeckMaximums, verifier, rearrangeable, ref windowId, callback); if (active) { NextQuestion(); } else { Trace.TraceInformation("Not active player, defaulting."); } if (TryAnswerForCardChoice(prompt, verifier, out answer, callback)) { proxy.Freeze(); #if DEBUG Trace.Assert(verifier.Verify(answer) == VerifierResult.Success); #endif return true; } proxy.Freeze(); return false; }
public bool AskForCardChoice(Prompt prompt, List<DeckPlace> sourceDecks, List<string> resultDeckNames, List<int> resultDeckMaximums, ICardChoiceVerifier verifier, out List<List<Card>> answer, AdditionalCardChoiceOptions options, CardChoiceRearrangeCallback callback) { answer = null; bool ret = true; if (!TryAskForCardChoice(sourceDecks, resultDeckMaximums, verifier, out answer, options, callback)) { SendNoAnswer(); ret = false; } else { SendCardChoice(verifier, answer, options); } NextQuestion(); if (answer == null) { answer = new List<List<Card>>(); foreach (var v in resultDeckMaximums) { answer.Add(new List<Card>()); } } return ret; }
bool IPlayerProxy.AskForCardUsage(Prompt prompt, ICardUsageVerifier verifier, out ISkill skill, out List <Card> cards, out List <Player> players) { Player p = hostPlayer; Console.Write("I AM PLAYER {0}({1}): ", p.Id, p.Hero.Name); cards = new List <Card>(); VerifierResult r = verifier.FastVerify(HostPlayer, null, null, null); skill = null; Console.Write("Ask for card usage, {0}: ", prompt); int i = 0; foreach (ICard card in Game.CurrentGame.Decks[p, DeckType.Hand]) { Console.Write(" Card {0} {1}{2}{3}, ", i, card.Suit, card.Rank, card.Type.Name); i++; } again: Console.Write("Card id, -1 to trigger"); string ids = Console.ReadLine(); if (ids == null) { Thread.Sleep(200); cards = null; players = null; return(false); } int id = int.Parse(ids); if (id < -1) { cards = null; players = null; } else { if (id == -1) { Console.Write("Skill ID:"); ids = Console.ReadLine(); id = int.Parse(ids); if (id >= hostPlayer.Skills.Count || ((!(hostPlayer.Skills[id] is ActiveSkill)) && (!(hostPlayer.Skills[id] is CardTransformSkill)))) { goto again; } skill = hostPlayer.Skills[id]; while (true) { Console.Write("Card id, -1 to end"); ids = Console.ReadLine(); id = int.Parse(ids); if (id < 0) { break; } if (id >= Game.CurrentGame.Decks[p, DeckType.Hand].Count) { continue; } cards.Add(Game.CurrentGame.Decks[p, DeckType.Hand][id]); } } else { if (id < Game.CurrentGame.Decks[p, DeckType.Hand].Count) { cards.Add(Game.CurrentGame.Decks[p, DeckType.Hand][id]); } } players = null; r = verifier.FastVerify(HostPlayer, skill, cards, players); if (r == VerifierResult.Success) { return(true); } if (r == VerifierResult.Fail) { Console.Write("Failed check, again? 1 yes 0 no"); ids = Console.ReadLine(); id = int.Parse(ids); if (id == 1) { goto again; } } } { players = new List <Player>(); while (true) { Console.WriteLine(""); Console.Write("Target player: -1 to end"); ids = Console.ReadLine(); id = int.Parse(ids); if (id < 0) { break; } if (id > Game.CurrentGame.Players.Count) { Console.WriteLine("out of range"); } else { players.Add(Game.CurrentGame.Players[id]); } r = verifier.FastVerify(HostPlayer, skill, cards, players); if (r == VerifierResult.Partial) { Console.WriteLine("Require more"); } if (r == VerifierResult.Fail) { Console.WriteLine("Failed check"); players.Remove(Game.CurrentGame.Players[id]); } } r = verifier.FastVerify(HostPlayer, skill, cards, players); if (r == VerifierResult.Success) { return(true); } if (r == VerifierResult.Fail) { Console.Write("Failed check, again? 1 yes 0 no"); ids = Console.ReadLine(); id = int.Parse(ids); if (id == 1) { goto again; } } players = null; skill = null; cards = null; return(false); } }
public bool TryAskForCardUsage(Prompt prompt, ICardUsageVerifier verifier, out ISkill skill, out List<Card> cards, out List<Player> players) { cards = null; skill = null; players = null; int timeOut = TimeOutSeconds + (verifier.Helper != null ? verifier.Helper.ExtraTimeOutSeconds : 0); Trace.TraceInformation("Asking Card Usage to {0}, timeout {1}.", HostPlayer.Id, timeOut); int? count; if (!server.ExpectNext(clientId, timeOut)) { return false; } count = server.GetInt(clientId, 0); if (count == null || count == 0) { return false; } if (count == null) { return false; } count = server.GetInt(clientId, 0); if (count == 1) { skill = server.GetSkill(clientId, 0); if (skill == null) { return false; } if (!(skill is CheatSkill) && !HostPlayer.ActionableSkills.Contains(skill)) { Trace.TraceWarning("Client DDOS!"); return false; } } count = server.GetInt(clientId, 0); if (count == null) { return false; } cards = new List<Card>(); while (count-- > 0) { Card item = server.GetCard(clientId, 0); if (item == null) { return false; } if (item.Owner != HostPlayer) { if (!(verifier.Helper.OtherDecksUsed.Any(dc => dc == item.Place.DeckType) || (skill != null && skill.Helper.OtherDecksUsed.Any(dc => dc == item.Place.DeckType)))) { Trace.TraceWarning("Client hacking cards!"); return false; } } cards.Add(item); } count = server.GetInt(clientId, 0); if (count == null) { return false; } players = new List<Player>(); while (count-- > 0) { Player item = server.GetPlayer(clientId, 0); if (item == null) { return false; } players.Add(item); } bool requireUnique = true; if (skill is ActiveSkill) { if ((skill as ActiveSkill).Helper != null && (skill as ActiveSkill).Helper.IsPlayerRepeatable) requireUnique = false; } if ((players != null && players.Distinct().Count() != players.Count && requireUnique) || verifier.FastVerify(HostPlayer, skill, cards, players) != VerifierResult.Success) { Trace.TraceWarning("Client seems to be sending invalid answers at us. DDOS?"); cards = new List<Card>(); skill = null; players = new List<Player>(); return false; } return true; }
public bool AskForMultipleChoice(Prompt prompt, List<OptionPrompt> questions, out int answer) { bool ret = true; if (!TryAskForMultipleChoice(out answer)) { SendNoAnswer(); ret = false; } else { SendMultipleChoice(answer); } NextQuestion(); return ret; }
public void NotifyWuGuStart(Prompt prompt, DeckPlace place) { }
public void NotifyTwoSidesCardPickStart(Prompt prompt, DeckPlace place, IDictionary<int, int> groupMap, int group0MaxPick, int group1MaxPick) { }
public void NotifyLogEvent(Prompt custom, List<Player> players = null, bool isKeyEvent = true, bool useUICard = true) { }
public void AskForMultipleCardUsage(Prompt prompt, ICardUsageVerifier verifier, List<Player> players, out Dictionary<Player, ISkill> askill, out Dictionary<Player, List<Card>> acards, out Dictionary<Player, List<Player>> aplayers) { this.prompt = prompt; this.verifier = verifier; foreach (var inactiveProxy in inactiveProxies) { if (players.Contains(inactiveProxy.HostPlayer)) { inactiveProxy.TryAskForCardUsage(new CardUsagePrompt(""), new NullVerifier()); } } pendingUiThread = new Thread(AskUiThread) { IsBackground = true }; if (players.Contains(proxy.HostPlayer)) { pendingUiThread = new Thread(AskUiThread) { IsBackground = true }; pendingUiThread.Start(); } proxy.SimulateReplayDelay(); askill = new Dictionary<Player, ISkill>(); acards = new Dictionary<Player, List<Card>>(); aplayers = new Dictionary<Player, List<Player>>(); foreach (var p in players) { ISkill tempSkill; List<Card> tempCards; List<Player> tempPlayers; if (!proxy.TryAnswerForCardUsage(prompt, verifier, out tempSkill, out tempCards, out tempPlayers)) { tempCards = new List<Card>(); tempPlayers = new List<Player>(); tempSkill = null; } askill.Add(p, tempSkill); acards.Add(p, tempCards); aplayers.Add(p, tempPlayers); } if (players.Contains(proxy.HostPlayer)) { pendingUiThread.Abort(); proxy.Freeze(); proxy.NextQuestion(); } pendingUiThread = null; foreach (var otherProxy in inactiveProxies) { if (players.Contains(otherProxy.HostPlayer)) { otherProxy.Freeze(); } } }
public void NotifyTwoSidesCardPickStart(Prompt prompt, DeckPlace place, IDictionary <int, int> groupMap, int group0MaxPick, int group1MaxPick) { }
public void NotifyWuGuStart(Prompt prompt, DeckPlace place) { Application.Current.Dispatcher.Invoke((ThreadStart)delegate() { GameModel.WuGuModel = new WuGuChoiceViewModel(); GameModel.WuGuModel.Prompt = PromptFormatter.Format(prompt); bool isFirstRow = true; int i = 0; int total = Game.CurrentGame.Decks[place].Count; foreach (var c in Game.CurrentGame.Decks[place]) { if (isFirstRow && total > 4 && i >= total / 2) isFirstRow = false; var card = new CardViewModel() { Card = c, IsSelectionMode = true, IsEnabled = true }; if (isFirstRow) GameModel.WuGuModel.Cards1.Add(card); else GameModel.WuGuModel.Cards2.Add(card); card.OnSelectedChanged += new EventHandler(card_OnSelectedChanged); i++; } wuGuWindow.Show(); }); }
public void AskForMultipleChoice(Prompt prompt, List<OptionPrompt> questions, List<Player> players, out Dictionary<Player, int> aanswer) { this.prompt = prompt; this.questions = questions; foreach (var inactiveProxy in inactiveProxies) { if (players.Contains(inactiveProxy.HostPlayer)) { inactiveProxy.TryAskForMultipleChoice(prompt, questions); } } if (players.Contains(proxy.HostPlayer)) { pendingUiThread = new Thread(AskMCQUiThread) { IsBackground = true }; pendingUiThread.Start(); } proxy.SimulateReplayDelay(); aanswer = new Dictionary<Player, int>(); foreach (var p in players) { int answer = 0; proxy.TryAnswerForMultipleChoice(out answer); aanswer.Add(p, answer); } if (players.Contains(proxy.HostPlayer)) { pendingUiThread.Abort(); proxy.Freeze(); proxy.NextQuestion(); } pendingUiThread = null; foreach (var otherProxy in inactiveProxies) { if (players.Contains(otherProxy.HostPlayer)) { otherProxy.Freeze(); } } }
public void NotifyLogEvent(Prompt custom, List <Player> players = null, bool isKeyEvent = true, bool useUICard = true) { }
public void NotifyLogEvent(Prompt prompt) { }
private void _AppendKeyEventLog(Prompt custom, bool useUICard = true) { Paragraph para = new Paragraph(); para.Inlines.AddRange(LogFormatter.TranslateLogEvent(custom, useUICard)); _AppendKeyEventLog(para); }
public bool AskForMultipleChoice(Prompt prompt, List<string> questions, out int answer) { answerPending = new Semaphore(0, 1); proxy.AskForMultipleChoice(prompt, questions, TimeOutSeconds); if (answerPending.WaitOne(TimeOutSeconds * 1000)) { answer = answerMultipleChoice; } else { answer = 0; } return true; }
public void NotifyLogEvent(Prompt custom, List<Player> players = null, bool isKeyEvent = true, bool useUICard = true) { if (ViewModelBase.IsDetached) return; Application.Current.Dispatcher.Invoke((ThreadStart)delegate() { gameLogs.AppendLogEvent(players == null ? Game.CurrentGame.Players : players, custom, useUICard); rtbLog.ScrollToEnd(); if (isKeyEvent) _AppendKeyEventLog(custom, useUICard); }); }
public bool AskForCardChoice(Prompt prompt, List<DeckPlace> sourceDecks, List<string> resultDeckNames, List<int> resultDeckMaximums, ICardChoiceVerifier verifier, out List<List<Card>> answer, AdditionalCardChoiceOptions helper = null, CardChoiceRearrangeCallback callback = null) { throw new NotImplementedException(); }
public void NotifyTwoSidesCardPickStart(Prompt prompt, DeckPlace place, IDictionary<int, int> groupMap, int group0MaxPick, int group1MaxPick) { Application.Current.Dispatcher.Invoke((ThreadStart)delegate() { var twoSidesCardChoiceModel = new TwoSidesCardChoiceViewModel(); twoSidesCardChoiceModel.Prompt = LogFormatter.Translate(prompt); twoSidesCardChoiceModel.GroupOfPlayer = groupMap; foreach (var c in Game.CurrentGame.Decks[place]) { var card = new CardViewModel() { Card = c, IsSelectionMode = true, IsEnabled = true }; card.OnSelectedChanged += new EventHandler(card_OnSelectedChanged); twoSidesCardChoiceModel.CardsToPick.Add(card); } int mainPlayerMaxPick, opponentMaxPick; if (groupMap[GameModel.MainPlayerModel.Id] == 0) { mainPlayerMaxPick = group0MaxPick; opponentMaxPick = group1MaxPick; } else { mainPlayerMaxPick = group1MaxPick; opponentMaxPick = group0MaxPick; } for (int i = 0; i < mainPlayerMaxPick; i++) { twoSidesCardChoiceModel.CardsPicked1.Add(new CardSlotViewModel()); } for (int i = 0; i < opponentMaxPick; i++) { twoSidesCardChoiceModel.CardsPicked2.Add(new CardSlotViewModel()); } GameModel.TwoSidesCardChoiceModel = twoSidesCardChoiceModel; if (ViewModelBase.IsDetached) return; twoSidesCardChoiceBox.DataContext = twoSidesCardChoiceModel; twoSidesCardChoiceWindow.Show(); }); }
public bool AskForMultipleChoice(Prompt prompt, List<OptionPrompt> questions, out int answer) { throw new NotImplementedException(); }
bool IPlayerProxy.AskForCardChoice(Prompt prompt, List <DeckPlace> sourceDecks, List <string> resultDeckNames, List <int> resultDeckMaximums, ICardChoiceVerifier verifier, out List <List <Card> > answer, AdditionalCardChoiceOptions options, CardChoiceRearrangeCallback callback) { answer = null; return(false); }