Add Spire Phantasm, Agent of Acquisitions, Cogwork Librarian, Leovold's Operative (#5437)

* Next few Draft cards

* Code review fixes

* Add Spire Phantasm

* Add Agent of Acquisitions, Cogwork Librarian, Leovold's Operative

* Some small fixes

* Getting closer

* Now the UI is updating

* Switch DraftPack to a delegate class

* Fix agent of acquisitions when AI drafts it
This commit is contained in:
Chris H
2024-06-22 06:42:29 -04:00
committed by GitHub
parent e0d8bcf490
commit d4469ca736
16 changed files with 384 additions and 58 deletions

View File

@@ -174,6 +174,21 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
return cp != null && !cp.isEmpty(); return cp != null && !cp.isEmpty();
} }
public PaperCard removeCardName(String name) {
PaperCard paperCard;
for (Entry<DeckSection, CardPool> kv : parts.entrySet()) {
CardPool pool = kv.getValue();
for (Entry<PaperCard, Integer> pc : pool) {
if (pc.getKey().getName().equalsIgnoreCase(name)) {
paperCard = pc.getKey();
pool.remove(paperCard);
return paperCard;
}
}
}
return null;
}
// will return new if it was absent // will return new if it was absent
public CardPool getOrCreate(DeckSection deckSection) { public CardPool getOrCreate(DeckSection deckSection) {
CardPool p = get(deckSection); CardPool p = get(deckSection);

View File

@@ -2129,6 +2129,9 @@ public class CardProperty {
List<String> nameList = Lists.newArrayList(names.split(";")); List<String> nameList = Lists.newArrayList(names.split(";"));
return nameList.contains(card.getName()); return nameList.contains(card.getName());
} else if (property.equals("NotedGuessPhantasm")) {
String names = sourceController.getDraftNotes().get("Spire Phantasm");
return names != null && !names.isEmpty();
} else if (property.equals("NotedTypes")) { } else if (property.equals("NotedTypes")) {
// Should Paliano Vanguard be hardcoded here or part of the property? // Should Paliano Vanguard be hardcoded here or part of the property?
String types = sourceController.getDraftNotes().get("Paliano Vanguard"); String types = sourceController.getDraftNotes().get("Paliano Vanguard");

View File

@@ -116,12 +116,21 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> i
// can only draft one at a time, regardless of the requested quantity // can only draft one at a time, regardless of the requested quantity
PaperCard card = items.iterator().next().getKey(); PaperCard card = items.iterator().next().getKey();
if (boosterDraft.getHumanPlayer().shouldSkipThisPick()) {
System.out.println(card + " not drafted because we're skipping this pick");
showPackToDraft();
return;
}
// Verify if card is in the activate pack? // Verify if card is in the activate pack?
this.getDeckManager().addItem(card, 1); this.getDeckManager().addItem(card, 1);
// get next booster pack // get next booster pack if we aren't picking again from this pack
this.boosterDraft.setChoice(card); this.boosterDraft.setChoice(card);
showPackToDraft();
}
protected void showPackToDraft() {
boolean nextChoice = this.boosterDraft.hasNextChoice(); boolean nextChoice = this.boosterDraft.hasNextChoice();
ItemPool<PaperCard> pool = null; ItemPool<PaperCard> pool = null;
if (nextChoice) { if (nextChoice) {

View File

@@ -58,10 +58,15 @@ public class BoosterDraftTest implements IBoosterDraft {
return result; return result;
} }
/** {@inheritDoc} */ /**
* {@inheritDoc}
*
* @return
*/
@Override @Override
public void setChoice(final PaperCard c) { public boolean setChoice(final PaperCard c) {
System.out.println(c.getName()); System.out.println(c.getName());
return false;
} }
@Override @Override

View File

@@ -0,0 +1,7 @@
Name:Agent of Acquisitions
ManaCost:2
Types:Artifact Creature Construct
PT:2/1
Draft:Draft CARDNAME face up.
Draft:Instead of drafting a card from a booster pack, you may draft each card in that booster pack, one at a time. If you do, turn CARDNAME face down and you cant draft cards for the rest of this draft round. (You may look at booster packs passed to you.)
Oracle:Draft Agent of Acquisitions face up.\nInstead of drafting a card from a booster pack, you may draft each card in that booster pack, one at a time. If you do, turn Agent of Acquisitions face down and you cant draft cards for the rest of this draft round. (You may look at booster packs passed to you.)

View File

@@ -0,0 +1,7 @@
Name:Cogwork Librarian
ManaCost:4
Types:Artifact Creature Construct
PT:3/3
Draft:Draft CARDNAME face up.
Draft:As you draft a card, you may draft an additional card from that booster pack. If you do, put CARDNAME into that booster pack.
Oracle:Draft Cogwork Librarian face up.\nAs you draft a card, you may draft an additional card from that booster pack. If you do, put Cogwork Librarian into that booster pack.

View File

@@ -0,0 +1,7 @@
Name:Leovold's Operative
ManaCost:2 G
Types:Creature Elf Rogue
PT:3/2
Draft:Draft CARDNAME face up.
Draft:As you draft a card, you may draft an additional card from that booster pack. If you do, turn CARDNAME face down, then pass the next booster pack without drafting a card from it. (You may look at that booster pack.)
Oracle:Draft Leovolds Operative face up.\n\nAs you draft a card, you may draft an additional card from that booster pack. If you do, turn Leovolds Operative face down, then pass the next booster pack without drafting a card from it. (You may look at that booster pack.)

View File

@@ -0,0 +1,10 @@
Name:Spire Phantasm
ManaCost:2 U U
Types:Creature Gargoyle Illusion
PT:3/2
Draft:Reveal CARDNAME as you draft it.
Draft:The next time a player drafts a card from this booster pack, guess that cards name. Then that player reveals the drafted card.
K:Flying
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self+NotedGuessPhantasm | Execute$ DrawACard | TriggerDescription$ When CARDNAME enters the battlefield, if you guessed correctly for a card named Spire Phantasm, draw a card.
SVar:DrawACard:DB$ Draw | Amount$ 1
Oracle:Reveal Spire Phantasm as you draft it. The next time a player drafts a card from this booster pack, guess that cards name. Then that player reveals the drafted card.\nFlying\nWhen Spire Phantasm enters the battlefield, if you guessed correctly for a card named Spire Phantasm, draw a card.

View File

@@ -248,6 +248,7 @@ Hold the Perimeter
Hymn of the Wilds Hymn of the Wilds
Illusionary Informant Illusionary Informant
Incendiary Dissent Incendiary Dissent
Leovold's Operative
Natural Unity Natural Unity
Noble Banneret Noble Banneret
Paliano Vanguard Paliano Vanguard

View File

@@ -221,31 +221,31 @@ ScryfallCode=CNS
210 R Reflecting Pool @Fred Fields 210 R Reflecting Pool @Fred Fields
[Draft Matters] [Draft Matters]
#1 Advantageous Proclamation|CNS 1 Advantageous Proclamation|CNS
1 Aether Searcher|CNS 1 Aether Searcher|CNS
#1 Agent of Acquisitions|CNS 1 Agent of Acquisitions|CNS
#1 Backup Plan|CNS #1 Backup Plan|CNS
1 Brago's Favor|CNS 1 Brago's Favor|CNS
#1 Canal Dredger|CNS #1 Canal Dredger|CNS
1 Cogwork Grinder|CNS 1 Cogwork Grinder|CNS
#1 Cogwork Librarian|CNS 1 Cogwork Librarian|CNS
1 Cogwork Spy|CNS 1 Cogwork Spy|CNS
1 Cogwork Tracker|CNS 1 Cogwork Tracker|CNS
#1 Deal Broker|CNS #1 Deal Broker|CNS
#1 Double Stroke|CNS 1 Double Stroke|CNS
1 Immediate Action|CNS 1 Immediate Action|CNS
#1 Iterative Analysis|CNS 1 Iterative Analysis|CNS
#1 Lore Seeker|CNS #1 Lore Seeker|CNS
1 Lurking Automaton|CNS 1 Lurking Automaton|CNS
1 Muzzio's Preparations|CNS 1 Muzzio's Preparations|CNS
1 Paliano, the High City|CNS 1 Paliano, the High City|CNS
#1 Power Play|CNS 1 Power Play|CNS
1 Secret Summoning|CNS 1 Secret Summoning|CNS
1 Secrets of Paradise|CNS 1 Secrets of Paradise|CNS
#1 Sentinel Dispatch|CNS 1 Sentinel Dispatch|CNS
#1 Unexpected Potential|CNS 1 Unexpected Potential|CNS
1 Whispergear Sneak|CNS 1 Whispergear Sneak|CNS
#1 Worldknit|CNS 1 Worldknit|CNS
[tokens] [tokens]
w_1_1_spirit_flying w_1_1_spirit_flying

View File

@@ -50,6 +50,7 @@ import java.util.*;
*/ */
public class BoosterDraft implements IBoosterDraft { public class BoosterDraft implements IBoosterDraft {
private static int nextId = 0;
private static final int N_PLAYERS = 8; private static final int N_PLAYERS = 8;
public static final String FILE_EXT = ".draft"; public static final String FILE_EXT = ".draft";
private final List<LimitedPlayer> players = new ArrayList<>(); private final List<LimitedPlayer> players = new ArrayList<>();
@@ -371,9 +372,11 @@ public class BoosterDraft implements IBoosterDraft {
} }
public void initializeBoosters() { public void initializeBoosters() {
for (Supplier<List<PaperCard>> boosterRound : this.product) { for (Supplier<List<PaperCard>> boosterRound : this.product) {
for (int i = 0; i < N_PLAYERS; i++) { for (int i = 0; i < N_PLAYERS; i++) {
this.players.get(i).receiveUnopenedPack(boosterRound.get()); DraftPack pack = new DraftPack(boosterRound.get(), nextId++);
this.players.get(i).receiveUnopenedPack(pack);
} }
} }
startRound(); startRound();
@@ -437,8 +440,10 @@ public class BoosterDraft implements IBoosterDraft {
adjust = 0; adjust = 0;
} }
// Do any players have a Canal Dredger?
for (int i = 0; i < N_PLAYERS; i++) { for (int i = 0; i < N_PLAYERS; i++) {
List<PaperCard> passingPack = this.players.get(i).passPack(); DraftPack passingPack = this.players.get(i).passPack();
if (passingPack == null) if (passingPack == null)
continue; continue;
@@ -463,7 +468,17 @@ public class BoosterDraft implements IBoosterDraft {
for (int i = 1; i < N_PLAYERS; i++) { for (int i = 1; i < N_PLAYERS; i++) {
LimitedPlayer pl = this.players.get(i); LimitedPlayer pl = this.players.get(i);
// TODO Agent of Acquisitions activation to loop the entire pack? // TODO Agent of Acquisitions activation to loop the entire pack?
pl.draftCard(pl.chooseCard());
if (pl.shouldSkipThisPick()) {
continue;
}
// Computer player has an empty pack or is passing the pack
Boolean passPack;
do {
// THe player holding onto the pack to draft an extra card... Do it now.
passPack = pl.draftCard(pl.chooseCard());
} while (passPack != null && !passPack);
} }
} }
@@ -473,6 +488,7 @@ public class BoosterDraft implements IBoosterDraft {
@Override @Override
public boolean isRoundOver() { public boolean isRoundOver() {
// Really should check if all packs are empty, but this is a good enough approximation
return packsInDraft == 0; return packsInDraft == 0;
} }
@@ -483,10 +499,12 @@ public class BoosterDraft implements IBoosterDraft {
/** /**
* {@inheritDoc} * {@inheritDoc}
*
* @return
*/ */
@Override @Override
public void setChoice(final PaperCard c) { public boolean setChoice(final PaperCard c) {
final List<PaperCard> thisBooster = this.localPlayer.nextChoice(); final DraftPack thisBooster = this.localPlayer.nextChoice();
if (!thisBooster.contains(c)) { if (!thisBooster.contains(c)) {
throw new RuntimeException("BoosterDraft : setChoice() error - card not found - " + c throw new RuntimeException("BoosterDraft : setChoice() error - card not found - " + c
@@ -495,12 +513,17 @@ public class BoosterDraft implements IBoosterDraft {
recordDraftPick(thisBooster, c); recordDraftPick(thisBooster, c);
// TODO Agent of Acquisitions activation to loop the entire pack? boolean passPack = this.localPlayer.draftCard(c);
if (passPack) {
this.localPlayer.draftCard(c); // Leovolds Operative and Cogwork Librarian get to draft an extra card.. How do we do that?
this.currentBoosterPick++;
this.passPacks(); this.passPacks();
} }
this.currentBoosterPick++;
// Return whether or not we passed, but that the UI always needs to refresh
// But returning might be useful for testing or other things?
return passPack;
}
private static String choosePackByPack(final List<String> setz, int packs) { private static String choosePackByPack(final List<String> setz, int packs) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();

View File

@@ -3,7 +3,6 @@ package forge.gamemodes.limited;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.DeckHints; import forge.card.DeckHints;
import forge.card.MagicColor; import forge.card.MagicColor;
@@ -114,6 +113,22 @@ public class CardRanker {
return cardScores; return cardScores;
} }
public static List<PaperCard> getOrderedRawScores(List<PaperCard> cards) {
List<Pair<Double, PaperCard>> cardScores = Lists.newArrayList();
for(PaperCard card : cards) {
cardScores.add(Pair.of(getRawScore(card), card));
}
cardScores.sort(Collections.reverseOrder(new CardRankingComparator()));
List<PaperCard> rankedCards = new ArrayList<>(cardScores.size());
for (Pair<Double, PaperCard> pair : cardScores) {
rankedCards.add(pair.getValue());
}
return rankedCards;
}
public static double getRawScore(PaperCard card) { public static double getRawScore(PaperCard card) {
Double rawScore; Double rawScore;
if (MagicColor.Constant.BASIC_LANDS.contains(card.getName())) { if (MagicColor.Constant.BASIC_LANDS.contains(card.getName())) {

View File

@@ -0,0 +1,49 @@
package forge.gamemodes.limited;
import com.google.common.collect.ForwardingList;
import forge.item.PaperCard;
import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
public class DraftPack extends ForwardingList<PaperCard> {
private final List<PaperCard> cards;
private final int id;
private LimitedPlayer passedFrom;
private Map.Entry<LimitedPlayer, PaperCard> awaitingGuess;
public DraftPack(List<PaperCard> cards, int id) {
this.cards = cards;
this.id = id;
}
public int getId() {
return id;
}
public LimitedPlayer getPassedFrom() {
return passedFrom;
}
public void setPassedFrom(LimitedPlayer passedFrom) {
this.passedFrom = passedFrom;
}
public void setAwaitingGuess(LimitedPlayer player, PaperCard card) {
this.awaitingGuess = new AbstractMap.SimpleEntry<>(player, card);
}
public Map.Entry<LimitedPlayer, PaperCard> getAwaitingGuess() {
return awaitingGuess;
}
public void resetAwaitingGuess() {
this.awaitingGuess = null;
}
@Override
protected List<PaperCard> delegate() {
return cards;
}
}

View File

@@ -34,7 +34,7 @@ public interface IBoosterDraft {
int getRound(); int getRound();
CardPool nextChoice(); CardPool nextChoice();
void setChoice(PaperCard c); boolean setChoice(PaperCard c);
boolean hasNextChoice(); boolean hasNextChoice();
boolean isRoundOver(); boolean isRoundOver();
Deck[] getDecks(); // size 7, all the computers decks Deck[] getDecks(); // size 7, all the computers decks
@@ -49,4 +49,6 @@ public interface IBoosterDraft {
IDraftLog getDraftLog(); IDraftLog getDraftLog();
LimitedPlayer getNeighbor(LimitedPlayer p, boolean left); LimitedPlayer getNeighbor(LimitedPlayer p, boolean left);
LimitedPlayer getPlayer(int i); LimitedPlayer getPlayer(int i);
} }

View File

@@ -21,15 +21,15 @@ public class LimitedPlayer {
protected Deck deck; protected Deck deck;
protected PaperCard lastPick; protected PaperCard lastPick;
protected Queue<List<PaperCard>> packQueue; protected Queue<DraftPack> packQueue;
protected Queue<List<PaperCard>> unopenedPacks; protected Queue<DraftPack> unopenedPacks;
protected List<PaperCard> removedFromCardPool = new ArrayList<>(); protected List<PaperCard> removedFromCardPool = new ArrayList<>();
private static final int CantDraftThisRound = 1; private static final int AgentAcquisitionsCanDraftAll = 1;
private static final int SpyNextCardDrafted = 1 << 1; private static final int AgentAcquisitionsIsDraftingAll = 1 << 1;
private static final int ReceiveLastCard = 1 << 2; private static final int AgentAcquisitionsSkipDraftRound = 1 << 2;
private static final int CanRemoveAfterDraft = 1 << 3; private static final int CogworkLibrarianExtraDraft = 1 << 3;
private static final int CanTradeAfterDraft = 1 << 4; private static final int CogworkLibrarianReturnLibrarian = 1 << 4;
private static final int AnimusRemoveFromPool = 1 << 5; private static final int AnimusRemoveFromPool = 1 << 5;
private static final int NobleBanneretActive = 1 << 6; private static final int NobleBanneretActive = 1 << 6;
private static final int PalianoVanguardActive = 1 << 7; private static final int PalianoVanguardActive = 1 << 7;
@@ -37,6 +37,10 @@ public class LimitedPlayer {
private static final int SearcherNoteNext = 1 << 9; private static final int SearcherNoteNext = 1 << 9;
private static final int WhispergearBoosterPeek = 1 << 10; private static final int WhispergearBoosterPeek = 1 << 10;
private static final int IllusionaryInformantPeek = 1 << 11; private static final int IllusionaryInformantPeek = 1 << 11;
private static final int LeovoldsOperativeCanExtraDraft = 1 << 12;
private static final int LeovoldsOperativeExtraDraft = 1 << 13;
private static final int LeovoldsOperativeSkipNext = 1 << 14;
private static final int SpyNextCardDrafted = 1 << 15;
private int playerFlags = 0; private int playerFlags = 0;
@@ -88,24 +92,25 @@ public class LimitedPlayer {
return null; return null;
} }
public boolean draftCard(PaperCard bestPick) { public Boolean draftCard(PaperCard bestPick) {
return draftCard(bestPick, DeckSection.Sideboard); return draftCard(bestPick, DeckSection.Sideboard);
} }
public boolean draftCard(PaperCard bestPick, DeckSection section) { public Boolean draftCard(PaperCard bestPick, DeckSection section) {
if (bestPick == null) { if (bestPick == null) {
return false; return null;
} }
List<PaperCard> chooseFrom = packQueue.peek(); DraftPack chooseFrom = packQueue.peek();
if (chooseFrom == null) { if (chooseFrom == null) {
return false; return null;
} }
boolean removedFromPool = false; boolean removedFromPool = false;
boolean alreadyRevealed = false; boolean alreadyRevealed = false;
boolean passPack = true;
chooseFrom.remove(bestPick); chooseFrom.remove(bestPick);
lastPick = lastPick; lastPick = bestPick;
draftedThisRound++; draftedThisRound++;
@@ -134,9 +139,10 @@ public class LimitedPlayer {
recordRemoveFromDraft(bestPick, choice); recordRemoveFromDraft(bestPick, choice);
} }
LimitedPlayer fromPlayer = receivedFrom();
LimitedPlayer fromPlayer = chooseFrom.getPassedFrom();
// If the previous player has an active Cogwork Spy, show them this card // If the previous player has an active Cogwork Spy, show them this card
if ((fromPlayer.playerFlags & SpyNextCardDrafted) == SpyNextCardDrafted) { if (fromPlayer != null && (fromPlayer.playerFlags & SpyNextCardDrafted) == SpyNextCardDrafted) {
if (fromPlayer instanceof LimitedPlayerAI) { if (fromPlayer instanceof LimitedPlayerAI) {
// I'm honestly not sure what the AI would do by learning this information // I'm honestly not sure what the AI would do by learning this information
// But just log that a reveal "happened" // But just log that a reveal "happened"
@@ -169,9 +175,73 @@ public class LimitedPlayer {
} }
} }
if ((playerFlags & AgentAcquisitionsCanDraftAll) == AgentAcquisitionsCanDraftAll) {
if (handleAgentOfAcquisitions(chooseFrom, bestPick)) {
addLog(name() + " drafted the rest of the pack with Agent of Acquisitions");
playerFlags &= ~AgentAcquisitionsCanDraftAll;
playerFlags |= AgentAcquisitionsIsDraftingAll;
}
}
if ((playerFlags & AgentAcquisitionsIsDraftingAll) == AgentAcquisitionsIsDraftingAll) {
if (chooseFrom.isEmpty()) {
playerFlags &= ~AgentAcquisitionsIsDraftingAll;
playerFlags |= AgentAcquisitionsSkipDraftRound;
} else {
passPack = false;
}
}
if ((playerFlags & LeovoldsOperativeExtraDraft) == LeovoldsOperativeExtraDraft) {
if (handleLeovoldsOperative(chooseFrom, bestPick)) {
addLog(name() + " skipped their next pick with Leovold's Operative.");
playerFlags &= ~LeovoldsOperativeExtraDraft;
playerFlags |= LeovoldsOperativeSkipNext;
passPack = false;
}
}
if ((playerFlags & LeovoldsOperativeCanExtraDraft) == LeovoldsOperativeCanExtraDraft) {
if (handleLeovoldsOperative(chooseFrom, bestPick)) {
addLog(name() + " picking again with Leovold's Operative.");
playerFlags &= ~LeovoldsOperativeCanExtraDraft;
playerFlags |= LeovoldsOperativeExtraDraft;
passPack = false;
}
}
if ((playerFlags & CogworkLibrarianReturnLibrarian) == CogworkLibrarianReturnLibrarian) {
addLog(name() + " returned Cogwork Librarian to the pack.");
PaperCard librarian = deck.removeCardName("Cogwork Librarian");
// TODO The librarian needs to be removed from the UI
// We shouldn't get here unless we've drafted librarian so we should be able to find one in Deck
// If somehow we don't wellll.. we should remove the bitflag anyway
playerFlags &= ~CogworkLibrarianReturnLibrarian;
if (librarian != null) {
chooseFrom.add(librarian);
} else {
System.out.println("This shouldn't happen. We drafted a libarian but didn't remove it properly.");
}
}
if ((playerFlags & CogworkLibrarianExtraDraft) == CogworkLibrarianExtraDraft) {
if (handleCogworkLibrarian(chooseFrom, bestPick)) {
addLog(name() + " drafted an extra card with Cogwork Librarian.");
playerFlags &= ~CogworkLibrarianExtraDraft;
playerFlags |= CogworkLibrarianReturnLibrarian;
passPack = false;
}
}
if (chooseFrom.getAwaitingGuess() != null) {
comparePhantasmGuess(chooseFrom, bestPick);
}
if (removedFromPool) { if (removedFromPool) {
// Can we hide this from UI? // Can we hide this from UI?
return true; return passPack;
} }
CardPool pool = deck.getOrCreate(section); CardPool pool = deck.getOrCreate(section);
@@ -182,7 +252,7 @@ public class LimitedPlayer {
Iterable<String> draftActions = bestPick.getRules().getMainPart().getDraftActions(); Iterable<String> draftActions = bestPick.getRules().getMainPart().getDraftActions();
if (draftActions == null || !draftActions.iterator().hasNext()) { if (draftActions == null || !draftActions.iterator().hasNext()) {
return true; return passPack;
} }
// Draft Actions // Draft Actions
@@ -223,17 +293,17 @@ public class LimitedPlayer {
} }
else { else {
if (Iterables.contains(draftActions, "You may look at the next card drafted from this booster pack.")) { if (Iterables.contains(draftActions, "You may look at the next card drafted from this booster pack.")) {
// Cogwork Spy
playerFlags |= SpyNextCardDrafted; playerFlags |= SpyNextCardDrafted;
} } else if (fromPlayer != null && Iterables.contains(draftActions, "Note the player who passed CARDNAME to you.")) {
if (Iterables.contains(draftActions, "Note the player who passed CARDNAME to you.")) {
// Note who passed it 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? // 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()); List<String> note = noted.computeIfAbsent(bestPick.getName(), k -> Lists.newArrayList());
note.add(String.valueOf(fromPlayer.order)); note.add(String.valueOf(fromPlayer.order));
addLog(name() + " revealed " + bestPick.getName() + " and noted " + fromPlayer.name() + " passed it.");
} else if (Iterables.contains(draftActions, "Reveal the next card you draft and note its name.")) { } else if (Iterables.contains(draftActions, "Reveal the next card you draft and note its name.")) {
playerFlags |= SearcherNoteNext; playerFlags |= SearcherNoteNext;
} else if (Iterables.contains(draftActions, "The next time a player drafts a card from this booster pack, guess that cards name. Then that player reveals the drafted card.")) {
chooseFrom.setAwaitingGuess(this, handleSpirePhantasm(chooseFrom));
} }
addLog(name() + " revealed " + bestPick.getName() + " as " + name() + " drafted it."); addLog(name() + " revealed " + bestPick.getName() + " as " + name() + " drafted it.");
@@ -261,6 +331,12 @@ public class LimitedPlayer {
// Do we need to ask to use the Sneak immediately? // 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.")) { } 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; playerFlags |= IllusionaryInformantPeek;
} else if (Iterables.contains(draftActions, "As you draft a card, you may draft an additional card from that booster pack. If you do, put CARDNAME into that booster pack.")) {
playerFlags |= CogworkLibrarianExtraDraft;
} else if (Iterables.contains(draftActions, "As you draft a card, you may draft an additional card from that booster pack. If you do, turn CARDNAME face down, then pass the next booster pack without drafting a card from it. (You may look at that booster pack.)")) {
playerFlags |= LeovoldsOperativeExtraDraft;
} else if (Iterables.contains(draftActions, "Instead of drafting a card from a booster pack, you may draft each card in that booster pack, one at a time. If you do, turn CARDNAME face down and you cant draft cards for the rest of this draft round. (You may look at booster packs passed to you.)")) {
playerFlags |= AgentAcquisitionsCanDraftAll;
} }
} }
@@ -277,32 +353,44 @@ public class LimitedPlayer {
// Mobile doesnt have a draft log yet // Mobile doesnt have a draft log yet
} }
public List<PaperCard> nextChoice() { public DraftPack nextChoice() {
return packQueue.peek(); return packQueue.peek();
} }
public LimitedPlayer receivedFrom() {
return draft.getNeighbor(this, draft.getRound() % 2 == 0);
}
public void newPack() { public void newPack() {
currentPack = order; currentPack = order;
draftedThisRound = 0; draftedThisRound = 0;
packQueue.add(unopenedPacks.poll()); packQueue.add(unopenedPacks.poll());
playerFlags &= ~AgentAcquisitionsSkipDraftRound;
} }
public void adjustPackNumber(int adjust, int numPacks) { public void adjustPackNumber(int adjust, int numPacks) {
// I shouldn't need this since DraftPack has this info
currentPack = (currentPack + adjust + numPacks) % numPacks; currentPack = (currentPack + adjust + numPacks) % numPacks;
} }
public List<PaperCard> passPack() { public DraftPack passPack() {
return packQueue.poll(); DraftPack pack = packQueue.poll();
if (pack != null) {
pack.setPassedFrom(this);
}
return pack;
} }
public void receiveUnopenedPack(List<PaperCard> pack) { public boolean shouldSkipThisPick() {
boolean skipping = (playerFlags & AgentAcquisitionsSkipDraftRound) == AgentAcquisitionsSkipDraftRound || (playerFlags & LeovoldsOperativeSkipNext) == LeovoldsOperativeSkipNext;
if (skipping && (playerFlags & LeovoldsOperativeSkipNext) == LeovoldsOperativeSkipNext) {
playerFlags &= ~LeovoldsOperativeSkipNext;
}
return skipping;
}
public void receiveUnopenedPack(DraftPack pack) {
unopenedPacks.add(pack); unopenedPacks.add(pack);
} }
public void receiveOpenedPack(List<PaperCard> pack) { public void receiveOpenedPack(DraftPack pack) {
packQueue.add(pack); packQueue.add(pack);
} }
@@ -504,7 +592,7 @@ public class LimitedPlayer {
return true; return true;
} }
protected List<PaperCard> peekAtBoosterPack(int round, int playerNumber) { protected DraftPack peekAtBoosterPack(int round, int playerNumber) {
if (draft.getRound() > round) { if (draft.getRound() > round) {
// There aren't any unopened packs from earlier rounds // There aren't any unopened packs from earlier rounds
return null; return null;
@@ -541,11 +629,51 @@ public class LimitedPlayer {
return true; return true;
} }
public PaperCard handleSpirePhantasm(DraftPack chooseFrom) {
if (chooseFrom.isEmpty()) {
return null;
}
return SGuiChoose.one("Guess the next card drafted from this pack", chooseFrom);
}
public boolean handleLeovoldsOperative(DraftPack pack, PaperCard drafted) {
if (Objects.equals(SGuiChoose.one("Draft an extra pick with Leovold's Operative?", Lists.newArrayList("Yes", "No")), "No")) {
return false;
}
playerFlags |= LeovoldsOperativeExtraDraft;
return true;
}
public boolean handleCogworkLibrarian(DraftPack pack, PaperCard drafted) {
return !Objects.equals(SGuiChoose.one("Draft an extra pick with Cogwork Librarian?", Lists.newArrayList("Yes", "No")), "No");
}
public boolean handleAgentOfAcquisitions(DraftPack pack, PaperCard drafted) {
return !Objects.equals(SGuiChoose.one("Draft the rest of the pack with Agent of Acquisitions?", Lists.newArrayList("Yes", "No")), "No");
}
public void comparePhantasmGuess(DraftPack pack, PaperCard drafted) {
LimitedPlayer guesser = pack.getAwaitingGuess().getKey();
PaperCard guess = pack.getAwaitingGuess().getValue();
addLog(name() + " reveals " + drafted.getName() + " from " + guesser.name() + "'s guess of " + guess.getName() + " with Spire Phantasm.");
if (guess.equals(drafted)) {
addLog(guesser.name() + " correctly guessed " + guess.getName() + " with Spire Phantasm.");
guesser.getDraftNotes().computeIfAbsent("Spire Phantasm", k -> Lists.newArrayList()).add(guess.getName());
} else {
addLog(guesser.name() + " incorrectly guessed " + guess.getName() + " with Spire Phantasm.");
}
pack.resetAwaitingGuess();
}
/* /*
public void addSingleBoosterPack(boolean random) { public void addSingleBoosterPack(boolean random) {
// TODO Lore Seeker // TODO Lore Seeker
// Generate booster pack then, insert it "before" the pack we're currently drafting from // Generate booster pack then, insert it "before" the pack we're currently drafting from
} }
*/ */
} }

View File

@@ -12,6 +12,9 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import static forge.gamemodes.limited.CardRanker.getOrderedRawScores;
import static forge.gamemodes.limited.CardRanker.rankCardsInPack;
public class LimitedPlayerAI extends LimitedPlayer { public class LimitedPlayerAI extends LimitedPlayer {
protected DeckColors deckCols; protected DeckColors deckCols;
@@ -26,7 +29,7 @@ public class LimitedPlayerAI extends LimitedPlayer {
return null; return null;
} }
List<PaperCard> chooseFrom = packQueue.peek(); DraftPack chooseFrom = packQueue.peek();
if (chooseFrom.isEmpty()) { if (chooseFrom.isEmpty()) {
return null; return null;
} }
@@ -38,11 +41,10 @@ public class LimitedPlayerAI extends LimitedPlayer {
// TODO Archdemon of Paliano random draft while active // TODO Archdemon of Paliano random draft while active
final ColorSet chosenColors = deckCols.getChosenColors(); final ColorSet chosenColors = deckCols.getChosenColors();
final boolean canAddMoreColors = deckCols.canChoseMoreColors(); final boolean canAddMoreColors = deckCols.canChoseMoreColors();
List<PaperCard> rankedCards = CardRanker.rankCardsInPack(chooseFrom, pool.toFlatList(), chosenColors, canAddMoreColors); List<PaperCard> rankedCards = rankCardsInPack(chooseFrom, pool.toFlatList(), chosenColors, canAddMoreColors);
PaperCard bestPick = rankedCards.get(0); PaperCard bestPick = rankedCards.get(0);
if (canAddMoreColors) { if (canAddMoreColors) {
@@ -177,4 +179,47 @@ public class LimitedPlayerAI extends LimitedPlayer {
//peekAt.getLastPick(); //peekAt.getLastPick();
return true; return true;
} }
@Override
public PaperCard handleSpirePhantasm(DraftPack chooseFrom) {
if (chooseFrom.isEmpty()) {
return null;
}
// Choose the card with the highest rank left
return getOrderedRawScores(chooseFrom).get(0);
}
@Override
public boolean handleLeovoldsOperative(DraftPack pack, PaperCard drafted) {
// Whats the score of the thing I just drafted?
// Whats the next card I would draft?
if (currentPack == 3) {
return true;
}
return draftedThisRound < 3;
}
@Override
public boolean handleAgentOfAcquisitions(DraftPack pack, PaperCard drafted) {
// Whats the score of the thing I just drafted?
// Whats the total score of the rest of the pack?
// How many of these cards would actually make my deck?
if (currentPack == 3) {
return true;
}
return draftedThisRound > 2 && draftedThisRound < 6;
}
@Override
public boolean handleCogworkLibrarian(DraftPack pack, PaperCard drafted) {
if (currentPack == 3) {
return true;
}
return draftedThisRound < 3;
}
} }