Draft Matters - How many cards you've drafted this round (#5203)

This commit is contained in:
Chris H
2024-05-21 05:36:59 -04:00
committed by GitHub
parent 6eebb1861f
commit 6087167673
30 changed files with 548 additions and 167 deletions

View File

@@ -51,6 +51,7 @@ final class CardFace implements ICardFace, Cloneable {
private List<String> abilities = null; private List<String> abilities = null;
private List<String> staticAbilities = null; private List<String> staticAbilities = null;
private List<String> triggers = null; private List<String> triggers = null;
private List<String> draftActions = null;
private List<String> replacements = null; private List<String> replacements = null;
private Map<String, String> variables = null; private Map<String, String> variables = null;
@@ -74,6 +75,7 @@ final class CardFace implements ICardFace, Cloneable {
@Override public Iterable<String> getAbilities() { return abilities; } @Override public Iterable<String> getAbilities() { return abilities; }
@Override public Iterable<String> getStaticAbilities() { return staticAbilities; } @Override public Iterable<String> getStaticAbilities() { return staticAbilities; }
@Override public Iterable<String> getTriggers() { return triggers; } @Override public Iterable<String> getTriggers() { return triggers; }
@Override public Iterable<String> getDraftActions() { return draftActions; }
@Override public Iterable<String> getReplacements() { return replacements; } @Override public Iterable<String> getReplacements() { return replacements; }
@Override public String getNonAbilityText() { return nonAbilityText; } @Override public String getNonAbilityText() { return nonAbilityText; }
@Override public Iterable<Entry<String, String>> getVariables() { return variables.entrySet(); } @Override public Iterable<Entry<String, String>> getVariables() { return variables.entrySet(); }
@@ -125,6 +127,7 @@ final class CardFace implements ICardFace, Cloneable {
void addKeyword(String value) { if (null == this.keywords) { this.keywords = new ArrayList<>(); } this.keywords.add(value); } void addKeyword(String value) { if (null == this.keywords) { this.keywords = new ArrayList<>(); } this.keywords.add(value); }
void addAbility(String value) { if (null == this.abilities) { this.abilities = new ArrayList<>(); } this.abilities.add(value);} void addAbility(String value) { if (null == this.abilities) { this.abilities = new ArrayList<>(); } this.abilities.add(value);}
void addTrigger(String value) { if (null == this.triggers) { this.triggers = new ArrayList<>(); } this.triggers.add(value);} void addTrigger(String value) { if (null == this.triggers) { this.triggers = new ArrayList<>(); } this.triggers.add(value);}
void addDraftAction(String value) { if (null == this.draftActions) { this.draftActions = new ArrayList<>(); } this.draftActions.add(value);}
void addStaticAbility(String value) { if (null == this.staticAbilities) { this.staticAbilities = new ArrayList<>(); } this.staticAbilities.add(value);} void addStaticAbility(String value) { if (null == this.staticAbilities) { this.staticAbilities = new ArrayList<>(); } this.staticAbilities.add(value);}
void addReplacementEffect(String value) { if (null == this.replacements) { this.replacements = new ArrayList<>(); } this.replacements.add(value);} void addReplacementEffect(String value) { if (null == this.replacements) { this.replacements = new ArrayList<>(); } this.replacements.add(value);}
void addSVar(String key, String value) { if (null == this.variables) { this.variables = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); } this.variables.put(key, value); } void addSVar(String key, String value) { if (null == this.variables) { this.variables = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); } this.variables.put(key, value); }

View File

@@ -547,6 +547,8 @@ public final class CardRules implements ICardCharacteristics {
has = new DeckHints(value); has = new DeckHints(value);
} else if ("Defense".equals(key)) { } else if ("Defense".equals(key)) {
this.faces[this.curFace].setDefense(value); this.faces[this.curFace].setDefense(value);
} else if ("Draft".equals(key)) {
this.faces[this.curFace].addDraftAction(value);
} }
break; break;

View File

@@ -7,6 +7,7 @@ public interface ICardRawAbilites
Iterable<String> getKeywords(); Iterable<String> getKeywords();
Iterable<String> getReplacements(); Iterable<String> getReplacements();
Iterable<String> getTriggers(); Iterable<String> getTriggers();
Iterable<String> getDraftActions();
Iterable<String> getStaticAbilities(); Iterable<String> getStaticAbilities();
Iterable<String> getAbilities(); Iterable<String> getAbilities();

View File

@@ -49,6 +49,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
// Supports deferring loading a deck until we actually need its contents. This works in conjunction with // Supports deferring loading a deck until we actually need its contents. This works in conjunction with
// the lazy card load feature to ensure we don't need to load all cards on start up. // the lazy card load feature to ensure we don't need to load all cards on start up.
private final Set<String> aiHints = new TreeSet<>(); private final Set<String> aiHints = new TreeSet<>();
private final Map<String, String> draftNotes = new HashMap<>();
private Map<String, List<String>> deferredSections = null; private Map<String, List<String>> deferredSections = null;
private Map<String, List<String>> loadedSections = null; private Map<String, List<String>> loadedSections = null;
private String lastCardArtPreferenceUsed = ""; private String lastCardArtPreferenceUsed = "";
@@ -91,10 +92,6 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
public Deck(final Deck other, final String newName) { public Deck(final Deck other, final String newName) {
super(newName); super(newName);
other.cloneFieldsTo(this); other.cloneFieldsTo(this);
for (final Entry<DeckSection, CardPool> sections : other.parts.entrySet()) {
parts.put(sections.getKey(), new CardPool(sections.getValue()));
}
tags.addAll(other.getTags());
} }
@Override @Override
@@ -209,6 +206,8 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
cp.addAll(kv.getValue()); cp.addAll(kv.getValue());
} }
result.setAiHints(StringUtils.join(aiHints, " | ")); result.setAiHints(StringUtils.join(aiHints, " | "));
result.setDraftNotes(draftNotes);
tags.addAll(result.getTags());
} }
/* /*
@@ -561,6 +560,24 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
return ""; return "";
} }
public void setDraftNotes(Map<String, String> draftNotes) {
if (draftNotes == null) {
return;
}
for(String key : draftNotes.keySet()) {
String notes = draftNotes.get(key);
if (notes == null || notes.isEmpty()) {
continue;
}
this.draftNotes.put(key, notes.trim());
}
}
public Map<String, String> getDraftNotes() {
return draftNotes;
}
public UnplayableAICards getUnplayableAICards() { public UnplayableAICards getUnplayableAICards() {
if (unplayableAI == null) { if (unplayableAI == null) {
unplayableAI = new UnplayableAICards(this); unplayableAI = new UnplayableAICards(this);

View File

@@ -26,7 +26,8 @@ import java.util.List;
import com.google.common.base.Function; import com.google.common.base.Function;
/** /**
* TODO: Write javadoc for this type. * Related decks usually pertaining to a limited experience like draft or sealed
* This file represents a human player deck and all opposing AI decks
* *
*/ */
public class DeckGroup extends DeckBase { public class DeckGroup extends DeckBase {

View File

@@ -17,6 +17,7 @@
*/ */
package forge.deck.io; package forge.deck.io;
import java.util.HashMap;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
@@ -37,9 +38,10 @@ public class DeckFileHeader {
/** The Constant DECK_TYPE. */ /** The Constant DECK_TYPE. */
public static final String DECK_TYPE = "Deck Type"; public static final String DECK_TYPE = "Deck Type";
public static final String TAGS = "Tags"; public static final String TAGS = "Tags";
public static final String TAGS_SEPARATOR = ","; public static final String TAGS_SEPARATOR = ",";
public static final String DRAFT_NOTES = "DraftNotes";
/** The Constant COMMENT. */ /** The Constant COMMENT. */
public static final String COMMENT = "Comment"; public static final String COMMENT = "Comment";
private static final String PLAYER = "Player"; private static final String PLAYER = "Player";
@@ -54,30 +56,19 @@ public class DeckFileHeader {
private final String comment; private final String comment;
private final Set<String> tags; private final Set<String> tags;
private final HashMap<String, String> draftNotes;
private final boolean intendedForAi; private final boolean intendedForAi;
private final String aiHints; private final String aiHints;
/**
* @return the intendedForAi
*/
public boolean isIntendedForAi() { public boolean isIntendedForAi() {
return intendedForAi; return intendedForAi;
} }
/**
* @return the AI hints
*/
public String getAiHints() { public String getAiHints() {
return aiHints; return aiHints;
} }
/**
* TODO: Write javadoc for Constructor.
*
* @param kvPairs
* the kv pairs
*/
public DeckFileHeader(final FileSection kvPairs) { public DeckFileHeader(final FileSection kvPairs) {
this.name = kvPairs.get(DeckFileHeader.NAME); this.name = kvPairs.get(DeckFileHeader.NAME);
this.comment = kvPairs.get(DeckFileHeader.COMMENT); this.comment = kvPairs.get(DeckFileHeader.COMMENT);
@@ -85,6 +76,7 @@ public class DeckFileHeader {
this.customPool = kvPairs.getBoolean(DeckFileHeader.CSTM_POOL); this.customPool = kvPairs.getBoolean(DeckFileHeader.CSTM_POOL);
this.intendedForAi = "computer".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER)) || "ai".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER_TYPE)); this.intendedForAi = "computer".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER)) || "ai".equalsIgnoreCase(kvPairs.get(DeckFileHeader.PLAYER_TYPE));
this.aiHints = kvPairs.get(DeckFileHeader.AI_HINTS); this.aiHints = kvPairs.get(DeckFileHeader.AI_HINTS);
this.tags = new TreeSet<>(); this.tags = new TreeSet<>();
String rawTags = kvPairs.get(DeckFileHeader.TAGS); String rawTags = kvPairs.get(DeckFileHeader.TAGS);
@@ -93,42 +85,42 @@ public class DeckFileHeader {
if ( StringUtils.isNotBlank(t)) if ( StringUtils.isNotBlank(t))
tags.add(t.trim()); tags.add(t.trim());
} }
this.draftNotes = new HashMap<>();
extractDraftNotes(kvPairs.get(DeckFileHeader.DRAFT_NOTES));
}
private void extractDraftNotes(String rawNotes) {
if(StringUtils.isBlank(rawNotes) ) {
return;
}
for(String t : rawNotes.split("\\|")) {
if (StringUtils.isBlank(t)) {
continue;
}
String[] notes = t.trim().split(":", 2);
if (notes[0].trim().isEmpty() || notes[1].trim().isEmpty()) {
continue;
}
draftNotes.put(notes[0].trim(), notes[1].trim());
}
} }
/**
* Checks if is custom pool.
*
* @return true, if is custom pool
*/
public final boolean isCustomPool() { public final boolean isCustomPool() {
return this.customPool; return this.customPool;
} }
/**
* Gets the name.
*
* @return the name
*/
public final String getName() { public final String getName() {
return this.name; return this.name;
} }
/**
* Gets the comment.
*
* @return the comment
*/
public final String getComment() { public final String getComment() {
return this.comment; return this.comment;
} }
/**
* Gets the deck type.
*
* @return the deck type
*/
public final DeckFormat getDeckType() { public final DeckFormat getDeckType() {
return this.deckType; return this.deckType;
} }
@@ -137,4 +129,7 @@ public class DeckFileHeader {
return tags; return tags;
} }
public final HashMap<String, String> getDraftNotes() {
return draftNotes;
}
} }

View File

@@ -56,14 +56,30 @@ public class DeckSerializer {
if (!d.getAiHints().isEmpty()) { if (!d.getAiHints().isEmpty()) {
out.add(TextUtil.concatNoSpace(DeckFileHeader.AI_HINTS, "=", StringUtils.join(d.getAiHints(), " | "))); out.add(TextUtil.concatNoSpace(DeckFileHeader.AI_HINTS, "=", StringUtils.join(d.getAiHints(), " | ")));
} }
if (!d.getDraftNotes().isEmpty()) {
String sb = serializeDraftNotes(d.getDraftNotes());
out.add(TextUtil.concatNoSpace(DeckFileHeader.DRAFT_NOTES, "=", sb));
}
for(Entry<DeckSection, CardPool> s : d) { for(Entry<DeckSection, CardPool> s : d) {
out.add(TextUtil.enclosedBracket(s.getKey().toString())); out.add(TextUtil.enclosedBracket(s.getKey().toString()));
out.add(s.getValue().toCardList(System.getProperty("line.separator"))); out.add(s.getValue().toCardList(System.lineSeparator()));
} }
return out; return out;
} }
public static String serializeDraftNotes(final Map<String, String> draftNotes) {
StringBuilder sb = new StringBuilder();
for(String key : draftNotes.keySet()) {
if (sb.length() > 0) {
sb.append(" | ");
}
sb.append(key).append(":").append(draftNotes.get(key));
}
return sb.toString();
}
public static Deck fromFile(final File deckFile) { public static Deck fromFile(final File deckFile) {
return fromSections(FileSection.parseSections(FileUtil.readFile(deckFile))); return fromSections(FileSection.parseSections(FileUtil.readFile(deckFile)));
} }
@@ -82,6 +98,7 @@ public class DeckSerializer {
d.setComment(dh.getComment()); d.setComment(dh.getComment());
d.setAiHints(dh.getAiHints()); d.setAiHints(dh.getAiHints());
d.getTags().addAll(dh.getTags()); d.getTags().addAll(dh.getTags());
d.setDraftNotes(dh.getDraftNotes());
d.setDeferredSections(sections); d.setDeferredSections(sections);
return d; return d;
} }

View File

@@ -288,6 +288,7 @@ public class Match {
} }
Deck myDeck = psc.getDeck(); Deck myDeck = psc.getDeck();
player.setDraftNotes(myDeck.getDraftNotes());
Set<PaperCard> myRemovedAnteCards = null; Set<PaperCard> myRemovedAnteCards = null;
if (!rules.useAnte()) { if (!rules.useAnte()) {

View File

@@ -2358,6 +2358,23 @@ public class AbilityUtils {
return doXMath(player.getNotedNumberForName(c.getName()), expr, c, ctb); return doXMath(player.getNotedNumberForName(c.getName()), expr, c, ctb);
} }
if (sq[0].equals("DraftNotesHighest")) {
// Just in case you are playing this card in a deck without draft notes
String note = player.getDraftNotes().getOrDefault(sq[1], "0");
int highest = 0;
for (String n : note.split(",")) {
int num = Integer.parseInt(n);
if (num > highest) {
highest = num;
}
}
return doXMath(highest, expr, c, ctb);
// Other draft notes include: Names, Colors, Players, Creature Type.
// But these aren't really things you count so they'll show up in properties most likely
}
//Count$TypesSharedWith [defined] //Count$TypesSharedWith [defined]
if (sq[0].startsWith("TypesSharedWith")) { if (sq[0].startsWith("TypesSharedWith")) {
Set<CardType.CoreType> thisTypes = Sets.newHashSet(c.getType().getCoreTypes()); Set<CardType.CoreType> thisTypes = Sets.newHashSet(c.getType().getCoreTypes());

View File

@@ -124,6 +124,7 @@ public class Player extends GameEntity implements Comparable<Player> {
private final Map<String, FCollection<String>> notes = Maps.newHashMap(); private final Map<String, FCollection<String>> notes = Maps.newHashMap();
private final Map<String, Integer> notedNum = Maps.newHashMap(); private final Map<String, Integer> notedNum = Maps.newHashMap();
private final Map<String, String> draftNotes = Maps.newHashMap();
private boolean revolt = false; private boolean revolt = false;
private int descended = 0; private int descended = 0;
@@ -2376,6 +2377,15 @@ public class Player extends GameEntity implements Comparable<Player> {
return getName().compareTo(o.getName()); return getName().compareTo(o.getName());
} }
public void setDraftNotes(Map<String, String> notes) {
this.draftNotes.clear();
this.draftNotes.putAll(notes);
}
public Map<String, String> getDraftNotes() {
return draftNotes;
}
public static class Accessors { public static class Accessors {
public static Function<Player, String> FN_GET_NAME = new Function<Player, String>() { public static Function<Player, String> FN_GET_NAME = new Function<Player, String>() {
@Override @Override

View File

@@ -5,16 +5,7 @@ package forge.gui.framework;
import com.google.common.collect.ObjectArrays; import com.google.common.collect.ObjectArrays;
import forge.screens.deckeditor.views.VAllDecks; import forge.screens.deckeditor.views.*;
import forge.screens.deckeditor.views.VBrawlDecks;
import forge.screens.deckeditor.views.VCardCatalog;
import forge.screens.deckeditor.views.VCommanderDecks;
import forge.screens.deckeditor.views.VCurrentDeck;
import forge.screens.deckeditor.views.VDeckgen;
import forge.screens.deckeditor.views.VOathbreakerDecks;
import forge.screens.deckeditor.views.VProbabilities;
import forge.screens.deckeditor.views.VStatistics;
import forge.screens.deckeditor.views.VTinyLeadersDecks;
import forge.screens.home.gauntlet.*; import forge.screens.home.gauntlet.*;
import forge.screens.home.online.VSubmenuOnlineLobby; import forge.screens.home.online.VSubmenuOnlineLobby;
import forge.screens.home.puzzle.VSubmenuPuzzleCreate; import forge.screens.home.puzzle.VSubmenuPuzzleCreate;
@@ -61,6 +52,7 @@ public enum EDocID {
EDITOR_BRAWL (VBrawlDecks.SINGLETON_INSTANCE), EDITOR_BRAWL (VBrawlDecks.SINGLETON_INSTANCE),
EDITOR_TINY_LEADERS (VTinyLeadersDecks.SINGLETON_INSTANCE), EDITOR_TINY_LEADERS (VTinyLeadersDecks.SINGLETON_INSTANCE),
EDITOR_OATHBREAKER (VOathbreakerDecks.SINGLETON_INSTANCE), EDITOR_OATHBREAKER (VOathbreakerDecks.SINGLETON_INSTANCE),
EDITOR_LOG(VEditorLog.SINGLETON_INSTANCE),
WORKSHOP_CATALOG (VWorkshopCatalog.SINGLETON_INSTANCE), WORKSHOP_CATALOG (VWorkshopCatalog.SINGLETON_INSTANCE),
WORKSHOP_CARDDESIGNER (VCardDesigner.SINGLETON_INSTANCE), WORKSHOP_CARDDESIGNER (VCardDesigner.SINGLETON_INSTANCE),

View File

@@ -42,13 +42,7 @@ import forge.screens.deckeditor.controllers.CEditorQuestCardShop;
import forge.screens.deckeditor.controllers.CProbabilities; import forge.screens.deckeditor.controllers.CProbabilities;
import forge.screens.deckeditor.controllers.CStatistics; import forge.screens.deckeditor.controllers.CStatistics;
import forge.screens.deckeditor.controllers.DeckController; import forge.screens.deckeditor.controllers.DeckController;
import forge.screens.deckeditor.views.VAllDecks; import forge.screens.deckeditor.views.*;
import forge.screens.deckeditor.views.VBrawlDecks;
import forge.screens.deckeditor.views.VCardCatalog;
import forge.screens.deckeditor.views.VCommanderDecks;
import forge.screens.deckeditor.views.VCurrentDeck;
import forge.screens.deckeditor.views.VOathbreakerDecks;
import forge.screens.deckeditor.views.VTinyLeadersDecks;
import forge.screens.match.controllers.CDetailPicture; import forge.screens.match.controllers.CDetailPicture;
import forge.util.ItemPool; import forge.util.ItemPool;
@@ -72,6 +66,7 @@ public enum CDeckEditorUI implements ICDoc {
private final VOathbreakerDecks vOathbreakerDecks; private final VOathbreakerDecks vOathbreakerDecks;
private final VBrawlDecks vBrawlDecks; private final VBrawlDecks vBrawlDecks;
private final VTinyLeadersDecks vTinyLeadersDecks; private final VTinyLeadersDecks vTinyLeadersDecks;
private final VEditorLog vEditorLog;
CDeckEditorUI() { CDeckEditorUI() {
screenChildControllers = new HashMap<>(); screenChildControllers = new HashMap<>();
@@ -86,6 +81,7 @@ public enum CDeckEditorUI implements ICDoc {
this.vBrawlDecks.setCDetailPicture(cDetailPicture); this.vBrawlDecks.setCDetailPicture(cDetailPicture);
this.vTinyLeadersDecks = VTinyLeadersDecks.SINGLETON_INSTANCE; this.vTinyLeadersDecks = VTinyLeadersDecks.SINGLETON_INSTANCE;
this.vTinyLeadersDecks.setCDetailPicture(cDetailPicture); this.vTinyLeadersDecks.setCDetailPicture(cDetailPicture);
this.vEditorLog = VEditorLog.SINGLETON_INSTANCE;
} }
public CDetailPicture getCDetailPicture() { public CDetailPicture getCDetailPicture() {
@@ -230,9 +226,9 @@ public enum CDeckEditorUI implements ICDoc {
} }
else if (KeyEvent.VK_LEFT == e.getKeyCode() || KeyEvent.VK_RIGHT == e.getKeyCode()) { else if (KeyEvent.VK_LEFT == e.getKeyCode() || KeyEvent.VK_RIGHT == e.getKeyCode()) {
if (e.isControlDown() || e.isMetaDown()) { if (e.isControlDown() || e.isMetaDown()) {
deckView.focus(); deckView.focus();
e.consume(); //prevent losing selection e.consume(); //prevent losing selection
} }
} }
} }
}); });
@@ -308,6 +304,7 @@ public enum CDeckEditorUI implements ICDoc {
public void register() { public void register() {
EDocID.CARD_PICTURE.setDoc(cDetailPicture.getCPicture().getView()); EDocID.CARD_PICTURE.setDoc(cDetailPicture.getCPicture().getView());
EDocID.CARD_DETAIL.setDoc(cDetailPicture.getCDetail().getView()); EDocID.CARD_DETAIL.setDoc(cDetailPicture.getCDetail().getView());
EDocID.EDITOR_LOG.setDoc(vEditorLog);
} }
/* (non-Javadoc) /* (non-Javadoc)

View File

@@ -27,6 +27,8 @@ import forge.deck.DeckSection;
import forge.game.GameType; import forge.game.GameType;
import forge.gamemodes.limited.BoosterDraft; import forge.gamemodes.limited.BoosterDraft;
import forge.gamemodes.limited.IBoosterDraft; import forge.gamemodes.limited.IBoosterDraft;
import forge.gamemodes.limited.IDraftLog;
import forge.gamemodes.limited.LimitedPlayer;
import forge.gui.framework.DragCell; import forge.gui.framework.DragCell;
import forge.gui.framework.FScreen; import forge.gui.framework.FScreen;
import forge.item.PaperCard; import forge.item.PaperCard;
@@ -34,13 +36,7 @@ import forge.itemmanager.CardManager;
import forge.itemmanager.ItemManagerConfig; import forge.itemmanager.ItemManagerConfig;
import forge.model.FModel; import forge.model.FModel;
import forge.screens.deckeditor.CDeckEditorUI; import forge.screens.deckeditor.CDeckEditorUI;
import forge.screens.deckeditor.views.VAllDecks; import forge.screens.deckeditor.views.*;
import forge.screens.deckeditor.views.VBrawlDecks;
import forge.screens.deckeditor.views.VCommanderDecks;
import forge.screens.deckeditor.views.VCurrentDeck;
import forge.screens.deckeditor.views.VDeckgen;
import forge.screens.deckeditor.views.VOathbreakerDecks;
import forge.screens.deckeditor.views.VTinyLeadersDecks;
import forge.screens.home.sanctioned.CSubmenuDraft; import forge.screens.home.sanctioned.CSubmenuDraft;
import forge.screens.match.controllers.CDetailPicture; import forge.screens.match.controllers.CDetailPicture;
import forge.toolbox.FOptionPane; import forge.toolbox.FOptionPane;
@@ -55,7 +51,7 @@ import forge.util.Localizer;
* @author Forge * @author Forge
* @version $Id: CEditorDraftingProcess.java 24872 2014-02-17 07:35:47Z drdev $ * @version $Id: CEditorDraftingProcess.java 24872 2014-02-17 07:35:47Z drdev $
*/ */
public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> { public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> implements IDraftLog {
private IBoosterDraft boosterDraft; private IBoosterDraft boosterDraft;
private String ccAddLabel = Localizer.getInstance().getMessage("lblAddcard"); private String ccAddLabel = Localizer.getInstance().getMessage("lblAddcard");
@@ -65,6 +61,7 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> {
private DragCell brawlDecksParent = null; private DragCell brawlDecksParent = null;
private DragCell tinyLeadersDecksParent = null; private DragCell tinyLeadersDecksParent = null;
private DragCell deckGenParent = null; private DragCell deckGenParent = null;
private DragCell draftLogParent = null;
private boolean saved = false; private boolean saved = false;
private final Localizer localizer = Localizer.getInstance(); private final Localizer localizer = Localizer.getInstance();
@@ -99,6 +96,13 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> {
*/ */
public final void showGui(final IBoosterDraft inBoosterDraft) { public final void showGui(final IBoosterDraft inBoosterDraft) {
this.boosterDraft = inBoosterDraft; this.boosterDraft = inBoosterDraft;
this.boosterDraft.setLogEntry(this);
this.addLogEntry("Drafting process started.");
}
public void addLogEntry(String message) {
CEditorLog.SINGLETON_INSTANCE.addLogEntry(message);
} }
/* (non-Javadoc) /* (non-Javadoc)
@@ -110,6 +114,8 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> {
// 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();
// 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
@@ -212,16 +218,30 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> {
} while(s == null || s.isEmpty()); } while(s == null || s.isEmpty());
saved = true;
// Construct computer's decks and save draft // Construct computer's decks and save draft
final Deck[] computer = this.boosterDraft.getDecks(); final Deck[] computer = this.boosterDraft.getDecks();
final LimitedPlayer[] players = this.boosterDraft.getOpposingPlayers();
for(int i = 0; i < computer.length; i++) {
Deck deck = computer[i];
LimitedPlayer player = players[i];
deck.setDraftNotes(player.getSerializedDraftNotes());
}
// Assigned noted stuff to deck from LimitedPlayer
final DeckGroup finishedDraft = new DeckGroup(s); final DeckGroup finishedDraft = new DeckGroup(s);
finishedDraft.setHumanDeck((Deck) this.getPlayersDeck().copyTo(s)); final LimitedPlayer player = this.boosterDraft.getHumanPlayer();
Deck humanDeck = (Deck) this.getPlayersDeck().copyTo(s);
humanDeck.setDraftNotes(player.getSerializedDraftNotes());
finishedDraft.setHumanDeck(humanDeck);
finishedDraft.addAiDecks(computer); finishedDraft.addAiDecks(computer);
FModel.getDecks().getDraft().add(finishedDraft); FModel.getDecks().getDraft().add(finishedDraft);
saved = true;
CSubmenuDraft.SINGLETON_INSTANCE.update(); CSubmenuDraft.SINGLETON_INSTANCE.update();
FScreen.DRAFTING_PROCESS.close(); FScreen.DRAFTING_PROCESS.close();
@@ -267,6 +287,11 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> {
this.getCatalogManager().setup(ItemManagerConfig.DRAFT_PACK); this.getCatalogManager().setup(ItemManagerConfig.DRAFT_PACK);
this.getDeckManager().setup(ItemManagerConfig.DRAFT_POOL); this.getDeckManager().setup(ItemManagerConfig.DRAFT_POOL);
if (VEditorLog.SINGLETON_INSTANCE.getParentCell() == null) {
VCardCatalog.SINGLETON_INSTANCE.getParentCell().addDoc(VEditorLog.SINGLETON_INSTANCE);
VEditorLog.SINGLETON_INSTANCE.showView();
}
ccAddLabel = this.getBtnAdd().getText(); ccAddLabel = this.getBtnAdd().getText();
if (this.getDeckManager().getPool() == null) { //avoid showing next choice or resetting pool if just switching back to Draft screen if (this.getDeckManager().getPool() == null) { //avoid showing next choice or resetting pool if just switching back to Draft screen
@@ -327,6 +352,7 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> {
this.getBtnRemove4().setVisible(true); this.getBtnRemove4().setVisible(true);
VCurrentDeck.SINGLETON_INSTANCE.getPnlHeader().setVisible(true); VCurrentDeck.SINGLETON_INSTANCE.getPnlHeader().setVisible(true);
VEditorLog.SINGLETON_INSTANCE.getParentCell().setVisible(true);
//Re-add tabs //Re-add tabs
if (deckGenParent != null) { if (deckGenParent != null) {
@@ -347,6 +373,9 @@ public class CEditorDraftingProcess extends ACEditorBase<PaperCard, DeckGroup> {
if (tinyLeadersDecksParent != null) { if (tinyLeadersDecksParent != null) {
tinyLeadersDecksParent.addDoc(VTinyLeadersDecks.SINGLETON_INSTANCE); tinyLeadersDecksParent.addDoc(VTinyLeadersDecks.SINGLETON_INSTANCE);
} }
if (draftLogParent != null) {
draftLogParent.addDoc(VEditorLog.SINGLETON_INSTANCE);
}
// set catalog table back to free-selection mode // set catalog table back to free-selection mode
getCatalogManager().setAllowMultipleSelections(true); getCatalogManager().setAllowMultipleSelections(true);

View File

@@ -0,0 +1,66 @@
package forge.screens.deckeditor.controllers;
import forge.gui.FThreads;
import forge.gui.framework.ICDoc;
import forge.screens.deckeditor.views.VEditorLog;
/**
* Controls the "editor log" panel in the deck editor UI.
*
* <br><br><i>(C at beginning of class name denotes a control class.)</i>
*
*/
public enum CEditorLog implements ICDoc {
SINGLETON_INSTANCE;
/** */
CEditorDraftingProcess draftingProcess;
private final VEditorLog view;
CEditorLog() {
this.view = VEditorLog.SINGLETON_INSTANCE;
}
//========== Overridden methods
public final VEditorLog getView() {
return view;
}
public final void addLogEntry(final String entry) {
view.addLogEntry(entry);
}
@Override
public void register() {
}
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#initialize()
*/
@Override
public void initialize() {
FThreads.invokeInEdtNowOrLater(reset);
}
private final Runnable reset = new Runnable() {
@Override
public void run() {
view.resetNewDraft();
}
};
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#update()
*/
@Override
public void update() {
FThreads.invokeInEdtNowOrLater(new Runnable() {
@Override
public void run() {
view.updateConsole();
}
});
}
}

View File

@@ -0,0 +1,102 @@
package forge.screens.deckeditor.views;
import com.google.common.collect.Lists;
import forge.gui.framework.DragCell;
import forge.gui.framework.DragTab;
import forge.gui.framework.EDocID;
import forge.gui.framework.IVDoc;
import forge.screens.deckeditor.controllers.CEditorLog;
import forge.screens.match.GameLogPanel;
import forge.toolbox.FScrollPane;
import forge.util.Localizer;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import java.util.List;
/**
* Assembles Swing components of card catalog in deck editor.
*
* <br><br><i>(V at beginning of class name denotes a view class.)</i>
*
*/
public enum VEditorLog implements IVDoc<CEditorLog> {
SINGLETON_INSTANCE;
// Fields used with interface IVDoc
private DragCell parentCell;
final Localizer localizer = Localizer.getInstance();
private final DragTab tab = new DragTab(localizer.getMessage("lblEditorLog"));
private final GameLogPanel gameLog;
private final JPanel pnlContent = new JPanel(new MigLayout("insets 0, gap 0, wrap"));
private final FScrollPane scroller = new FScrollPane(pnlContent, false);
private final List<String> editorLogEntries = Lists.newArrayList();
VEditorLog() {
pnlContent.setOpaque(false);
scroller.getViewport().setBorder(null);
this.gameLog = new GameLogPanel();
}
//========== Overridden from IVDoc
@Override
public EDocID getDocumentID() {
return EDocID.EDITOR_LOG;
}
@Override
public DragTab getTabLabel() {
return tab;
}
public void showView() {
tab.setVisible(true);
tab.setOpaque(true);
pnlContent.setOpaque(true);
pnlContent.setVisible(true);
}
@Override
public CEditorLog getLayoutControl() {
return CEditorLog.SINGLETON_INSTANCE;
}
@Override
public void setParentCell(final DragCell cell0) {
this.parentCell = cell0;
}
@Override
public DragCell getParentCell() {
return this.parentCell;
}
@Override
public void populate() {
final JPanel parentBody = parentCell.getBody();
parentBody.setLayout(new MigLayout("insets 5, gap 0, wrap, hidemode 3"));
// Add the panel that contains the log entries
parentBody.add(gameLog, "w 10:100%, h 100%");
}
public void resetNewDraft() {
// Should we store the draft?
gameLog.reset();
editorLogEntries.clear();
}
public void updateConsole() {
gameLog.updateUI();
}
public void addLogEntry(String entry) {
gameLog.addLogEntry(entry);
this.editorLogEntries.add(entry);
}
}

View File

@@ -2,6 +2,8 @@ package forge;
import java.util.List; import java.util.List;
import forge.gamemodes.limited.IDraftLog;
import forge.gamemodes.limited.LimitedPlayer;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import forge.deck.CardPool; import forge.deck.CardPool;
@@ -32,6 +34,16 @@ public class BoosterDraftTest implements IBoosterDraft {
return null; return null;
} }
@Override
public LimitedPlayer[] getOpposingPlayers() {
return new LimitedPlayer[0];
}
@Override
public LimitedPlayer getHumanPlayer() {
return null;
}
@Override @Override
public CardPool nextChoice() { public CardPool nextChoice() {
this.n--; this.n--;
@@ -69,4 +81,14 @@ public class BoosterDraftTest implements IBoosterDraft {
public boolean isPileDraft() { public boolean isPileDraft() {
return false; return false;
} }
@Override
public void setLogEntry(IDraftLog draftingProcess) {
}
@Override
public IDraftLog getDraftLog() {
return null;
}
} }

View File

@@ -635,33 +635,6 @@
1 Wayfaring Temple|RTR 1 Wayfaring Temple|RTR
1 Wild Beastmaster|RTR 1 Wild Beastmaster|RTR
[CNS Draft Matters]
#1 Advantageous Proclamation|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 Deal Broker|CNS
#1 Double Stroke|CNS
1 Immediate Action|CNS
#1 Iterative Analysis|CNS
#1 Lore Seeker|CNS
#1 Lurking Automaton|CNS
1 Muzzio's Preparations|CNS
#1 Paliano, the High City|CNS
#1 Power Play|CNS
1 Secret Summoning|CNS
1 Secrets of Paradise|CNS
#1 Sentinel Dispatch|CNS
#1 Unexpected Potential|CNS
#1 Whispergear Sneak|CNS
#1 Worldknit|CNS
[M15 Sample Cards] [M15 Sample Cards]
1 Aegis Angel|M15 1 Aegis Angel|M15
1 Cancel|M15 1 Cancel|M15
@@ -965,21 +938,6 @@ Strip Mine|EXP
Tectonic Edge|EXP Tectonic Edge|EXP
Wasteland|EXP Wasteland|EXP
[CN2 Draft Matters]
Adriana's Valor
Assemble the Rank and Vile
Echoing Boon
#Emissary's Ploy
Hired Heist
Hold the Perimeter
Hymn of the Wilds
Incendiary Dissent
Natural Unity
#Sovereign's Realm
Summoner's Bond
Weight Advantage
[MPS Amonkhet Invocations] [MPS Amonkhet Invocations]
Austere Command|MPS_AKH Austere Command|MPS_AKH
Aven Mindcensor|MPS_AKH Aven Mindcensor|MPS_AKH
@@ -1483,24 +1441,6 @@ Kenrith's Transformation|ELD|2
Improbable Alliance|ELD|2 Improbable Alliance|ELD|2
Inspiring Veteran|ELD|2 Inspiring Veteran|ELD|2
[CN2 Not In Normal Slots]
Adriana's Valor
Assemble the Rank and Vile
Echoing Boon
#Emissary's Ploy
Hired Heist
Hold the Perimeter
Hymn of the Wilds
Incendiary Dissent
Natural Unity
#Sovereign's Realm
Summoner's Bond
Weight Advantage
Kaya, Ghost Assassin|CN2|2
[CN2 Foil Kaya]
Kaya, Ghost Assassin|CN2|2
[JMP Above the Clouds 1] [JMP Above the Clouds 1]
1 Warden of Evos Isle|JMP 1 Warden of Evos Isle|JMP
1 Inniaz, the Gale Force|JMP 1 Inniaz, the Gale Force|JMP

View File

@@ -0,0 +1,9 @@
Name:Custodi Peacekeeper
ManaCost:2 W
Types:Creature Human Cleric
PT:2/3
Draft:Reveal CARDNAME as you draft it.
Draft:Note how many cards you've drafted this draft round, including CARDNAME.
A:AB$ Tap | Cost$ W T | ValidTgts$ Creature.powerLEX | TgtPrompt$ Tap target creature with power less than or equal to the highest number you noted for cards named Custodi Peacekeeper. | SpellDescription$ Tap target creature with power less than or equal to the highest number you noted for cards named Custodi Peacekeeper.
SVar:X:Count$DraftNotesHighest.Custodi Peacekeeper
Oracle:Reveal Custodi Peacekeeper as you draft it and note how many cards youve drafted this draft round, including Custodi Peacekeeper.\n{W}, {T}: Tap target creature with power less than or equal to the highest number you noted for cards named Custodi Peacekeeper.

View File

@@ -0,0 +1,8 @@
Name:Garbage Fire
ManaCost:2 R
Types:Instant
Draft:Reveal CARDNAME as you draft it.
Draft:Note how many cards you've drafted this draft round, including CARDNAME.
A:SP$ DealDamage | ValidTgts$ Creature | NumDmg$ X | Description$ CARDNAME deals damage to target creature equal to the highest number you noted for cards named Garbage Fire.
SVar:X:Count$DraftNotesHighest.Garbage Fire
Oracle:Reveal Garbage Fire as you draft it and note how many cards youve drafted this draft round, including Garbage Fire.\nGarbage Fire deals damage to target creature equal to the highest number you noted for cards named Garbage Fire.

View File

@@ -0,0 +1,9 @@
Name:Lurking Automaton
ManaCost:5
Types:Artifact Creature Construct
PT:0/0
Draft:Reveal CARDNAME as you draft it.
Draft:Note how many cards you've drafted this draft round, including CARDNAME.
K:etbCounter:P1P1:X:no Condition:CARDNAME enters the battlefield with X +1/+1 counters on it, where X is the highest number you noted for cards named Lurking Automaton.
SVar:X:Count$DraftNotesHighest.Lurking Automaton
Oracle:Reveal Lurking Automaton as you draft it and note how many cards youve drafted this draft round, including Lurking Automaton.\nLurking Automaton enters the battlefield with X +1/+1 counters on it, where X is the highest number you noted for cards named Lurking Automaton.

View File

@@ -0,0 +1,10 @@
Name:Pyretic Hunter
ManaCost:4 R
Types:Creature Elemental Cat
PT:0/0
Draft:Reveal CARDNAME as you draft it.
Draft:Note how many cards you've drafted this draft round, including CARDNAME.
K:etbCounter:P1P1:X:no Condition:CARDNAME enters the battlefield with X +1/+1 counters on it, where X is the highest number you noted for cards named Pyretic Hunter.
K:Menace
SVar:X:Count$DraftNotesHighest.Pyretic Hunter
Oracle:Reveal Pyretic Hunter as you draft it and note how many cards youve drafted this draft round, including Pyretic Hunter.\nMenace (This creature cant be blocked except by two or more creatures.)\nPyretic Hunter enters the battlefield with X +1/+1 counters on it, where X is the highest number you noted for cards named Pyretic Hunter.

View File

@@ -56,7 +56,7 @@
#55|He Who Hungers|R|CHK #55|He Who Hungers|R|CHK
#56|Ghostly Prison|U|CHK #56|Ghostly Prison|U|CHK
#57|Samurai of the Pale Curtain|U|CHK #57|Samurai of the Pale Curtain|U|CHK
#58|Soratami Mirror Guard|C|CHK #58|Soratami Mirror-Guard|C|CHK
#59|Reciprocate|U|CHK #59|Reciprocate|U|CHK
#60|Sensei's Divining Top|U|CHK #60|Sensei's Divining Top|U|CHK
#61|Frostwielder|C|CHK #61|Frostwielder|C|CHK
@@ -108,7 +108,7 @@
#107|Orochi Sustainer|C|CHK #107|Orochi Sustainer|C|CHK
#108|Blood Speaker|U|CHK #108|Blood Speaker|U|CHK
#109|Brutal Deceiver|C|CHK #109|Brutal Deceiver|C|CHK
#110|Ember Fist Zubera|C|CHK #110|Ember-Fist Zubera|C|CHK
#111|Kami of Old Stone|U|CHK #111|Kami of Old Stone|U|CHK
#112|Budoka Gardener|R|CHK #112|Budoka Gardener|R|CHK
#113|Indomitable Will|C|CHK #113|Indomitable Will|C|CHK
@@ -186,7 +186,7 @@
#185|Distress|C|CHK #185|Distress|C|CHK
#186|Myojin of Night's Reach|R|CHK #186|Myojin of Night's Reach|R|CHK
#187|Eerie Procession|U|CHK #187|Eerie Procession|U|CHK
#188|Battle Mad Ronin|C|CHK #188|Battle-Mad Ronin|C|CHK
#189|Cranial Extraction|R|CHK #189|Cranial Extraction|R|CHK
#190|Orochi Leafcaller|C|CHK #190|Orochi Leafcaller|C|CHK
#191|Ethereal Haze|C|CHK #191|Ethereal Haze|C|CHK

View File

@@ -5,7 +5,7 @@ Name=Conspiracy: Take the Crown
Code2=CN2 Code2=CN2
Type=Draft Type=Draft
BoosterCovers=3 BoosterCovers=3
Booster=10 Common:!fromSheet("CN2 Not In Normal Slots"), 3 Uncommon:!fromSheet("CN2 Not In Normal Slots"), 1 RareMythic:!fromSheet("CN2 Not In Normal Slots"), 1 fromSheet("CN2 Draft Matters") Booster=10 Common:!fromSheet("CN2 Draft Matters"), 3 Uncommon:!fromSheet("CN2 Draft Matters"), 1 RareMythic:!fromSheet("CN2 Draft Matters"), 1 fromSheet("CN2 Draft Matters")
AdditionalSheetForFoils=fromSheet("CN2 Foil Kaya") AdditionalSheetForFoils=fromSheet("CN2 Foil Kaya")
ScryfallCode=CN2 ScryfallCode=CN2
@@ -231,8 +231,30 @@ ScryfallCode=CN2
219 R Exotic Orchard @Steven Belledin 219 R Exotic Orchard @Steven Belledin
220 U Rogue's Passage @Christine Choi 220 U Rogue's Passage @Christine Choi
221 U Shimmering Grotto @Cliff Childs 221 U Shimmering Grotto @Cliff Childs
[promo]
222 M Kaya, Ghost Assassin @Chris Rallis 222 M Kaya, Ghost Assassin @Chris Rallis
[Draft Matters]
Adriana's Valor
Assemble the Rank and Vile
Custodi Peacekeeper
Echoing Boon
#Emissary's Ploy
Garbage Fire
Hired Heist
Hold the Perimeter
Hymn of the Wilds
Incendiary Dissent
Natural Unity
Pyretic Hunter
#Sovereign's Realm
Summoner's Bond
Weight Advantage
[Foil Kaya]
Kaya, Ghost Assassin|CN2|2
[tokens] [tokens]
w_1_1_soldier w_1_1_soldier
w_1_2_soldier_defender w_1_2_soldier_defender

View File

@@ -220,6 +220,33 @@ ScryfallCode=CNS
209 U Quicksand @Matt Stewart 209 U Quicksand @Matt Stewart
210 R Reflecting Pool @Fred Fields 210 R Reflecting Pool @Fred Fields
[Draft Matters]
#1 Advantageous Proclamation|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 Deal Broker|CNS
#1 Double Stroke|CNS
1 Immediate Action|CNS
#1 Iterative Analysis|CNS
#1 Lore Seeker|CNS
1 Lurking Automaton|CNS
1 Muzzio's Preparations|CNS
#1 Paliano, the High City|CNS
#1 Power Play|CNS
1 Secret Summoning|CNS
1 Secrets of Paradise|CNS
#1 Sentinel Dispatch|CNS
#1 Unexpected Potential|CNS
#1 Whispergear Sneak|CNS
#1 Worldknit|CNS
[tokens] [tokens]
w_1_1_spirit_flying w_1_1_spirit_flying
b_x_x_demon_flying b_x_x_demon_flying

View File

@@ -870,6 +870,7 @@ ttRemove4ofcard=Remove up to 4 of selected card to current deck
lblAddBasicLands=Add Basic Lands lblAddBasicLands=Add Basic Lands
ttAddBasicLands=Add basic lands to the deck ttAddBasicLands=Add basic lands to the deck
lblCardCatalog=Card Catalog lblCardCatalog=Card Catalog
lblEditorLog=Editor Log
lblJumptoprevioustable=Jump to previous table lblJumptoprevioustable=Jump to previous table
lblJumptopnexttable=Jump to next table lblJumptopnexttable=Jump to next table
lblJumptotextfilter=Jump to text filter lblJumptotextfilter=Jump to text filter

View File

@@ -62,7 +62,9 @@ public class BoosterDraft implements IBoosterDraft {
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<>();
private LimitedPlayer localPlayer; private final LimitedPlayer localPlayer;
private IDraftLog draftLog = null;
private String doublePickDuringDraft = ""; // "FirstPick" or "Always" private String doublePickDuringDraft = ""; // "FirstPick" or "Always"
protected int nextBoosterGroup = 0; protected int nextBoosterGroup = 0;
@@ -264,12 +266,16 @@ public class BoosterDraft implements IBoosterDraft {
} }
protected BoosterDraft(final LimitedPoolType draftType) { protected BoosterDraft(final LimitedPoolType draftType) {
this(draftType, N_PLAYERS);
}
protected BoosterDraft(final LimitedPoolType draftType, int numPlayers) {
this.draftFormat = draftType; this.draftFormat = draftType;
localPlayer = new LimitedPlayer(0); localPlayer = new LimitedPlayer(0, this);
players.add(localPlayer); players.add(localPlayer);
for (int i = 1; i < N_PLAYERS; i++) { for (int i = 1; i < numPlayers; i++) {
players.add(new LimitedPlayerAI(i)); players.add(new LimitedPlayerAI(i, this));
} }
} }
@@ -278,6 +284,16 @@ public class BoosterDraft implements IBoosterDraft {
return false; return false;
} }
@Override
public void setLogEntry(IDraftLog draftingProcess) {
draftLog = draftingProcess;
}
@Override
public IDraftLog getDraftLog() {
return draftLog;
}
private void setupCustomDraft(final CustomLimited draft) { private void setupCustomDraft(final CustomLimited draft) {
final ItemPool<PaperCard> dPool = draft.getCardPool(); final ItemPool<PaperCard> dPool = draft.getCardPool();
if (dPool == null) { if (dPool == null) {
@@ -374,6 +390,9 @@ public class BoosterDraft implements IBoosterDraft {
for (LimitedPlayer pl : this.players) { for (LimitedPlayer pl : this.players) {
pl.newPack(); pl.newPack();
} }
if (this.getDraftLog() != null) {
this.getDraftLog().addLogEntry("Round " + this.nextBoosterGroup + " is starting...");
}
this.currentBoosterSize = firstPlayer.packQueue.peek().size(); this.currentBoosterSize = firstPlayer.packQueue.peek().size();
return true; return true;
} }
@@ -387,6 +406,16 @@ public class BoosterDraft implements IBoosterDraft {
return decks; return decks;
} }
@Override
public LimitedPlayer[] getOpposingPlayers() {
return this.players.toArray(new LimitedPlayer[7]);
}
@Override
public LimitedPlayer getHumanPlayer() {
return this.localPlayer;
}
public void passPacks() { public void passPacks() {
// Alternate direction of pack passing // Alternate direction of pack passing
int adjust = this.nextBoosterGroup % 2 == 1 ? 1 : -1; int adjust = this.nextBoosterGroup % 2 == 1 ? 1 : -1;
@@ -404,7 +433,10 @@ public class BoosterDraft implements IBoosterDraft {
continue; continue;
if (!passingPack.isEmpty()) { if (!passingPack.isEmpty()) {
// TODO Canal Dredger for passing a pack with a single card in it 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; int passTo = (i + adjust + N_PLAYERS) % N_PLAYERS;
this.players.get(passTo).receiveOpenedPack(passingPack); this.players.get(passTo).receiveOpenedPack(passingPack);

View File

@@ -37,9 +37,13 @@ public interface IBoosterDraft {
boolean hasNextChoice(); boolean hasNextChoice();
boolean isRoundOver(); boolean isRoundOver();
Deck[] getDecks(); // size 7, all the computers decks Deck[] getDecks(); // size 7, all the computers decks
LimitedPlayer[] getOpposingPlayers(); // size 7, all the computers
LimitedPlayer getHumanPlayer();
CardEdition[] LAND_SET_CODE = { null }; CardEdition[] LAND_SET_CODE = { null };
String[] CUSTOM_RANKINGS_FILE = { null }; String[] CUSTOM_RANKINGS_FILE = { null };
boolean isPileDraft(); boolean isPileDraft();
void setLogEntry(IDraftLog draftingProcess);
IDraftLog getDraftLog();
} }

View File

@@ -0,0 +1,5 @@
package forge.gamemodes.limited;
public interface IDraftLog {
public void addLogEntry(String message);
}

View File

@@ -1,14 +1,14 @@
package forge.gamemodes.limited; package forge.gamemodes.limited;
import java.util.LinkedList; import com.google.common.collect.Iterables;
import java.util.List; import com.google.common.collect.Lists;
import java.util.Queue;
//import com.google.common.collect.Lists;
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.item.PaperCard; import forge.item.PaperCard;
import forge.util.TextUtil;
import java.util.*;
//import forge.gamemodes.limited.powers.DraftPower; //import forge.gamemodes.limited.powers.DraftPower;
public class LimitedPlayer { public class LimitedPlayer {
@@ -21,31 +21,43 @@ public class LimitedPlayer {
protected Queue<List<PaperCard>> packQueue; protected Queue<List<PaperCard>> packQueue;
protected Queue<List<PaperCard>> unopenedPacks; protected Queue<List<PaperCard>> unopenedPacks;
// WIP - Draft Matters cards private static final int CantDraftThisRound = 1;
/* private static final int SpyNextCardDrafted = 1 << 1;
private static int CantDraftThisRound = 1, private static final int ReceiveLastCard = 1 << 2;
SpyNextCardDrafted = 1 << 1, private static final int CanRemoveAfterDraft = 1 << 3;
ReceiveLastCard = 1 << 2, private static final int CanTradeAfterDraft = 1 << 4;
CanRemoveAfterDraft = 1 << 3,
CanTradeAfterDraft = 1 << 4;
private static int MAXFLAGS = CantDraftThisRound | ReceiveLastCard | CanRemoveAfterDraft | SpyNextCardDrafted private static final int MAXFLAGS = CantDraftThisRound | ReceiveLastCard | CanRemoveAfterDraft | SpyNextCardDrafted
| CanTradeAfterDraft; | CanTradeAfterDraft;
private final int playerFlags = 0;
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 Map<DraftPower, Integer> powers = new HashMap<>();
private List<PaperCard> revealed = Lists.newArrayList(); IBoosterDraft draft = null;
private Map<String, List<Object>> noted = new HashMap<>();
private Map<DraftPower, Integer> powers = new HashMap<>();
*/
public LimitedPlayer(int seatingOrder) { public LimitedPlayer(int seatingOrder, IBoosterDraft draft) {
order = seatingOrder; order = seatingOrder;
deck = new Deck(); deck = new Deck();
packQueue = new LinkedList<>(); packQueue = new LinkedList<>();
unopenedPacks = new LinkedList<>(); unopenedPacks = new LinkedList<>();
this.draft = draft;
}
public Map<String, List<String>> getDraftNotes() {
return noted;
}
public Map<String, String> getSerializedDraftNotes() {
Map<String, String> serialized = new HashMap<>();
for (Map.Entry<String, List<String>> entry : noted.entrySet()) {
serialized.put(entry.getKey(), TextUtil.join(entry.getValue(), ","));
}
return serialized;
} }
public PaperCard chooseCard() { public PaperCard chooseCard() {
@@ -72,16 +84,38 @@ public class LimitedPlayer {
pool.add(bestPick); pool.add(bestPick);
draftedThisRound++; draftedThisRound++;
// TODO Note Lurking Automaton if (bestPick.getRules().getMainPart().getDraftActions() == null) {
return true;
}
// Draft Actions
Iterable<String> draftActions = bestPick.getRules().getMainPart().getDraftActions();
if (Iterables.contains(draftActions, "Reveal CARDNAME as you draft it.")) {
revealed.add(bestPick);
if (Iterables.contains(draftActions, "Note how many cards you've drafted this draft round, including CARDNAME.")) {
List<String> note = noted.computeIfAbsent(bestPick.getName(), k -> Lists.newArrayList());
note.add(String.valueOf(draftedThisRound));
addLog(name() + " revealed " + bestPick.getName() + " and noted " + draftedThisRound + " cards drafted this round.");
} else {
addLog(name() + " revealed " + bestPick.getName() + " as they drafted it.");
}
}
// Colors
// TODO Note Paliano, the High City // TODO Note Paliano, the High City
// TODO Note Aether Searcher // TODO Note Regicide
// TODO Note Custodi Peacepeeper
// TODO Note Paliano Vanguard // TODO Note Paliano Vanguard
// TODO Note Garbage Fire // TODO Note Aether Searcher (for the next card)
return true; return true;
} }
public void addLog(String message) {
this.draft.getDraftLog().addLogEntry(message);
}
public List<PaperCard> nextChoice() { public List<PaperCard> nextChoice() {
return packQueue.peek(); return packQueue.peek();
} }
@@ -107,6 +141,14 @@ public class LimitedPlayer {
packQueue.add(pack); packQueue.add(pack);
} }
public String name() {
if (this instanceof LimitedPlayerAI) {
return "Player[" + order + "]";
}
return "You";
}
/* /*
public void addSingleBoosterPack(boolean random) { public void addSingleBoosterPack(boolean random) {
// TODO Lore Seeker // TODO Lore Seeker

View File

@@ -12,8 +12,8 @@ import forge.localinstance.properties.ForgePreferences;
public class LimitedPlayerAI extends LimitedPlayer { public class LimitedPlayerAI extends LimitedPlayer {
protected DeckColors deckCols; protected DeckColors deckCols;
public LimitedPlayerAI(int seatingOrder) { public LimitedPlayerAI(int seatingOrder, BoosterDraft draft) {
super(seatingOrder); super(seatingOrder, draft);
deckCols = new DeckColors(); deckCols = new DeckColors();
} }