mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 12:18:00 +00:00
Add remaining Conspiracy cards
- Archdemon of Paliano - Canal Dredger - Deal Broker - Lore Seeker
This commit is contained in:
@@ -193,6 +193,8 @@ public class PaperCard implements Comparable<IPaperCard>, InventoryItemFromSet,
|
||||
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
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
|
||||
@@ -122,6 +122,10 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> i
|
||||
return;
|
||||
}
|
||||
|
||||
if (boosterDraft.getHumanPlayer().hasArchdemonCurse()) {
|
||||
card = boosterDraft.getHumanPlayer().pickFromArchdemonCurse(boosterDraft.getHumanPlayer().nextChoice());
|
||||
}
|
||||
|
||||
// Verify if card is in the activate pack?
|
||||
this.getDeckManager().addItem(card, 1);
|
||||
|
||||
@@ -144,6 +148,7 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> i
|
||||
else {
|
||||
// TODO Deal Broker
|
||||
// Offer trades before saving
|
||||
boosterDraft.postDraftActions();
|
||||
|
||||
this.saveDraft();
|
||||
}
|
||||
@@ -178,9 +183,25 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> i
|
||||
int packNumber = ((BoosterDraft) boosterDraft).getCurrentBoosterIndex() + 1;
|
||||
|
||||
this.getCatalogManager().setCaption(localizer.getMessage("lblPackNCards", String.valueOf(packNumber)));
|
||||
this.getCatalogManager().setPool(list);
|
||||
|
||||
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);
|
||||
}
|
||||
} // 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>
|
||||
* getPlayersDeck.
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package forge;
|
||||
|
||||
import forge.card.CardEdition;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.game.card.Card;
|
||||
import forge.gamemodes.limited.DraftPack;
|
||||
import forge.gamemodes.limited.IBoosterDraft;
|
||||
import forge.gamemodes.limited.IDraftLog;
|
||||
import forge.gamemodes.limited.LimitedPlayer;
|
||||
@@ -79,6 +81,11 @@ public class BoosterDraftTest implements IBoosterDraft {
|
||||
return hasNextChoice();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DraftPack addBooster(CardEdition edition) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Card> getChosenCards() {
|
||||
return null;
|
||||
}
|
||||
@@ -111,4 +118,7 @@ public class BoosterDraftTest implements IBoosterDraft {
|
||||
public LimitedPlayer getPlayer(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postDraftActions() {}
|
||||
}
|
||||
|
||||
8
forge-gui/res/cardsfolder/a/archdemon_of_paliano.txt
Normal file
8
forge-gui/res/cardsfolder/a/archdemon_of_paliano.txt
Normal 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 can’t 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 can’t 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
|
||||
8
forge-gui/res/cardsfolder/c/canal_dredger.txt
Normal file
8
forge-gui/res/cardsfolder/c/canal_dredger.txt
Normal 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.
|
||||
10
forge-gui/res/cardsfolder/d/deal_broker.txt
Normal file
10
forge-gui/res/cardsfolder/d/deal_broker.txt
Normal 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.
|
||||
|
||||
7
forge-gui/res/cardsfolder/l/lore_seeker.txt
Normal file
7
forge-gui/res/cardsfolder/l/lore_seeker.txt
Normal 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 it’s 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 it’s drafted this draft round.)
|
||||
@@ -238,6 +238,7 @@ ScryfallCode=CN2
|
||||
[Draft Matters]
|
||||
Adriana's Valor
|
||||
Animus of Predation
|
||||
Archdemon of Paliano
|
||||
Assemble the Rank and Vile
|
||||
Custodi Peacekeeper
|
||||
Echoing Boon
|
||||
@@ -254,6 +255,7 @@ Noble Banneret
|
||||
Paliano Vanguard
|
||||
Pyretic Hunter
|
||||
Regicide
|
||||
Spire Phantasm
|
||||
Sovereign's Realm
|
||||
Summoner's Bond
|
||||
Weight Advantage
|
||||
|
||||
@@ -226,16 +226,16 @@ ScryfallCode=CNS
|
||||
1 Agent of Acquisitions|CNS
|
||||
#1 Backup Plan|CNS
|
||||
1 Brago's Favor|CNS
|
||||
#1 Canal Dredger|CNS
|
||||
1 Canal Dredger|CNS
|
||||
1 Cogwork Grinder|CNS
|
||||
1 Cogwork Librarian|CNS
|
||||
1 Cogwork Spy|CNS
|
||||
1 Cogwork Tracker|CNS
|
||||
#1 Deal Broker|CNS
|
||||
1 Deal Broker|CNS
|
||||
1 Double Stroke|CNS
|
||||
1 Immediate Action|CNS
|
||||
1 Iterative Analysis|CNS
|
||||
#1 Lore Seeker|CNS
|
||||
1 Lore Seeker|CNS
|
||||
1 Lurking Automaton|CNS
|
||||
1 Muzzio's Preparations|CNS
|
||||
1 Paliano, the High City|CNS
|
||||
|
||||
@@ -50,7 +50,7 @@ import java.util.*;
|
||||
*/
|
||||
public class BoosterDraft implements IBoosterDraft {
|
||||
|
||||
private static int nextId = 0;
|
||||
private int nextId = 0;
|
||||
private static final int N_PLAYERS = 8;
|
||||
public static final String FILE_EXT = ".draft";
|
||||
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
|
||||
public boolean isPileDraft() {
|
||||
return false;
|
||||
@@ -441,25 +446,52 @@ public class BoosterDraft implements IBoosterDraft {
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
DraftPack passingPack = this.players.get(i).passPack();
|
||||
LimitedPlayer pl = this.players.get(i);
|
||||
DraftPack passingPack = pl.passPack();
|
||||
|
||||
if (passingPack == null)
|
||||
continue;
|
||||
|
||||
if (!passingPack.isEmpty()) {
|
||||
if (passingPack.size() == 1) {
|
||||
// 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 {
|
||||
LimitedPlayer passToPlayer = null;
|
||||
if (passingPack.isEmpty()) {
|
||||
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
|
||||
for (int i = 1; i < N_PLAYERS; i++) {
|
||||
LimitedPlayer pl = this.players.get(i);
|
||||
// TODO Agent of Acquisitions activation to loop the entire pack?
|
||||
|
||||
if (pl.shouldSkipThisPick()) {
|
||||
continue;
|
||||
}
|
||||
@@ -525,6 +555,22 @@ public class BoosterDraft implements IBoosterDraft {
|
||||
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) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ public class CardRanker {
|
||||
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<PaperCard> cache = Lists.newArrayList(cards);
|
||||
|
||||
@@ -31,12 +31,12 @@ import forge.item.PaperCard;
|
||||
* @version $Id$
|
||||
*/
|
||||
public interface IBoosterDraft {
|
||||
|
||||
int getRound();
|
||||
CardPool nextChoice();
|
||||
boolean setChoice(PaperCard c);
|
||||
boolean hasNextChoice();
|
||||
boolean isRoundOver();
|
||||
DraftPack addBooster(CardEdition edition);
|
||||
Deck[] getDecks(); // size 7, all the computers decks
|
||||
LimitedPlayer[] getOpposingPlayers(); // size 7, all the computers
|
||||
LimitedPlayer getHumanPlayer();
|
||||
@@ -47,8 +47,7 @@ public interface IBoosterDraft {
|
||||
|
||||
void setLogEntry(IDraftLog draftingProcess);
|
||||
IDraftLog getDraftLog();
|
||||
void postDraftActions();
|
||||
LimitedPlayer getNeighbor(LimitedPlayer p, boolean left);
|
||||
LimitedPlayer getPlayer(int i);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,12 +3,14 @@ package forge.gamemodes.limited;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import forge.card.CardEdition;
|
||||
import forge.card.MagicColor;
|
||||
import forge.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.gui.util.SGuiChoose;
|
||||
import forge.item.PaperCard;
|
||||
import forge.model.FModel;
|
||||
import forge.util.TextUtil;
|
||||
|
||||
import java.util.*;
|
||||
@@ -25,6 +27,9 @@ public class LimitedPlayer {
|
||||
protected Queue<DraftPack> unopenedPacks;
|
||||
protected List<PaperCard> removedFromCardPool = new ArrayList<>();
|
||||
|
||||
protected List<Integer> archdemonFavors;
|
||||
protected int dealBrokers = 0;
|
||||
|
||||
private static final int AgentAcquisitionsCanDraftAll = 1;
|
||||
private static final int AgentAcquisitionsIsDraftingAll = 1 << 1;
|
||||
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 LeovoldsOperativeSkipNext = 1 << 14;
|
||||
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;
|
||||
|
||||
@@ -57,6 +64,7 @@ public class LimitedPlayer {
|
||||
|
||||
packQueue = new LinkedList<>();
|
||||
unopenedPacks = new LinkedList<>();
|
||||
archdemonFavors = new ArrayList<>();
|
||||
this.draft = draft;
|
||||
}
|
||||
|
||||
@@ -87,8 +95,6 @@ public class LimitedPlayer {
|
||||
|
||||
public PaperCard chooseCard() {
|
||||
// A non-AI LimitedPlayer chooses cards via the UI instead of this function
|
||||
// TODO Archdemon of Paliano random draft while active
|
||||
|
||||
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.")) {
|
||||
playerFlags |= SpyNextCardDrafted;
|
||||
} 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());
|
||||
note.add(String.valueOf(fromPlayer.order));
|
||||
addLog(name() + " revealed " + bestPick.getName() + " and noted " + fromPlayer.name() + " passed it.");
|
||||
@@ -304,6 +308,8 @@ public class LimitedPlayer {
|
||||
playerFlags |= SearcherNoteNext;
|
||||
} else if (Iterables.contains(draftActions, "The next time a player drafts a card from this booster pack, guess that card’s name. Then that player reveals the drafted card.")) {
|
||||
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 it’s drafted this draft round.)")) {
|
||||
addSingleBoosterPack();
|
||||
}
|
||||
|
||||
addLog(name() + " revealed " + bestPick.getName() + " as " + name() + " drafted it.");
|
||||
@@ -337,12 +343,16 @@ public class LimitedPlayer {
|
||||
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 can’t draft cards for the rest of this draft round. (You may look at booster packs passed to you.)")) {
|
||||
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 can’t 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;
|
||||
}
|
||||
|
||||
@@ -354,7 +364,12 @@ public class LimitedPlayer {
|
||||
}
|
||||
|
||||
public DraftPack nextChoice() {
|
||||
return packQueue.peek();
|
||||
DraftPack pack = packQueue.peek();
|
||||
if (pack != null) {
|
||||
adjustPackNumber(pack);
|
||||
}
|
||||
|
||||
return pack;
|
||||
}
|
||||
|
||||
public void newPack() {
|
||||
@@ -363,9 +378,9 @@ public class LimitedPlayer {
|
||||
packQueue.add(unopenedPacks.poll());
|
||||
playerFlags &= ~AgentAcquisitionsSkipDraftRound;
|
||||
}
|
||||
public void adjustPackNumber(int adjust, int numPacks) {
|
||||
// I shouldn't need this since DraftPack has this info
|
||||
currentPack = (currentPack + adjust + numPacks) % numPacks;
|
||||
|
||||
public void adjustPackNumber(DraftPack pack) {
|
||||
currentPack = pack.getId();
|
||||
}
|
||||
|
||||
public DraftPack passPack() {
|
||||
@@ -386,6 +401,10 @@ public class LimitedPlayer {
|
||||
return skipping;
|
||||
}
|
||||
|
||||
public boolean hasCanalDredger() {
|
||||
return (playerFlags & CanalDredgerLastPick) != CanalDredgerLastPick;
|
||||
}
|
||||
|
||||
public void receiveUnopenedPack(DraftPack pack) {
|
||||
unopenedPacks.add(pack);
|
||||
}
|
||||
@@ -669,11 +688,110 @@ public class LimitedPlayer {
|
||||
pack.resetAwaitingGuess();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
public void addSingleBoosterPack(boolean random) {
|
||||
// TODO Lore Seeker
|
||||
// Generate booster pack then, insert it "before" the pack we're currently drafting from
|
||||
public boolean hasArchdemonCurse() {
|
||||
return (playerFlags & ArchdemonOfPalianoCurse) == ArchdemonOfPalianoCurse;
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
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.deck.CardPool;
|
||||
import forge.deck.Deck;
|
||||
import forge.deck.DeckSection;
|
||||
import forge.deck.generation.DeckGeneratorBase;
|
||||
import forge.item.PaperCard;
|
||||
import forge.localinstance.properties.ForgePreferences;
|
||||
import forge.util.MyRandom;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static forge.gamemodes.limited.CardRanker.getOrderedRawScores;
|
||||
@@ -39,16 +45,19 @@ public class LimitedPlayerAI extends LimitedPlayer {
|
||||
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 boolean canAddMoreColors = deckCols.canChoseMoreColors();
|
||||
|
||||
final ColorSet chosenColors = deckCols.getChosenColors();
|
||||
final boolean canAddMoreColors = deckCols.canChoseMoreColors();
|
||||
List<PaperCard> rankedCards = rankCardsInPack(chooseFrom, pool.toFlatList(), chosenColors, canAddMoreColors);
|
||||
bestPick = rankedCards.get(0);
|
||||
|
||||
List<PaperCard> rankedCards = rankCardsInPack(chooseFrom, pool.toFlatList(), chosenColors, canAddMoreColors);
|
||||
PaperCard bestPick = rankedCards.get(0);
|
||||
|
||||
if (canAddMoreColors) {
|
||||
deckCols.addColorsOf(bestPick);
|
||||
if (canAddMoreColors) {
|
||||
deckCols.addColorsOf(bestPick);
|
||||
}
|
||||
}
|
||||
|
||||
if (ForgePreferences.DEV_MODE) {
|
||||
@@ -222,4 +231,65 @@ public class LimitedPlayerAI extends LimitedPlayer {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user