Draft matters with a vengeance (#5400)

* Next few Draft cards

* Whispergear Sneak

* Whispergear Sneak

* Code review fixes

* Fix index mapping

* Don't try to log if Draft doesnt have one
This commit is contained in:
Chris H
2024-06-12 02:18:12 -04:00
committed by GitHub
parent 5c02a580c3
commit 50746d9a72
17 changed files with 319 additions and 53 deletions

View File

@@ -50,7 +50,6 @@ import forge.util.Aggregates;
import forge.util.MyRandom;
import forge.util.Visitor;
import forge.util.collect.FCollection;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.tuple.Pair;
@@ -327,7 +326,9 @@ public class Game {
int plId = 0;
for (RegisteredPlayer psc : players0) {
IGameEntitiesFactory factory = (IGameEntitiesFactory)psc.getPlayer();
Player pl = factory.createIngamePlayer(this, plId++);
// If the Registered Player already has a pre-assigned ID, use that. Otherwise, assign a new one.
Integer id = psc.getId();
Player pl = factory.createIngamePlayer(this, id == null ? plId++ : id);
allPlayers.add(pl);
ingamePlayers.add(pl);

View File

@@ -2120,6 +2120,14 @@ public class CardProperty {
}
List<String> nameList = Lists.newArrayList(names.split(";"));
return nameList.contains(card.getName());
} else if (property.equals("NotedNameAetherSearcher")) {
String names = sourceController.getDraftNotes().get("Aether Searcher");
if (names == null || names.isEmpty()) {
return false;
}
List<String> nameList = Lists.newArrayList(names.split(";"));
return nameList.contains(card.getName());
} else if (property.equals("NotedTypes")) {
// Should Paliano Vanguard be hardcoded here or part of the property?

View File

@@ -2,7 +2,6 @@ package forge.game.player;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.game.CardTraitBase;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
@@ -15,6 +14,7 @@ import forge.util.Expressions;
import forge.util.TextUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
@@ -264,6 +264,10 @@ public class PlayerProperty {
if (source.getChosenPlayer() == null || !source.getChosenPlayer().equals(player)) {
return false;
}
} else if (property.equals("NotedDefender")) {
String tracker = player.getDraftNotes().getOrDefault("Cogwork Tracker", "");
return Iterables.contains(Arrays.asList(tracker.split(",")), String.valueOf(player));
} else if (property.startsWith("life")) {
int life = player.getLife();
int amount = AbilityUtils.calculateAmount(source, property.substring(6), spellAbility);

View File

@@ -1,13 +1,7 @@
package forge.game.player;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.LobbyPlayer;
import forge.deck.CardPool;
import forge.deck.Deck;
@@ -16,6 +10,11 @@ import forge.game.GameType;
import forge.item.IPaperCard;
import forge.item.PaperCard;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class RegisteredPlayer {
private final Deck originalDeck; // never return or modify this instance (it's a reference to game resources)
private Deck currentDeck;
@@ -37,6 +36,7 @@ public class RegisteredPlayer {
private List<PaperCard> vanguardAvatars = null;
private PaperCard planeswalker = null;
private int teamNumber = -1; // members of teams with negative id will play FFA.
private Integer id = null;
private boolean randomFoil = false;
private boolean enableETBCountersEffect = false;
@@ -45,6 +45,14 @@ public class RegisteredPlayer {
restoreDeck();
}
public final Integer getId() {
return id;
}
public final void setId(Integer id0) {
id = id0;
}
public final Deck getDeck() {
return currentDeck;
}

View File

@@ -1,17 +1,7 @@
package forge.screens.home.sanctioned;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.SwingUtilities;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.Singletons;
import forge.deck.Deck;
import forge.deck.DeckGroup;
@@ -38,6 +28,14 @@ import forge.screens.deckeditor.views.VStatistics;
import forge.toolbox.FOptionPane;
import forge.util.Localizer;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Controls the draft submenu in the home UI.
*
@@ -142,6 +140,12 @@ public enum CSubmenuDraft implements ICDoc {
FModel.getGauntletMini().resetGauntletDraft();
String duelType = (String)VSubmenuDraft.SINGLETON_INSTANCE.getCbOpponent().getSelectedItem();
if (duelType == null) {
FOptionPane.showErrorDialog("Please select duel types for the draft match.", "Missing opponent items");
return;
}
final DeckGroup opponentDecks = FModel.getDecks().getDraft().get(humanDeck.getName());
if (gauntlet) {
if ("Gauntlet".equals(duelType)) {
@@ -161,7 +165,7 @@ public enum CSubmenuDraft implements ICDoc {
}
});
List<Deck> aiDecks = Lists.newArrayList();
Map<Integer, Deck> aiMap = Maps.newHashMap();
if (VSubmenuDraft.SINGLETON_INSTANCE.isSingleSelected()) {
// Restore Zero Indexing
final int aiIndex = Integer.parseInt(duelType)-1;
@@ -169,28 +173,43 @@ public enum CSubmenuDraft implements ICDoc {
if (aiDeck == null) {
throw new IllegalStateException("Draft: Computer deck is null!");
}
aiDecks.add(aiDeck);
aiMap.put(aiIndex, aiDeck);
} else {
final int numOpponents = Integer.parseInt(duelType);
List<Deck> randomOpponents = Lists.newArrayList(opponentDecks.getAiDecks());
Collections.shuffle(randomOpponents);
aiDecks = randomOpponents.subList(0, numOpponents);
for(Deck d : aiDecks) {
if (d == null) {
int maxDecks = opponentDecks.getAiDecks().size();
if (numOpponents > maxDecks) {
throw new IllegalStateException("Draft: Not enough decks for the number of opponents!");
}
List<Integer> aiIndices = Lists.newArrayList();
for(int i = 0; i < maxDecks; i++) {
aiIndices.add(i);
}
Collections.shuffle(aiIndices);
aiIndices = aiIndices.subList(0, numOpponents);
for(int i : aiIndices) {
final Deck aiDeck = opponentDecks.getAiDecks().get(i);
if (aiDeck == null) {
throw new IllegalStateException("Draft: Computer deck is null!");
}
aiMap.put(i + 1, aiDeck);
}
}
final List<RegisteredPlayer> starter = new ArrayList<>();
// Human is 0
final RegisteredPlayer human = new RegisteredPlayer(humanDeck.getDeck()).setPlayer(GamePlayerUtil.getGuiPlayer());
starter.add(human);
for(Deck aiDeck : aiDecks) {
starter.add(new RegisteredPlayer(aiDeck).setPlayer(GamePlayerUtil.createAiPlayer()));
}
for (final RegisteredPlayer pl : starter) {
pl.assignConspiracies();
human.setId(0);
for(Map.Entry<Integer, Deck> aiDeck : aiMap.entrySet()) {
RegisteredPlayer aiPlayer = new RegisteredPlayer(aiDeck.getValue()).setPlayer(GamePlayerUtil.createAiPlayer());
aiPlayer.setId(aiDeck.getKey());
starter.add(aiPlayer);
aiPlayer.assignConspiracies();
}
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();

View File

@@ -26,6 +26,7 @@ import java.util.List;
public class BoosterDraftTest implements IBoosterDraft {
private int n = 3;
private int round = 1;
@Override
@Test(timeOut = 1000)
@@ -43,6 +44,11 @@ public class BoosterDraftTest implements IBoosterDraft {
return null;
}
@Override
public int getRound() {
return round;
}
@Override
public CardPool nextChoice() {
this.n--;
@@ -95,4 +101,9 @@ public class BoosterDraftTest implements IBoosterDraft {
public LimitedPlayer getNeighbor(LimitedPlayer p, boolean left) {
return null;
}
@Override
public LimitedPlayer getPlayer(int i) {
return null;
}
}

View File

@@ -0,0 +1,17 @@
Name:Aether Searcher
ManaCost:7
PT:6/4
Types:Artifact Creature Construct
Draft:Reveal CARDNAME as you draft it.
Draft:Reveal the next card you draft and note its name.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSearchHand | TriggerDescription$ When CARDNAME enters the battlefield, you may search your hand and/or library for a card with a name noted as you drafted cards named Aether Searcher. You may cast it without paying its mana cost. If you searched your library this way, shuffle.
SVar:TrigSearchHand:DB$ ChangeZone | Origin$ Hand | Destination$ Hand | ChangeType$ Card.NotedNameAetherSearcher | ChangeNum$ 1 | RememberChanged$ True | SubAbility$ TrigBranch
# Branch to casting the found spell
SVar:TrigBranch:DB$ Branch | BranchConditionSVar$ X | BranchConditionSVarCompare$ EQ1 | TrueSubAbility$ CastFromHand | FalseSubAbility$ SearchLibrary
SVar:CastFromHand:DB$ Play | ValidZone$ Hand | Valid$ Card.IsRemembered | Controller$ You | WithoutManaCost$ True | Optional$ True | SubAbility$ DBCleanup
# Or search the library
SVar:SearchLibrary:DB$ ChangeZone | Origin$ Library | Destination$ Library | ChangeType$ Card.NotedNameAetherSearcher | ChangeNum$ 1 | RememberChanged$ True | SubAbility$ CastFromLibrary
SVar:CastFromLibrary:DB$ Play | ValidZone$ Library | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | Valid$ Card.IsRemembered | Controller$ You | WithoutManaCost$ True | Optional$ True | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Remembered$Amount
Oracle:Reveal Aether Searcher as you draft it. Reveal the next card you draft and note its name.\nWhen Aether Searcher enters the battlefield, you may search your hand and/or library for a card with a name noted as you drafted cards named Aether Searcher. You may cast it without paying its mana cost. If you searched your library this way, shuffle.

View File

@@ -0,0 +1,8 @@
Name:Cogwork Spy
ManaCost:3
Types:Artifact Creature Bird Construct
PT:2/1
K:Flying
Draft:Reveal CARDNAME as you draft it.
Draft:You may look at the next card drafted from this booster pack.
Oracle:Reveal Cogwork Spy as you draft it. You may look at the next card drafted from this booster pack.\nFlying

View File

@@ -0,0 +1,9 @@
Name:Cogwork Tracker
ManaCost:4
Types:Artifact Creature Hound Construct
PT:4/4
Draft:Reveal CARDNAME as you draft it.
Draft:Note the player who passed CARDNAME to you.
S:Mode$ MustAttack | ValidCreature$ Card.Self | Description$ CARDNAME attacks each combat if able.
S:Mode$ MustAttack | ValidPlayer$ Opponent.NotedDefender | ValidCreature$ Card.Self | Description$ CARDNAME attacks a player you noted for cards named Cogwork Tracker each combat if able.
Oracle:Reveal Cogwork Tracker as you draft it and note the player who passed it to you.\nCogwork Tracker attacks each combat if able.\nCogwork Tracker attacks a player you noted for cards named Cogwork Tracker each combat if able.

View File

@@ -0,0 +1,8 @@
Name:Illusionary Informant
ManaCost:1 U
Types:Creature Bird Illusion
PT:1/3
Draft:Draft CARDNAME face up.
Draft:During the draft, you may turn CARDNAME face down. If you do, look at the next card drafted by a player of your choice.
K:Flying
Oracle:Draft Illusionary Informant face up.\nDuring the draft, you may turn Illusionary Informant face down. If you do, look at the next card drafted by a player of your choice.\nFlying

View File

@@ -0,0 +1,7 @@
Name:Whispergear Sneak
ManaCost:1
Types:Artifact Creature Construct
PT:1/1
Draft:Draft CARDNAME face up.
Draft:During the draft, you may turn CARDNAME face down. If you do, look at any unopened booster pack in the draft or any booster pack not being looked at by another player.
Oracle:Draft Whispergear Sneak face up.\nDuring the draft, you may turn Whispergear Sneak face down. If you do, look at any unopened booster pack in the draft or any booster pack not being looked at by another player.

View File

@@ -246,6 +246,7 @@ Garbage Fire
Hired Heist
Hold the Perimeter
Hymn of the Wilds
Illusionary Informant
Incendiary Dissent
Natural Unity
Noble Banneret

View File

@@ -222,15 +222,15 @@ ScryfallCode=CNS
[Draft Matters]
#1 Advantageous Proclamation|CNS
#1 AEther Searcher|CNS
1 AEther Searcher|CNS
#1 Agent of Acquisitions|CNS
#1 Backup Plan|CNS
1 Brago's Favor|CNS
#1 Canal Dredger|CNS
1 Cogwork Grinder|CNS
#1 Cogwork Librarian|CNS
#1 Cogwork Spy|CNS
#1 Cogwork Tracker|CNS
1 Cogwork Spy|CNS
1 Cogwork Tracker|CNS
#1 Deal Broker|CNS
#1 Double Stroke|CNS
1 Immediate Action|CNS
@@ -244,7 +244,7 @@ ScryfallCode=CNS
1 Secrets of Paradise|CNS
#1 Sentinel Dispatch|CNS
#1 Unexpected Potential|CNS
#1 Whispergear Sneak|CNS
1 Whispergear Sneak|CNS
#1 Worldknit|CNS
[tokens]

View File

@@ -285,9 +285,14 @@ public class BoosterDraft implements IBoosterDraft {
return draftLog;
}
@Override
public int getRound() {
return nextBoosterGroup;
}
@Override
public LimitedPlayer getNeighbor(LimitedPlayer player, boolean left) {
return players.get((player.order + (left ? -1 : 1) + N_PLAYERS) % N_PLAYERS);
return players.get((player.order + (left ? 1 : -1) + N_PLAYERS) % N_PLAYERS);
}
private void setupCustomDraft(final CustomLimited draft) {
@@ -412,6 +417,15 @@ public class BoosterDraft implements IBoosterDraft {
return this.localPlayer;
}
@Override
public LimitedPlayer getPlayer(int i) {
if (i == 0) {
return this.localPlayer;
}
return this.players.get(i - 1);
}
public void passPacks() {
// Alternate direction of pack passing
int adjust = this.nextBoosterGroup % 2 == 1 ? 1 : -1;
@@ -419,6 +433,7 @@ public class BoosterDraft implements IBoosterDraft {
adjust = 0;
} else if (currentBoosterPick % 2 == 1 && "Always".equals(this.doublePickDuringDraft)) {
// This may not work with Conspiracy cards that mess with the draft
// But it probably doesn't matter since Conspiracy doesn't have double pick?
adjust = 0;
}

View File

@@ -32,6 +32,7 @@ import forge.item.PaperCard;
*/
public interface IBoosterDraft {
int getRound();
CardPool nextChoice();
void setChoice(PaperCard c);
boolean hasNextChoice();
@@ -47,4 +48,5 @@ public interface IBoosterDraft {
void setLogEntry(IDraftLog draftingProcess);
IDraftLog getDraftLog();
LimitedPlayer getNeighbor(LimitedPlayer p, boolean left);
LimitedPlayer getPlayer(int i);
}

View File

@@ -19,6 +19,7 @@ public class LimitedPlayer {
protected int currentPack;
protected int draftedThisRound;
protected Deck deck;
protected PaperCard lastPick;
protected Queue<List<PaperCard>> packQueue;
protected Queue<List<PaperCard>> unopenedPacks;
@@ -33,17 +34,16 @@ public class LimitedPlayer {
private static final int NobleBanneretActive = 1 << 6;
private static final int PalianoVanguardActive = 1 << 7;
private static final int GrinderRemoveFromPool = 1 << 8;
private static final int MAXFLAGS = CantDraftThisRound | ReceiveLastCard | CanRemoveAfterDraft | SpyNextCardDrafted
| CanTradeAfterDraft | AnimusRemoveFromPool | NobleBanneretActive | PalianoVanguardActive
| GrinderRemoveFromPool;
private static final int SearcherNoteNext = 1 << 9;
private static final int WhispergearBoosterPeek = 1 << 10;
private static final int IllusionaryInformantPeek = 1 << 11;
private int playerFlags = 0;
private final List<PaperCard> faceUp = Lists.newArrayList();
private final List<PaperCard> revealed = Lists.newArrayList();
private final Map<String, List<String>> noted = new HashMap<>();
private final HashSet<String> semicolonDelimiter = Sets.newHashSet("Noble Banneret", "Cogwork Grinder");
private final HashSet<String> semicolonDelimiter = Sets.newHashSet("Noble Banneret", "Cogwork Grinder", "Aether Searcher");
IBoosterDraft draft;
@@ -69,6 +69,10 @@ public class LimitedPlayer {
return serialized;
}
public PaperCard getLastPick() {
return lastPick;
}
public Deck getDeck() {
return deck;
}
@@ -101,6 +105,7 @@ public class LimitedPlayer {
boolean alreadyRevealed = false;
chooseFrom.remove(bestPick);
lastPick = lastPick;
draftedThisRound++;
@@ -129,6 +134,41 @@ public class LimitedPlayer {
recordRemoveFromDraft(bestPick, choice);
}
LimitedPlayer fromPlayer = receivedFrom();
// If the previous player has an active Cogwork Spy, show them this card
if ((fromPlayer.playerFlags & SpyNextCardDrafted) == SpyNextCardDrafted) {
if (fromPlayer instanceof LimitedPlayerAI) {
// I'm honestly not sure what the AI would do by learning this information
// But just log that a reveal "happened"
addLog(this.name() + " revealed a card to " + fromPlayer.name() + " via Cogwork Spy.");
} else {
addLog(this.name() + " revealed " + bestPick.getName() + " to you with Cogwork Spy.");
}
fromPlayer.playerFlags &= ~SpyNextCardDrafted;
}
if ((playerFlags & SearcherNoteNext) == SearcherNoteNext) {
addLog(name() + " revealed " + bestPick.getName() + " for Aether Searcher.");
playerFlags &= ~SearcherNoteNext;
List<String> note = noted.computeIfAbsent("Aether Searcher", k -> Lists.newArrayList());
note.add(String.valueOf(bestPick.getName()));
}
if ((playerFlags & WhispergearBoosterPeek) == WhispergearBoosterPeek) {
if (handleWhispergearSneak()) {
addLog(name() + " peeked at a booster pack with Whispergear Sneak and turned it face down.");
playerFlags &= ~WhispergearBoosterPeek;
}
}
if ((playerFlags & IllusionaryInformantPeek) == IllusionaryInformantPeek) {
if (handleIllusionaryInformant()) {
addLog(name() + " peeked at " + fromPlayer.name() + "'s next pick with Illusionary Informant and turned it face down.");
playerFlags &= ~IllusionaryInformantPeek;
}
}
if (removedFromPool) {
// Can we hide this from UI?
return true;
@@ -182,7 +222,21 @@ public class LimitedPlayer {
addLog(name() + " revealed " + bestPick.getName() + " and noted " + String.join(",", chosenColors) + " chosen colors.");
}
else {
addLog(name() + " revealed " + bestPick.getName() + " as they drafted it.");
if (Iterables.contains(draftActions, "You may look at the next card drafted from this booster pack.")) {
// Cogwork Spy
playerFlags |= SpyNextCardDrafted;
}
if (Iterables.contains(draftActions, "Note the player who passed CARDNAME to you.")) {
// Note who passed it to you.
// If you receive last card from Canal Dredger, we need to figure out who last had the pack?
List<String> note = noted.computeIfAbsent(bestPick.getName(), k -> Lists.newArrayList());
note.add(String.valueOf(fromPlayer.order));
} else if (Iterables.contains(draftActions, "Reveal the next card you draft and note its name.")) {
playerFlags |= SearcherNoteNext;
}
addLog(name() + " revealed " + bestPick.getName() + " as " + name() + " drafted it.");
}
}
if (Iterables.contains(draftActions, "Draft CARDNAME face up.")) {
@@ -202,18 +256,14 @@ public class LimitedPlayer {
playerFlags |= NobleBanneretActive;
} else if (Iterables.contains(draftActions, "As you draft a creature card, you may reveal it, note its creature types, then turn CARDNAME face down.")) {
playerFlags |= PalianoVanguardActive;
} else if (Iterables.contains(draftActions, "During the draft, you may turn CARDNAME face down. If you do, look at any unopened booster pack in the draft or any booster pack not being looked at by another player.")) {
playerFlags |= WhispergearBoosterPeek;
// Do we need to ask to use the Sneak immediately?
} else if (Iterables.contains(draftActions, "During the draft, you may turn CARDNAME face down. If you do, look at the next card drafted by a player of your choice.")) {
playerFlags |= IllusionaryInformantPeek;
}
}
// Note who passed it to you. (Either player before you in draft passing order except if you receive the last card
// TODO Cogwork Tracker
// Note next card on this card
// TODO Aether Searcher (for the next card)
// Peek at next card from this pack
// TODO Cogwork Spy
// TODO Lore Seeker
// This adds a pack and MIGHT screw up all of our assumptions about pack passing. Do this last probably
@@ -221,13 +271,20 @@ public class LimitedPlayer {
}
public void addLog(String message) {
this.draft.getDraftLog().addLogEntry(message);
if (this.draft.getDraftLog() != null) {
this.draft.getDraftLog().addLogEntry(message);
}
// Mobile doesnt have a draft log yet
}
public List<PaperCard> nextChoice() {
return packQueue.peek();
}
public LimitedPlayer receivedFrom() {
return draft.getNeighbor(this, draft.getRound() % 2 == 0);
}
public void newPack() {
currentPack = order;
draftedThisRound = 0;
@@ -430,10 +487,65 @@ public class LimitedPlayer {
return alreadyRevealed;
}
public boolean handleWhispergearSneak() {
if (Objects.equals(SGuiChoose.oneOrNone("Peek at a booster pack with Whispergear Sneak?", Lists.newArrayList("Yes", "No")), "No")) {
return false;
}
int round = 3;
if (draft.getRound() != 3) {
round = SGuiChoose.getInteger("Which round would you like to peek at?", draft.getRound(), 3);
}
int playerId = SGuiChoose.getInteger("Which player would you like to peek at?", 0, draft.getOpposingPlayers().length);
SGuiChoose.reveal("Peeked booster", peekAtBoosterPack(round, playerId));
// This reveal popup doesn't update the card detail panel in draft
// How do we get to do that?
return true;
}
protected List<PaperCard> peekAtBoosterPack(int round, int playerNumber) {
if (draft.getRound() > round) {
// There aren't any unopened packs from earlier rounds
return null;
}
int relativeRound = round - draft.getRound();
LimitedPlayer player;
if (playerNumber == 0) {
player = this.draft.getHumanPlayer();
} else {
player = this.draft.getOpposingPlayers()[playerNumber - 1];
}
if (relativeRound == 0) {
// I want to see a pack from the current round
return player.packQueue.peek();
} else {
return player.unopenedPacks.peek();
}
}
public boolean handleIllusionaryInformant() {
Integer player = SGuiChoose.getInteger("Peek at another player's last pick?", 0, draft.getOpposingPlayers().length);
if (Objects.equals(player, null)) {
return false;
}
LimitedPlayer peekAt = draft.getPlayer(player);
if (peekAt == null) {
return false;
}
SGuiChoose.reveal("Player " + player + " lastPicked: ", Lists.newArrayList(peekAt.getLastPick()));
return true;
}
/*
public void addSingleBoosterPack(boolean random) {
// TODO Lore Seeker
// Generate booster pack then, insert it "before" the pack we're currently drafting from
}
*/
}

View File

@@ -6,6 +6,7 @@ import forge.deck.Deck;
import forge.deck.DeckSection;
import forge.item.PaperCard;
import forge.localinstance.properties.ForgePreferences;
import forge.util.MyRandom;
import java.util.Collections;
import java.util.List;
@@ -141,4 +142,39 @@ public class LimitedPlayerAI extends LimitedPlayer {
return types.containsAll(notedTypes);
}
@Override
public boolean handleWhispergearSneak() {
// Always choose the next pack I will open
// What do I do with this information? Great question. I have no idea.
List<PaperCard> cards;
if (draft.getRound() == 3) {
// Take a peek at the pack you are about to get if its the last round
cards = peekAtBoosterPack(this.order, 1);
} else {
cards = peekAtBoosterPack(this.order, draft.getRound() + 1);
}
return true;
}
@Override
public boolean handleIllusionaryInformant() {
// Always choose the next pack I will open
// What do I do with this information? Great question. I have no idea.
int player;
do {
player = MyRandom.getRandom().nextInt(draft.getOpposingPlayers().length + 1);
} while(player == this.order);
LimitedPlayer peekAt = draft.getPlayer(player);
if (peekAt == null) {
return false;
}
// Not really sure what the AI does with this information. But its' known now.
//peekAt.getLastPick();
return true;
}
}