Add remaining Conspiracy cards

- Archdemon of Paliano
- Canal Dredger
- Deal Broker
- Lore Seeker
This commit is contained in:
Chris H
2024-06-22 10:18:53 -04:00
parent b9829eef92
commit 33f34231f4
14 changed files with 348 additions and 47 deletions

View File

@@ -193,6 +193,8 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
sortableName = TextUtil.toSortableName(CardTranslation.getTranslatedName(rules0.getName())); sortableName = TextUtil.toSortableName(CardTranslation.getTranslatedName(rules0.getName()));
} }
public static PaperCard FAKE_CARD = new PaperCard(CardRules.getUnsupportedCardNamed("Fake Card"), "Fake Edition", CardRarity.Common);
// Want this class to be a key for HashTable // Want this class to be a key for HashTable
@Override @Override
public boolean equals(final Object obj) { public boolean equals(final Object obj) {

View File

@@ -122,6 +122,10 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> i
return; return;
} }
if (boosterDraft.getHumanPlayer().hasArchdemonCurse()) {
card = boosterDraft.getHumanPlayer().pickFromArchdemonCurse(boosterDraft.getHumanPlayer().nextChoice());
}
// 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);
@@ -144,6 +148,7 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> i
else { else {
// TODO Deal Broker // TODO Deal Broker
// Offer trades before saving // Offer trades before saving
boosterDraft.postDraftActions();
this.saveDraft(); this.saveDraft();
} }
@@ -178,9 +183,25 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> i
int packNumber = ((BoosterDraft) boosterDraft).getCurrentBoosterIndex() + 1; int packNumber = ((BoosterDraft) boosterDraft).getCurrentBoosterIndex() + 1;
this.getCatalogManager().setCaption(localizer.getMessage("lblPackNCards", String.valueOf(packNumber))); this.getCatalogManager().setCaption(localizer.getMessage("lblPackNCards", String.valueOf(packNumber)));
int count = list.countAll();
if (boosterDraft.getHumanPlayer().hasArchdemonCurse()) {
// Only show facedown cards with no information
this.getCatalogManager().setPool(generateFakePaperCards(count));
} else {
this.getCatalogManager().setPool(list); this.getCatalogManager().setPool(list);
}
} // showChoices() } // showChoices()
private ItemPool<PaperCard> generateFakePaperCards(int count) {
ItemPool<PaperCard> pool = new ItemPool<>(PaperCard.class);
for (int i = 0; i < count; i++) {
pool.add(PaperCard.FAKE_CARD);
}
return pool;
}
/** /**
* <p> * <p>
* getPlayersDeck. * getPlayersDeck.

View File

@@ -1,8 +1,10 @@
package forge; package forge;
import forge.card.CardEdition;
import forge.deck.CardPool; import forge.deck.CardPool;
import forge.deck.Deck; import forge.deck.Deck;
import forge.game.card.Card; import forge.game.card.Card;
import forge.gamemodes.limited.DraftPack;
import forge.gamemodes.limited.IBoosterDraft; import forge.gamemodes.limited.IBoosterDraft;
import forge.gamemodes.limited.IDraftLog; import forge.gamemodes.limited.IDraftLog;
import forge.gamemodes.limited.LimitedPlayer; import forge.gamemodes.limited.LimitedPlayer;
@@ -79,6 +81,11 @@ public class BoosterDraftTest implements IBoosterDraft {
return hasNextChoice(); return hasNextChoice();
} }
@Override
public DraftPack addBooster(CardEdition edition) {
return null;
}
public List<Card> getChosenCards() { public List<Card> getChosenCards() {
return null; return null;
} }
@@ -111,4 +118,7 @@ public class BoosterDraftTest implements IBoosterDraft {
public LimitedPlayer getPlayer(int i) { public LimitedPlayer getPlayer(int i) {
return null; return null;
} }
@Override
public void postDraftActions() {}
} }

View File

@@ -0,0 +1,8 @@
Name:Archdemon of Paliano
ManaCost:2 B B
Types:Creature Demon
PT:5/4
Draft:Draft CARDNAME face up.
Draft:As long as CARDNAME is face up during the draft, you cant look at booster packs and must draft cards at random. After you draft three cards this way, turn CARDNAME face down. (You may look at cards as you draft them.)
K:Flying
Oracle:Draft Archdemon of Paliano face up.\n\nAs long as Archdemon of Paliano is face up during the draft, you cant look at booster packs and must draft cards at random. After you draft three cards this way, turn Archdemon of Paliano face down. (You may look at cards as you draft them.)\nFlying

View File

@@ -0,0 +1,8 @@
Name:Canal Dredger
ManaCost:4
Types:Artifact Creature Construct
PT:1/5
Draft:Draft Canal Dredger face up.
Draft:Each player passes the last card from each booster pack to a player who drafted a card named CARDNAME.
A:AB$ ChangeZone | Cost$ T | ValidTgts$ Card.YouOwn | TgtPrompt$ Select target card in your graveyard | Origin$ Graveyard | Destination$ Library | LibraryPosition$ -1 | SpellDescription$ Put target card from your graveyard on the bottom of your library.
Oracle:Draft Canal Dredger face up.\nEach player passes the last card from each booster pack to a player who drafted a card named Canal Dredger.\n{T}: Put target card from your graveyard on the bottom of your library.

View File

@@ -0,0 +1,10 @@
Name:Deal Broker
ManaCost:3
PT:2/3
Types:Artifact Creature Construct
Draft:Draft CARDNAME face up.
Draft:Immediately after the draft, you may reveal a card in your card pool. Each other player may offer you one card in their card pool in exchange. You may accept any one offer.
A:AB$ Draw | Cost$ T | Defined$ You | NumCards$ 1 | SubAbility$ Discard | SpellDescription$ Draw a card, then discard a card.
SVar:Discard:DB$ Discard | Defined$ You | NumCards$ 1 | Mode$ TgtChoose
Oracle:Draft Deal Broker face up.\nImmediately after the draft, you may reveal a card in your card pool. Each other player may offer you one card in their card pool in exchange. You may accept any one offer.\n{T}: Draw a card, then discard a card.

View File

@@ -0,0 +1,7 @@
Name:Lore Seeker
ManaCost:2
PT:2/2
Types:Artifact Creature Construct
Draft:Reveal CARDNAME as you draft it.
Draft:After you draft CARDNAME, you may add a booster pack to the draft. (Your next pick is from that booster pack. Pass it to the next player and its drafted this draft round.)
Oracle:Reveal Lore Seeker as you draft it. After you draft Lore Seeker, you may add a booster pack to the draft. (Your next pick is from that booster pack. Pass it to the next player and its drafted this draft round.)

View File

@@ -238,6 +238,7 @@ ScryfallCode=CN2
[Draft Matters] [Draft Matters]
Adriana's Valor Adriana's Valor
Animus of Predation Animus of Predation
Archdemon of Paliano
Assemble the Rank and Vile Assemble the Rank and Vile
Custodi Peacekeeper Custodi Peacekeeper
Echoing Boon Echoing Boon
@@ -254,6 +255,7 @@ Noble Banneret
Paliano Vanguard Paliano Vanguard
Pyretic Hunter Pyretic Hunter
Regicide Regicide
Spire Phantasm
Sovereign's Realm Sovereign's Realm
Summoner's Bond Summoner's Bond
Weight Advantage Weight Advantage

View File

@@ -226,16 +226,16 @@ ScryfallCode=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

View File

@@ -50,7 +50,7 @@ import java.util.*;
*/ */
public class BoosterDraft implements IBoosterDraft { public class BoosterDraft implements IBoosterDraft {
private static int nextId = 0; private 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<>();
@@ -271,6 +271,11 @@ public class BoosterDraft implements IBoosterDraft {
} }
} }
public DraftPack addBooster(CardEdition edition) {
final IUnOpenedProduct product = new UnOpenedProduct(FModel.getMagicDb().getBoosters().get(edition.getCode()));
return new DraftPack(product.get(), nextId++);
}
@Override @Override
public boolean isPileDraft() { public boolean isPileDraft() {
return false; return false;
@@ -441,25 +446,52 @@ public class BoosterDraft implements IBoosterDraft {
} }
// Do any players have a Canal Dredger? // Do any players have a Canal Dredger?
List<LimitedPlayer> dredgers = new ArrayList<>();
for (LimitedPlayer pl : this.players) {
if (pl.hasCanalDredger()) {
dredgers.add(pl);
}
}
for (int i = 0; i < N_PLAYERS; i++) { for (int i = 0; i < N_PLAYERS; i++) {
DraftPack passingPack = this.players.get(i).passPack(); LimitedPlayer pl = this.players.get(i);
DraftPack passingPack = pl.passPack();
if (passingPack == null) if (passingPack == null)
continue; continue;
if (!passingPack.isEmpty()) { LimitedPlayer passToPlayer = null;
if (passingPack.size() == 1) { if (passingPack.isEmpty()) {
// TODO Canal Dredger for passing a pack with a single card in it
}
int passTo = (i + adjust + N_PLAYERS) % N_PLAYERS;
this.players.get(passTo).receiveOpenedPack(passingPack);
this.players.get(passTo).adjustPackNumber(adjust, packsInDraft);
} else {
packsInDraft--; packsInDraft--;
continue;
} }
if (passingPack.size() == 1) {
if (dredgers.size() == 1) {
passToPlayer = dredgers.get(0);
} else if (dredgers.size() > 1) {
// Multiple dredgers, so we need to choose one to pass to
if (dredgers.contains(pl)) {
// If the current player has a Canal Dredger, they should pass to themselves
passToPlayer = pl;
} else if (pl instanceof LimitedPlayerAI) {
// Maybe the AI could have more knowledge about the other players.
// Like don't pass to players that have revealed certain cards or colors
// But random is probably fine for now
Collections.shuffle(dredgers);
passToPlayer = dredgers.get(0);
} else {
// Human player, so we need to ask them
passToPlayer = SGuiChoose.one("Which player with Canal Dredger should we pass the last card to?", dredgers);
}
}
}
if (passToPlayer == null) {
passToPlayer = this.players.get((i + adjust + N_PLAYERS) % N_PLAYERS);
}
passToPlayer.receiveOpenedPack(passingPack);
} }
} }
@@ -467,8 +499,6 @@ public class BoosterDraft implements IBoosterDraft {
// Loop through players 1-7 to draft their current pack // Loop through players 1-7 to draft their current pack
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?
if (pl.shouldSkipThisPick()) { if (pl.shouldSkipThisPick()) {
continue; continue;
} }
@@ -525,6 +555,22 @@ public class BoosterDraft implements IBoosterDraft {
return passPack; return passPack;
} }
public void postDraftActions() {
List<LimitedPlayer> brokers = new ArrayList<>();
for (LimitedPlayer pl : this.players) {
if (pl.hasBrokers()) {
brokers.add(pl);
}
}
Collections.shuffle(brokers);
for(LimitedPlayer pl : brokers) {
pl.activateBrokers(this.players);
}
}
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

@@ -66,7 +66,7 @@ public class CardRanker {
return sortAndCreateList(cardScores); return sortAndCreateList(cardScores);
} }
private static List<Pair<Double, PaperCard>> getScores(Iterable<PaperCard> cards) { public static List<Pair<Double, PaperCard>> getScores(Iterable<PaperCard> cards) {
List<Pair<Double, PaperCard>> cardScores = new ArrayList<>(); List<Pair<Double, PaperCard>> cardScores = new ArrayList<>();
List<PaperCard> cache = Lists.newArrayList(cards); List<PaperCard> cache = Lists.newArrayList(cards);

View File

@@ -31,12 +31,12 @@ import forge.item.PaperCard;
* @version $Id$ * @version $Id$
*/ */
public interface IBoosterDraft { public interface IBoosterDraft {
int getRound(); int getRound();
CardPool nextChoice(); CardPool nextChoice();
boolean setChoice(PaperCard c); boolean setChoice(PaperCard c);
boolean hasNextChoice(); boolean hasNextChoice();
boolean isRoundOver(); boolean isRoundOver();
DraftPack addBooster(CardEdition edition);
Deck[] getDecks(); // size 7, all the computers decks Deck[] getDecks(); // size 7, all the computers decks
LimitedPlayer[] getOpposingPlayers(); // size 7, all the computers LimitedPlayer[] getOpposingPlayers(); // size 7, all the computers
LimitedPlayer getHumanPlayer(); LimitedPlayer getHumanPlayer();
@@ -47,8 +47,7 @@ public interface IBoosterDraft {
void setLogEntry(IDraftLog draftingProcess); void setLogEntry(IDraftLog draftingProcess);
IDraftLog getDraftLog(); IDraftLog getDraftLog();
void postDraftActions();
LimitedPlayer getNeighbor(LimitedPlayer p, boolean left); LimitedPlayer getNeighbor(LimitedPlayer p, boolean left);
LimitedPlayer getPlayer(int i); LimitedPlayer getPlayer(int i);
} }

View File

@@ -3,12 +3,14 @@ package forge.gamemodes.limited;
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 com.google.common.collect.Sets; import com.google.common.collect.Sets;
import forge.card.CardEdition;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.deck.CardPool; import forge.deck.CardPool;
import forge.deck.Deck; import forge.deck.Deck;
import forge.deck.DeckSection; import forge.deck.DeckSection;
import forge.gui.util.SGuiChoose; import forge.gui.util.SGuiChoose;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.model.FModel;
import forge.util.TextUtil; import forge.util.TextUtil;
import java.util.*; import java.util.*;
@@ -25,6 +27,9 @@ public class LimitedPlayer {
protected Queue<DraftPack> unopenedPacks; protected Queue<DraftPack> unopenedPacks;
protected List<PaperCard> removedFromCardPool = new ArrayList<>(); protected List<PaperCard> removedFromCardPool = new ArrayList<>();
protected List<Integer> archdemonFavors;
protected int dealBrokers = 0;
private static final int AgentAcquisitionsCanDraftAll = 1; private static final int AgentAcquisitionsCanDraftAll = 1;
private static final int AgentAcquisitionsIsDraftingAll = 1 << 1; private static final int AgentAcquisitionsIsDraftingAll = 1 << 1;
private static final int AgentAcquisitionsSkipDraftRound = 1 << 2; private static final int AgentAcquisitionsSkipDraftRound = 1 << 2;
@@ -41,6 +46,8 @@ public class LimitedPlayer {
private static final int LeovoldsOperativeExtraDraft = 1 << 13; private static final int LeovoldsOperativeExtraDraft = 1 << 13;
private static final int LeovoldsOperativeSkipNext = 1 << 14; private static final int LeovoldsOperativeSkipNext = 1 << 14;
private static final int SpyNextCardDrafted = 1 << 15; private static final int SpyNextCardDrafted = 1 << 15;
private static final int CanalDredgerLastPick = 1 << 16;
private static final int ArchdemonOfPalianoCurse = 1 << 17;
private int playerFlags = 0; private int playerFlags = 0;
@@ -57,6 +64,7 @@ public class LimitedPlayer {
packQueue = new LinkedList<>(); packQueue = new LinkedList<>();
unopenedPacks = new LinkedList<>(); unopenedPacks = new LinkedList<>();
archdemonFavors = new ArrayList<>();
this.draft = draft; this.draft = draft;
} }
@@ -87,8 +95,6 @@ public class LimitedPlayer {
public PaperCard chooseCard() { public PaperCard chooseCard() {
// A non-AI LimitedPlayer chooses cards via the UI instead of this function // A non-AI LimitedPlayer chooses cards via the UI instead of this function
// TODO Archdemon of Paliano random draft while active
return null; return null;
} }
@@ -295,8 +301,6 @@ public class LimitedPlayer {
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.")) {
playerFlags |= SpyNextCardDrafted; playerFlags |= SpyNextCardDrafted;
} else if (fromPlayer != null && Iterables.contains(draftActions, "Note the player who passed CARDNAME to you.")) { } else if (fromPlayer != null && 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()); 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."); addLog(name() + " revealed " + bestPick.getName() + " and noted " + fromPlayer.name() + " passed it.");
@@ -304,6 +308,8 @@ public class LimitedPlayer {
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.")) { } 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)); chooseFrom.setAwaitingGuess(this, handleSpirePhantasm(chooseFrom));
} else if (Iterables.contains(draftActions, "After you draft CARDNAME, you may add a booster pack to the draft. (Your next pick is from that booster pack. Pass it to the next player and its drafted this draft round.)")) {
addSingleBoosterPack();
} }
addLog(name() + " revealed " + bestPick.getName() + " as " + name() + " drafted it."); addLog(name() + " revealed " + bestPick.getName() + " as " + name() + " drafted it.");
@@ -337,12 +343,16 @@ public class LimitedPlayer {
playerFlags |= LeovoldsOperativeExtraDraft; 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.)")) { } 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; playerFlags |= AgentAcquisitionsCanDraftAll;
} else if (Iterables.contains(draftActions, "Each player passes the last card from each booster pack to a player who drafted a card named CARDNAME.")) {
playerFlags |= CanalDredgerLastPick;
} else if (Iterables.contains(draftActions, "As long as CARDNAME is face up during the draft, you cant look at booster packs and must draft cards at random. After you draft three cards this way, turn CARDNAME face down. (You may look at cards as you draft them.)")) {
playerFlags |= ArchdemonOfPalianoCurse;
archdemonFavors.add(3);
} else if (Iterables.contains(draftActions, "Immediately after the draft, you may reveal a card in your card pool. Each other player may offer you one card in their card pool in exchange. You may accept any one offer.")) {
dealBrokers++;
} }
} }
// TODO Lore Seeker
// This adds a pack and MIGHT screw up all of our assumptions about pack passing. Do this last probably
return true; return true;
} }
@@ -354,7 +364,12 @@ public class LimitedPlayer {
} }
public DraftPack nextChoice() { public DraftPack nextChoice() {
return packQueue.peek(); DraftPack pack = packQueue.peek();
if (pack != null) {
adjustPackNumber(pack);
}
return pack;
} }
public void newPack() { public void newPack() {
@@ -363,9 +378,9 @@ public class LimitedPlayer {
packQueue.add(unopenedPacks.poll()); packQueue.add(unopenedPacks.poll());
playerFlags &= ~AgentAcquisitionsSkipDraftRound; playerFlags &= ~AgentAcquisitionsSkipDraftRound;
} }
public void adjustPackNumber(int adjust, int numPacks) {
// I shouldn't need this since DraftPack has this info public void adjustPackNumber(DraftPack pack) {
currentPack = (currentPack + adjust + numPacks) % numPacks; currentPack = pack.getId();
} }
public DraftPack passPack() { public DraftPack passPack() {
@@ -386,6 +401,10 @@ public class LimitedPlayer {
return skipping; return skipping;
} }
public boolean hasCanalDredger() {
return (playerFlags & CanalDredgerLastPick) != CanalDredgerLastPick;
}
public void receiveUnopenedPack(DraftPack pack) { public void receiveUnopenedPack(DraftPack pack) {
unopenedPacks.add(pack); unopenedPacks.add(pack);
} }
@@ -669,11 +688,110 @@ public class LimitedPlayer {
pack.resetAwaitingGuess(); pack.resetAwaitingGuess();
} }
public boolean hasArchdemonCurse() {
/* return (playerFlags & ArchdemonOfPalianoCurse) == ArchdemonOfPalianoCurse;
public void addSingleBoosterPack(boolean random) { }
// TODO Lore Seeker
// Generate booster pack then, insert it "before" the pack we're currently drafting from public boolean hasBrokers() {
return dealBrokers > 0;
}
public void reduceArchdemonOfPalianoCurse() {
if (hasArchdemonCurse()) {
archdemonFavors.replaceAll(integer -> integer - 1);
archdemonFavors.removeIf(integer -> integer <= 0);
if (archdemonFavors.isEmpty()) {
playerFlags &= ~ArchdemonOfPalianoCurse;
}
}
}
public PaperCard pickFromArchdemonCurse(DraftPack chooseFrom) {
Collections.shuffle(chooseFrom);
reduceArchdemonOfPalianoCurse();
return chooseFrom.get(0);
}
public void addSingleBoosterPack() {
// if this is just a normal draft, allow picking a pack from any set
// If this is adventure or quest or whatever then we should limit it to something
List<CardEdition> possibleEditions = Lists.newArrayList(Iterables.filter(FModel.getMagicDb().getEditions(), CardEdition.Predicates.CAN_MAKE_BOOSTER));
CardEdition edition = chooseEdition(possibleEditions);
if (edition == null) {
addLog(name() + " chose not to add a booster pack to the draft.");
return;
}
packQueue.add(draft.addBooster(edition));
addLog(name() + " added " + edition.getName() + " to be drafted this round");
}
protected CardEdition chooseEdition(List<CardEdition> possibleEditions) {
return SGuiChoose.oneOrNone("Choose a booster pack to add to the draft", possibleEditions);
}
public void activateBrokers(List<LimitedPlayer> players) {
while(dealBrokers > 0) {
dealBrokers--;
addLog(name() + " activated Deal Broker.");
PaperCard exchangeCard = chooseExchangeCard(null);
Map<PaperCard, LimitedPlayer> offers = new HashMap<>();
for(LimitedPlayer player : players) {
if (player == this) {
continue;
}
PaperCard offer = player.chooseExchangeCard(exchangeCard);
if (offer == null) {
continue;
}
addLog(player.name() + " offered " + offer.getName() + " to " + name() + " for " + exchangeCard.getName());
offers.put(offer, player);
}
PaperCard exchangeOffer = chooseCardToExchange(exchangeCard, offers);
if (exchangeOffer == null) {
addLog(name() + " chose not to accept any offers.");
continue;
}
exchangeAcceptedOffer(exchangeCard, offers.get(exchangeOffer), exchangeOffer);
}
}
protected PaperCard chooseExchangeCard(PaperCard offer) {
// Choose a card in your deck to trade for offer
List<PaperCard> deckCards = deck.getOrCreate(DeckSection.Sideboard).toFlatList();
if (offer == null) {
return SGuiChoose.oneOrNone("Choose a card to offer for trade: ", deckCards);
}
return SGuiChoose.oneOrNone("Choose a card to trade for " + offer.getName() + ": ", deckCards);
}
protected PaperCard chooseCardToExchange(PaperCard exchangeCard, Map<PaperCard, LimitedPlayer> offers) {
return SGuiChoose.oneOrNone("Choose a card to accept trade of " + exchangeCard + ": ", offers.keySet());
}
protected void exchangeAcceptedOffer(PaperCard exchangeCard, LimitedPlayer player, PaperCard offer) {
addLog(name() + " accepted the offer of " + exchangeCard + " for " + offer + " from " + player.name() + ".");
player.getDeck().removeCardName(offer.getName());
player.getDeck().get(DeckSection.Sideboard).add(exchangeCard);
deck.removeCardName(exchangeCard.getName());
deck.get(DeckSection.Sideboard).add(offer);
// Exchange noted information
player.getDraftNotes().getOrDefault(offer.getName(), Lists.newArrayList()).forEach(note -> {
List<String> noteList = noted.computeIfAbsent(offer.getName(), k -> Lists.newArrayList());
noteList.add(note);
});
this.getDraftNotes().getOrDefault(exchangeCard.getName(), Lists.newArrayList()).forEach(note -> {
List<String> noteList = player.getDraftNotes().computeIfAbsent(exchangeCard.getName(), k -> Lists.newArrayList());
noteList.add(note);
});
} }
*/
} }

View File

@@ -1,15 +1,21 @@
package forge.gamemodes.limited; package forge.gamemodes.limited;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.card.CardEdition;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.deck.CardPool; import forge.deck.CardPool;
import forge.deck.Deck; import forge.deck.Deck;
import forge.deck.DeckSection; import forge.deck.DeckSection;
import forge.deck.generation.DeckGeneratorBase;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.localinstance.properties.ForgePreferences; import forge.localinstance.properties.ForgePreferences;
import forge.util.MyRandom; import forge.util.MyRandom;
import org.apache.commons.lang3.tuple.Pair;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import static forge.gamemodes.limited.CardRanker.getOrderedRawScores; import static forge.gamemodes.limited.CardRanker.getOrderedRawScores;
@@ -39,17 +45,20 @@ public class LimitedPlayerAI extends LimitedPlayer {
System.out.println("Player[" + order + "] pack: " + chooseFrom); System.out.println("Player[" + order + "] pack: " + chooseFrom);
} }
// TODO Archdemon of Paliano random draft while active PaperCard bestPick;
if (hasArchdemonCurse()) {
bestPick = pickFromArchdemonCurse(chooseFrom);
} else {
final ColorSet chosenColors = deckCols.getChosenColors(); final ColorSet chosenColors = deckCols.getChosenColors();
final boolean canAddMoreColors = deckCols.canChoseMoreColors(); final boolean canAddMoreColors = deckCols.canChoseMoreColors();
List<PaperCard> rankedCards = rankCardsInPack(chooseFrom, pool.toFlatList(), chosenColors, canAddMoreColors); List<PaperCard> rankedCards = rankCardsInPack(chooseFrom, pool.toFlatList(), chosenColors, canAddMoreColors);
PaperCard bestPick = rankedCards.get(0); bestPick = rankedCards.get(0);
if (canAddMoreColors) { if (canAddMoreColors) {
deckCols.addColorsOf(bestPick); deckCols.addColorsOf(bestPick);
} }
}
if (ForgePreferences.DEV_MODE) { if (ForgePreferences.DEV_MODE) {
System.out.println("Player[" + order + "] picked: " + bestPick); System.out.println("Player[" + order + "] picked: " + bestPick);
@@ -222,4 +231,65 @@ public class LimitedPlayerAI extends LimitedPlayer {
return draftedThisRound < 3; return draftedThisRound < 3;
} }
@Override
protected CardEdition chooseEdition(List<CardEdition> possibleEditions) {
Collections.shuffle(possibleEditions);
return possibleEditions.get(0);
}
@Override
protected PaperCard chooseExchangeCard(PaperCard offer) {
final ColorSet colors = deckCols.getChosenColors();
List<PaperCard> deckCards = deck.getOrCreate(DeckSection.Sideboard).toFlatList();
DeckGeneratorBase.MatchColorIdentity hasColor = new DeckGeneratorBase.MatchColorIdentity(colors);
Iterable<PaperCard> colorList = Iterables.filter(deckCards,
Predicates.not(Predicates.compose(hasColor, PaperCard.FN_GET_RULES)));
PaperCard exchangeCard = null;
if (offer == null) {
// Choose the highest rated card outside your colors
List<PaperCard> rankedColorList = CardRanker.rankCardsInDeck(colorList);
return rankedColorList.get(0);
}
// Choose a card in my deck outside my colors with similar value
List<Pair<Double, PaperCard>> rankedColorList = CardRanker.getScores(colorList);
double score = CardRanker.getRawScore(offer);
double closestScore = Double.POSITIVE_INFINITY;
for (Pair<Double, PaperCard> pair : rankedColorList) {
double diff = Math.abs(pair.getLeft() - score);
if (diff < closestScore) {
closestScore = diff;
exchangeCard = pair.getRight();
}
}
return exchangeCard;
}
protected PaperCard chooseCardToExchange(PaperCard exchangeCard, Map<PaperCard, LimitedPlayer> offers) {
double score = CardRanker.getRawScore(exchangeCard);
List<Pair<Double, PaperCard>> rankedColorList = CardRanker.getScores(offers.keySet());
final ColorSet colors = deckCols.getChosenColors();
for(Pair<Double, PaperCard> pair : rankedColorList) {
ColorSet cardColors = pair.getRight().getRules().getColorIdentity();
if (!cardColors.hasNoColorsExcept(colors)) {
continue;
}
if (score < pair.getLeft()) {
return pair.getRight();
}
double threshold = Math.abs(pair.getLeft() - score) / pair.getLeft();
if (threshold < 0.1) {
return pair.getRight();
}
}
return null;
}
} }