Draft Cubes rework (better cube from deck, dynamic data, better errors processing, actual MTGO Vintage Cube) (#13705)

- GUI, table: added dynamic data support for Cube Types (no more depends on server's config names, part of #12050);
- server: replace multiple MTGO Vintage Cubes by single cube, updated to April 2025 (part of #12050);
- server: fixed table freeze on starting error (related to #11285);
- GUI, table: added better support of Cube From Deck (client/server side errors, additional info about loaded cards, etc);
This commit is contained in:
Oleg Agafonov 2025-05-31 20:15:31 +04:00 committed by GitHub
parent 2034b3fe59
commit 3d45a24959
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 755 additions and 61 deletions

View file

@ -43,6 +43,8 @@ public class NewTournamentDialog extends MageDialog {
// it's ok to have 4 players at the screen, 6 is fine for big screens too
private static final int MAX_WORKABLE_PLAYERS_PER_GAME = 6;
private static final String CUBE_FROM_DECK_NAME = "Cube From Deck";
// temp settings on loading players list
private final List<PlayerType> prefPlayerTypes = new ArrayList<>();
private final List<Integer> prefPlayerSkills = new ArrayList<>();
@ -712,6 +714,21 @@ public class NewTournamentDialog extends MageDialog {
}
}
// cube from deck uses weird choose logic from combobox select, so players can forget or cancel it
if (tournamentType.isDraft()
&& tOptions.getLimitedOptions().getDraftCubeName() != null
&& tOptions.getLimitedOptions().getDraftCubeName().contains(CUBE_FROM_DECK_NAME)) {
if (tOptions.getLimitedOptions().getCubeFromDeck() == null || tOptions.getLimitedOptions().getCubeFromDeck().getCards().isEmpty()) {
JOptionPane.showMessageDialog(
MageFrame.getDesktop(),
"Found empty cube. You must choose Cube From Deck again and select existing deck file.",
"Warning",
JOptionPane.WARNING_MESSAGE
);
return;
}
}
// save last settings
onSaveSettings(0, tOptions);
@ -826,7 +843,7 @@ public class NewTournamentDialog extends MageDialog {
private void cbDraftCubeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbDraftCubeActionPerformed
cubeFromDeckFilename = "";
if (cbDraftCube.getSelectedItem().toString().equals("Cube From Deck")) {
if (cbDraftCube.getSelectedItem().toString().startsWith(CUBE_FROM_DECK_NAME)) {
cubeFromDeckFilename = playerLoadDeck();
}
}//GEN-LAST:event_cbDraftCubeActionPerformed

View file

@ -191,15 +191,15 @@
}
public void updateDraft(DraftView draftView) {
if (draftView.getSets().size() != 3) {
if (draftView.getSetNames().size() != 3) {
// Random draft - TODO: can we access the type of draft here?
this.editPack1.setText("Random Boosters");
this.editPack2.setText("Random Boosters");
this.editPack3.setText("Random Boosters");
} else {
this.editPack1.setText(String.format("%s - %s", draftView.getSetCodes().get(0), draftView.getSets().get(0)));
this.editPack2.setText(String.format("%s - %s", draftView.getSetCodes().get(1), draftView.getSets().get(1)));
this.editPack3.setText(String.format("%s - %s", draftView.getSetCodes().get(2), draftView.getSets().get(2)));
this.editPack1.setText(draftView.getBoosterInfo(0));
this.editPack2.setText(draftView.getBoosterInfo(1));
this.editPack3.setText(draftView.getBoosterInfo(2));
}
// scroll too long text to the start

View file

@ -1,50 +1,63 @@
package mage.view;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import mage.cards.ExpansionSet;
import mage.game.draft.Draft;
import mage.game.draft.DraftCube;
import mage.game.draft.DraftPlayer;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author BetaSteward_at_googlemail.com
* @author BetaSteward_at_googlemail.com, JayDi85
*/
public class DraftView implements Serializable {
private static final long serialVersionUID = 1L;
private final List<String> sets = new ArrayList<>();
private final List<String> setNames = new ArrayList<>();
private final List<String> setCodes = new ArrayList<>();
private final int boosterNum; // starts with 1
private final int cardNum; // starts with 1
private final boolean isCube;
private final List<String> players = new ArrayList<>();
public DraftView(Draft draft) {
if (draft.getDraftCube() != null) {
this.isCube = draft.getDraftCube() != null;
if (this.isCube) {
for (int i = 0; i < draft.getNumberBoosters(); i++) {
DraftCube cube = draft.getDraftCube();
sets.add(cube.getName());
setNames.add(cube.getName());
setCodes.add(cube.getCode());
}
} else {
for (ExpansionSet set: draft.getSets()) {
sets.add(set.getName());
for (ExpansionSet set : draft.getSets()) {
setNames.add(set.getName());
setCodes.add(set.getCode());
}
}
this.boosterNum = draft.getBoosterNum();
this.cardNum = draft.getCardNum();
for(DraftPlayer draftPlayer :draft.getPlayers()) {
for (DraftPlayer draftPlayer : draft.getPlayers()) {
players.add(draftPlayer.getPlayer().getName());
}
}
public List<String> getSets() {
return sets;
public String getBoosterInfo(int index) {
if (index >= this.setCodes.size() || this.setCodes.size() != this.setNames.size()) {
return "error";
}
if (this.isCube) {
return this.setNames.get(index);
} else {
return String.join(" - ", this.setCodes.get(index), this.setNames.get(index));
}
}
public List<String> getSetNames() {
return setNames;
}
public List<String> getSetCodes() {

View file

@ -6,12 +6,15 @@ import mage.cards.decks.DeckCardLists;
import mage.game.draft.DraftCube;
/**
* @author spjspj
* @author spjspj, JayDi85
*/
public class CubeFromDeck extends DraftCube {
/**
* Calls on table create, can use any names
*/
public CubeFromDeck(Deck cubeFromDeck) {
super("Cube From Deck");
this();
if (cubeFromDeck == null) {
return;
@ -21,5 +24,16 @@ public class CubeFromDeck extends DraftCube {
for (DeckCardInfo card : cards.getCards()) {
cubeCards.add(new CardIdentity(card.getCardName(), card.getSetCode(), card.getCardNumber()));
}
// add useful info about cubes, but don't print user defined data like deck name due security reasons
this.setUpdateInfo(String.format("%d cards", cubeCards.size()));
}
/**
* Calls on server's startng, must use default name - that's name will see all users after connection
*/
public CubeFromDeck() {
// don't change default name - new tourney dialog use it to choose a cube's deck
super("Cube From Deck", "your custom cube", 0, 0, 0);
}
}

View file

@ -0,0 +1,559 @@
package mage.tournament.cubes;
import mage.game.draft.DraftCube;
/**
* MTGO Vintage Cube, latest version
* <p>
* <a href="https://scryfall.com/cubes/vintage">data source</a>
*
* @author JayDi85
*/
public class MTGOVintageCube extends DraftCube {
public MTGOVintageCube() {
super("MTGO Vintage Cube", "", 2025, 4, 23);
cubeCards.add(new CardIdentity("\"Name Sticker\" Goblin", ""));
cubeCards.add(new CardIdentity("Abrade", ""));
cubeCards.add(new CardIdentity("Abrupt Decay", ""));
cubeCards.add(new CardIdentity("Adanto Vanguard", ""));
cubeCards.add(new CardIdentity("Adeline, Resplendent Cathar", ""));
cubeCards.add(new CardIdentity("Aether Spellbomb", ""));
cubeCards.add(new CardIdentity("Aetherflux Reservoir", ""));
cubeCards.add(new CardIdentity("Agatha's Soul Cauldron", ""));
cubeCards.add(new CardIdentity("Akal Pakal, First Among Equals", ""));
cubeCards.add(new CardIdentity("Ancestral Recall", ""));
cubeCards.add(new CardIdentity("Ancient Tomb", ""));
cubeCards.add(new CardIdentity("Animate Dead", ""));
cubeCards.add(new CardIdentity("Arbor Elf", ""));
cubeCards.add(new CardIdentity("Arc Trail", ""));
cubeCards.add(new CardIdentity("Archon of Cruelty", ""));
cubeCards.add(new CardIdentity("Arid Mesa", ""));
cubeCards.add(new CardIdentity("Arwen, Mortal Queen", ""));
cubeCards.add(new CardIdentity("Ashen Rider", ""));
cubeCards.add(new CardIdentity("Assimilation Aegis", ""));
cubeCards.add(new CardIdentity("Atraxa, Grand Unifier", ""));
cubeCards.add(new CardIdentity("Augur of Autumn", ""));
cubeCards.add(new CardIdentity("Avacyn's Pilgrim", ""));
cubeCards.add(new CardIdentity("Aven Interrupter", ""));
cubeCards.add(new CardIdentity("Badlands", ""));
cubeCards.add(new CardIdentity("Balance", ""));
cubeCards.add(new CardIdentity("Baleful Mastery", ""));
cubeCards.add(new CardIdentity("Baleful Strix", ""));
cubeCards.add(new CardIdentity("Basalt Monolith", ""));
cubeCards.add(new CardIdentity("Batterskull", ""));
cubeCards.add(new CardIdentity("Bayou", ""));
cubeCards.add(new CardIdentity("Benevolent Bodyguard", ""));
cubeCards.add(new CardIdentity("Beseech the Mirror", ""));
cubeCards.add(new CardIdentity("Birds of Paradise", ""));
cubeCards.add(new CardIdentity("Birgi, God of Storytelling", ""));
cubeCards.add(new CardIdentity("Bitter Triumph", ""));
cubeCards.add(new CardIdentity("Black Lotus", ""));
cubeCards.add(new CardIdentity("Blackcleave Cliffs", ""));
cubeCards.add(new CardIdentity("Blade Splicer", ""));
cubeCards.add(new CardIdentity("Blightsteel Colossus", ""));
cubeCards.add(new CardIdentity("Blood Crypt", ""));
cubeCards.add(new CardIdentity("Bloodstained Mire", ""));
cubeCards.add(new CardIdentity("Bloodtithe Harvester", ""));
cubeCards.add(new CardIdentity("Blooming Marsh", ""));
cubeCards.add(new CardIdentity("Bolas's Citadel", ""));
cubeCards.add(new CardIdentity("Bone Shards", ""));
cubeCards.add(new CardIdentity("Bonecrusher Giant", ""));
cubeCards.add(new CardIdentity("Bonehoard Dracosaur", ""));
cubeCards.add(new CardIdentity("Boseiju, Who Endures", ""));
cubeCards.add(new CardIdentity("Botanical Sanctum", ""));
cubeCards.add(new CardIdentity("Brain Freeze", ""));
cubeCards.add(new CardIdentity("Brainstorm", ""));
cubeCards.add(new CardIdentity("Brazen Borrower", ""));
cubeCards.add(new CardIdentity("Breeding Pool", ""));
cubeCards.add(new CardIdentity("Bring to Light", ""));
cubeCards.add(new CardIdentity("Bristly Bill, Spine Sower", ""));
cubeCards.add(new CardIdentity("Broadside Bombardiers", ""));
cubeCards.add(new CardIdentity("Bubbling Muck", ""));
cubeCards.add(new CardIdentity("Burst Lightning", ""));
cubeCards.add(new CardIdentity("Cabal Ritual", ""));
cubeCards.add(new CardIdentity("Candelabra of Tawnos", ""));
cubeCards.add(new CardIdentity("Carnage Interpreter", ""));
cubeCards.add(new CardIdentity("Cathar Commando", ""));
cubeCards.add(new CardIdentity("Caustic Bronco", ""));
cubeCards.add(new CardIdentity("Celestial Colonnade", ""));
cubeCards.add(new CardIdentity("Chain Lightning", ""));
cubeCards.add(new CardIdentity("Chandra, Torch of Defiance", ""));
cubeCards.add(new CardIdentity("Channel", ""));
cubeCards.add(new CardIdentity("Chart a Course", ""));
cubeCards.add(new CardIdentity("Chromatic Star", ""));
cubeCards.add(new CardIdentity("Chrome Host Seedshark", ""));
cubeCards.add(new CardIdentity("Chrome Mox", ""));
cubeCards.add(new CardIdentity("City of Traitors", ""));
cubeCards.add(new CardIdentity("Coalition Relic", ""));
cubeCards.add(new CardIdentity("Collective Brutality", ""));
cubeCards.add(new CardIdentity("Collector's Cage", ""));
cubeCards.add(new CardIdentity("Commercial District", ""));
cubeCards.add(new CardIdentity("Concealed Courtyard", ""));
cubeCards.add(new CardIdentity("Concealing Curtains", ""));
cubeCards.add(new CardIdentity("Consider", ""));
cubeCards.add(new CardIdentity("Containment Priest", ""));
cubeCards.add(new CardIdentity("Copperline Gorge", ""));
cubeCards.add(new CardIdentity("Corpse Dance", ""));
cubeCards.add(new CardIdentity("Council's Judgment", ""));
cubeCards.add(new CardIdentity("Counterspell", ""));
cubeCards.add(new CardIdentity("Courser of Kruphix", ""));
cubeCards.add(new CardIdentity("Coveted Jewel", ""));
cubeCards.add(new CardIdentity("Craterhoof Behemoth", ""));
cubeCards.add(new CardIdentity("Creeping Tar Pit", ""));
cubeCards.add(new CardIdentity("Crucible of Worlds", ""));
cubeCards.add(new CardIdentity("Cruel Ultimatum", ""));
cubeCards.add(new CardIdentity("Cryptic Coat", ""));
cubeCards.add(new CardIdentity("Cryptic Command", ""));
cubeCards.add(new CardIdentity("Currency Converter", ""));
cubeCards.add(new CardIdentity("Cut Down", ""));
cubeCards.add(new CardIdentity("Dack Fayden", ""));
cubeCards.add(new CardIdentity("Damn", ""));
cubeCards.add(new CardIdentity("Dark Confidant", ""));
cubeCards.add(new CardIdentity("Dark Ritual", ""));
cubeCards.add(new CardIdentity("Darkslick Shores", ""));
cubeCards.add(new CardIdentity("Dauthi Voidwalker", ""));
cubeCards.add(new CardIdentity("Daze", ""));
cubeCards.add(new CardIdentity("Death-Greeter's Champion", ""));
cubeCards.add(new CardIdentity("Deep-Cavern Bat", ""));
cubeCards.add(new CardIdentity("Delayed Blast Fireball", ""));
cubeCards.add(new CardIdentity("Delighted Halfling", ""));
cubeCards.add(new CardIdentity("Demonic Tutor", ""));
cubeCards.add(new CardIdentity("Dig Through Time", ""));
cubeCards.add(new CardIdentity("Dismember", ""));
cubeCards.add(new CardIdentity("Displacer Kitten", ""));
cubeCards.add(new CardIdentity("Dragon's Rage Channeler", ""));
cubeCards.add(new CardIdentity("Dreadhorde Arcanist", ""));
cubeCards.add(new CardIdentity("Dream Halls", ""));
cubeCards.add(new CardIdentity("Duelist of the Mind", ""));
cubeCards.add(new CardIdentity("Duress", ""));
cubeCards.add(new CardIdentity("Echo of Eons", ""));
cubeCards.add(new CardIdentity("Elegant Parlor", ""));
cubeCards.add(new CardIdentity("Elemental Eruption", ""));
cubeCards.add(new CardIdentity("Elite Spellbinder", ""));
cubeCards.add(new CardIdentity("Elspeth, Knight-Errant", ""));
cubeCards.add(new CardIdentity("Elvish Mystic", ""));
cubeCards.add(new CardIdentity("Embereth Shieldbreaker", ""));
cubeCards.add(new CardIdentity("Emrakul, the Aeons Torn", ""));
cubeCards.add(new CardIdentity("Endurance", ""));
cubeCards.add(new CardIdentity("Enlightened Tutor", ""));
cubeCards.add(new CardIdentity("Entomb", ""));
cubeCards.add(new CardIdentity("Ephemerate", ""));
cubeCards.add(new CardIdentity("Escape to the Wilds", ""));
cubeCards.add(new CardIdentity("Esika's Chariot", ""));
cubeCards.add(new CardIdentity("Esper Sentinel", ""));
cubeCards.add(new CardIdentity("Etali, Primal Conqueror", ""));
cubeCards.add(new CardIdentity("Eternal Witness", ""));
cubeCards.add(new CardIdentity("Eureka", ""));
cubeCards.add(new CardIdentity("Everflowing Chalice", ""));
cubeCards.add(new CardIdentity("Evolved Sleeper", ""));
cubeCards.add(new CardIdentity("Exhume", ""));
cubeCards.add(new CardIdentity("Exploration", ""));
cubeCards.add(new CardIdentity("Expressive Iteration", ""));
cubeCards.add(new CardIdentity("Fable of the Mirror-Breaker", ""));
cubeCards.add(new CardIdentity("Faerie Mastermind", ""));
cubeCards.add(new CardIdentity("Faithless Looting", ""));
cubeCards.add(new CardIdentity("Fallen Shinobi", ""));
cubeCards.add(new CardIdentity("Fastbond", ""));
cubeCards.add(new CardIdentity("Fatal Push", ""));
cubeCards.add(new CardIdentity("Fiery Confluence", ""));
cubeCards.add(new CardIdentity("Fiery Islet", ""));
cubeCards.add(new CardIdentity("Figure of Destiny", ""));
cubeCards.add(new CardIdentity("Fire Covenant", ""));
cubeCards.add(new CardIdentity("Fireblast", ""));
cubeCards.add(new CardIdentity("Firebolt", ""));
cubeCards.add(new CardIdentity("Flame Slash", ""));
cubeCards.add(new CardIdentity("Flametongue Kavu", ""));
cubeCards.add(new CardIdentity("Flash", ""));
cubeCards.add(new CardIdentity("Flickerwisp", ""));
cubeCards.add(new CardIdentity("Flooded Strand", ""));
cubeCards.add(new CardIdentity("Force of Negation", ""));
cubeCards.add(new CardIdentity("Force of Will", ""));
cubeCards.add(new CardIdentity("Forensic Gadgeteer", ""));
cubeCards.add(new CardIdentity("Forth Eorlingas!", ""));
cubeCards.add(new CardIdentity("Fractured Identity", ""));
cubeCards.add(new CardIdentity("Frantic Search", ""));
cubeCards.add(new CardIdentity("Fury", ""));
cubeCards.add(new CardIdentity("Gaea's Cradle", ""));
cubeCards.add(new CardIdentity("Garruk Wildspeaker", ""));
cubeCards.add(new CardIdentity("Generous Ent", ""));
cubeCards.add(new CardIdentity("Generous Plunderer", ""));
cubeCards.add(new CardIdentity("Gitaxian Probe", ""));
cubeCards.add(new CardIdentity("Giver of Runes", ""));
cubeCards.add(new CardIdentity("Gix, Yawgmoth Praetor", ""));
cubeCards.add(new CardIdentity("Glimmer Lens", ""));
cubeCards.add(new CardIdentity("Goblin Rabblemaster", ""));
cubeCards.add(new CardIdentity("Godless Shrine", ""));
cubeCards.add(new CardIdentity("Goldspan Dragon", ""));
cubeCards.add(new CardIdentity("Goldvein Hydra", ""));
cubeCards.add(new CardIdentity("Goryo's Vengeance", ""));
cubeCards.add(new CardIdentity("Grave Titan", ""));
cubeCards.add(new CardIdentity("Graveyard Trespasser", ""));
cubeCards.add(new CardIdentity("Green Sun's Zenith", ""));
cubeCards.add(new CardIdentity("Grief", ""));
cubeCards.add(new CardIdentity("Grim Lavamancer", ""));
cubeCards.add(new CardIdentity("Grim Monolith", ""));
cubeCards.add(new CardIdentity("Griselbrand", ""));
cubeCards.add(new CardIdentity("Grist, the Hunger Tide", ""));
cubeCards.add(new CardIdentity("Gruff Triplets", ""));
cubeCards.add(new CardIdentity("Guardian Scalelord", ""));
cubeCards.add(new CardIdentity("Gut, True Soul Zealot", ""));
cubeCards.add(new CardIdentity("Hallowed Fountain", ""));
cubeCards.add(new CardIdentity("Hard Evidence", ""));
cubeCards.add(new CardIdentity("Harvester of Misery", ""));
cubeCards.add(new CardIdentity("Haywire Mite", ""));
cubeCards.add(new CardIdentity("Headliner Scarlett", ""));
cubeCards.add(new CardIdentity("Hedge Maze", ""));
cubeCards.add(new CardIdentity("Helm of Awakening", ""));
cubeCards.add(new CardIdentity("Hero of Bladehold", ""));
cubeCards.add(new CardIdentity("Hexdrinker", ""));
cubeCards.add(new CardIdentity("High Tide", ""));
cubeCards.add(new CardIdentity("Highway Robbery", ""));
cubeCards.add(new CardIdentity("Horizon Canopy", ""));
cubeCards.add(new CardIdentity("Hostile Investigator", ""));
cubeCards.add(new CardIdentity("Huatli, Poet of Unity", ""));
cubeCards.add(new CardIdentity("Hullbreacher", ""));
cubeCards.add(new CardIdentity("Hymn to Tourach", ""));
cubeCards.add(new CardIdentity("Ignoble Hierarch", ""));
cubeCards.add(new CardIdentity("Imperial Seal", ""));
cubeCards.add(new CardIdentity("Indatha Triome", ""));
cubeCards.add(new CardIdentity("Infernal Grasp", ""));
cubeCards.add(new CardIdentity("Inquisition of Kozilek", ""));
cubeCards.add(new CardIdentity("Inspiring Vantage", ""));
cubeCards.add(new CardIdentity("Inti, Seneschal of the Sun", ""));
cubeCards.add(new CardIdentity("Intrepid Adversary", ""));
cubeCards.add(new CardIdentity("Invigorate", ""));
cubeCards.add(new CardIdentity("Jace Reawakened", ""));
cubeCards.add(new CardIdentity("Jace, the Mind Sculptor", ""));
cubeCards.add(new CardIdentity("Jace, Vryn's Prodigy", ""));
cubeCards.add(new CardIdentity("Jetmir's Garden", ""));
cubeCards.add(new CardIdentity("Kaervek, the Punisher", ""));
cubeCards.add(new CardIdentity("Kaito Shizuki", ""));
cubeCards.add(new CardIdentity("Kaldra Compleat", ""));
cubeCards.add(new CardIdentity("Kappa Cannoneer", ""));
cubeCards.add(new CardIdentity("Karakas", ""));
cubeCards.add(new CardIdentity("Karn, Scion of Urza", ""));
cubeCards.add(new CardIdentity("Ketria Triome", ""));
cubeCards.add(new CardIdentity("Kinnan, Bonder Prodigy", ""));
cubeCards.add(new CardIdentity("Kitesail Larcenist", ""));
cubeCards.add(new CardIdentity("Kolaghan's Command", ""));
cubeCards.add(new CardIdentity("Kozilek, Butcher of Truth", ""));
cubeCards.add(new CardIdentity("Kutzil, Malamet Exemplar", ""));
cubeCards.add(new CardIdentity("Laelia, the Blade Reforged", ""));
cubeCards.add(new CardIdentity("Lava Dart", ""));
cubeCards.add(new CardIdentity("Lazav, Wearer of Faces", ""));
cubeCards.add(new CardIdentity("Ledger Shredder", ""));
cubeCards.add(new CardIdentity("Legion Extruder", ""));
cubeCards.add(new CardIdentity("Legolas's Quick Reflexes", ""));
cubeCards.add(new CardIdentity("Leonin Relic-Warder", ""));
cubeCards.add(new CardIdentity("Leovold, Emissary of Trest", ""));
cubeCards.add(new CardIdentity("Leyline Binding", ""));
cubeCards.add(new CardIdentity("Library of Alexandria", ""));
cubeCards.add(new CardIdentity("Life // Death", ""));
cubeCards.add(new CardIdentity("Lightning Bolt", ""));
cubeCards.add(new CardIdentity("Liliana of the Veil", ""));
cubeCards.add(new CardIdentity("Lim-Dul's Vault", ""));
cubeCards.add(new CardIdentity("Lingering Souls", ""));
cubeCards.add(new CardIdentity("Lion Sash", ""));
cubeCards.add(new CardIdentity("Lion's Eye Diamond", ""));
cubeCards.add(new CardIdentity("Llanowar Elves", ""));
cubeCards.add(new CardIdentity("Long Goodbye", ""));
cubeCards.add(new CardIdentity("Loran of the Third Path", ""));
cubeCards.add(new CardIdentity("Lotus Cobra", ""));
cubeCards.add(new CardIdentity("Lotus Field", ""));
cubeCards.add(new CardIdentity("Lotus Petal", ""));
cubeCards.add(new CardIdentity("Luminarch Aspirant", ""));
cubeCards.add(new CardIdentity("Lurrus of the Dream-Den", ""));
cubeCards.add(new CardIdentity("Lush Portico", ""));
cubeCards.add(new CardIdentity("Lorien Revealed", ""));
cubeCards.add(new CardIdentity("Magda, Brazen Outlaw", ""));
cubeCards.add(new CardIdentity("Magda, the Hoardmaster", ""));
cubeCards.add(new CardIdentity("Magma Opus", ""));
cubeCards.add(new CardIdentity("Malcolm, Alluring Scoundrel", ""));
cubeCards.add(new CardIdentity("Mana Confluence", ""));
cubeCards.add(new CardIdentity("Mana Crypt", ""));
cubeCards.add(new CardIdentity("Mana Drain", ""));
cubeCards.add(new CardIdentity("Mana Leak", ""));
cubeCards.add(new CardIdentity("Mana Tithe", ""));
cubeCards.add(new CardIdentity("Mana Vault", ""));
cubeCards.add(new CardIdentity("Manamorphose", ""));
cubeCards.add(new CardIdentity("Manifold Key", ""));
cubeCards.add(new CardIdentity("Marsh Flats", ""));
cubeCards.add(new CardIdentity("Memory Jar", ""));
cubeCards.add(new CardIdentity("Memory Lapse", ""));
cubeCards.add(new CardIdentity("Meticulous Archive", ""));
cubeCards.add(new CardIdentity("Mind Stone", ""));
cubeCards.add(new CardIdentity("Mind Twist", ""));
cubeCards.add(new CardIdentity("Mind's Desire", ""));
cubeCards.add(new CardIdentity("Mine Collapse", ""));
cubeCards.add(new CardIdentity("Minsc & Boo, Timeless Heroes", ""));
cubeCards.add(new CardIdentity("Miscalculation", ""));
cubeCards.add(new CardIdentity("Mishra's Bauble", ""));
cubeCards.add(new CardIdentity("Mishra's Research Desk", ""));
cubeCards.add(new CardIdentity("Mishra's Workshop", ""));
cubeCards.add(new CardIdentity("Misty Rainforest", ""));
cubeCards.add(new CardIdentity("Mizzix's Mastery", ""));
cubeCards.add(new CardIdentity("Monastery Mentor", ""));
cubeCards.add(new CardIdentity("Monastery Swiftspear", ""));
cubeCards.add(new CardIdentity("Mother of Runes", ""));
cubeCards.add(new CardIdentity("Mox Diamond", ""));
cubeCards.add(new CardIdentity("Mox Emerald", ""));
cubeCards.add(new CardIdentity("Mox Jet", ""));
cubeCards.add(new CardIdentity("Mox Opal", ""));
cubeCards.add(new CardIdentity("Mox Pearl", ""));
cubeCards.add(new CardIdentity("Mox Ruby", ""));
cubeCards.add(new CardIdentity("Mox Sapphire", ""));
cubeCards.add(new CardIdentity("Mutagenic Growth", ""));
cubeCards.add(new CardIdentity("Myr Battlesphere", ""));
cubeCards.add(new CardIdentity("Mystic Confluence", ""));
cubeCards.add(new CardIdentity("Mystic Forge", ""));
cubeCards.add(new CardIdentity("Mystical Tutor", ""));
cubeCards.add(new CardIdentity("Narset, Parter of Veils", ""));
cubeCards.add(new CardIdentity("Natural Order", ""));
cubeCards.add(new CardIdentity("Nature's Claim", ""));
cubeCards.add(new CardIdentity("Necromancy", ""));
cubeCards.add(new CardIdentity("Nettlecyst", ""));
cubeCards.add(new CardIdentity("Nexus of Becoming", ""));
cubeCards.add(new CardIdentity("Night's Whisper", ""));
cubeCards.add(new CardIdentity("Nishoba Brawler", ""));
cubeCards.add(new CardIdentity("Nissa, Ascended Animist", ""));
cubeCards.add(new CardIdentity("Nissa, Who Shakes the World", ""));
cubeCards.add(new CardIdentity("Noble Hierarch", ""));
cubeCards.add(new CardIdentity("Nurturing Peatland", ""));
cubeCards.add(new CardIdentity("Oath of Druids", ""));
cubeCards.add(new CardIdentity("Oko, the Ringleader", ""));
cubeCards.add(new CardIdentity("Oko, Thief of Crowns", ""));
cubeCards.add(new CardIdentity("Oliphaunt", ""));
cubeCards.add(new CardIdentity("Omnath, Locus of Creation", ""));
cubeCards.add(new CardIdentity("Once Upon a Time", ""));
cubeCards.add(new CardIdentity("Orcish Bowmasters", ""));
cubeCards.add(new CardIdentity("Orcish Lumberjack", ""));
cubeCards.add(new CardIdentity("Ornery Tumblewagg", ""));
cubeCards.add(new CardIdentity("Otawara, Soaring City", ""));
cubeCards.add(new CardIdentity("Otharri, Suns' Glory", ""));
cubeCards.add(new CardIdentity("Oust", ""));
cubeCards.add(new CardIdentity("Outland Liberator", ""));
cubeCards.add(new CardIdentity("Overgrown Tomb", ""));
cubeCards.add(new CardIdentity("Palace Jailer", ""));
cubeCards.add(new CardIdentity("Palantir of Orthanc", ""));
cubeCards.add(new CardIdentity("Paradise Druid", ""));
cubeCards.add(new CardIdentity("Parallax Wave", ""));
cubeCards.add(new CardIdentity("Path to Exile", ""));
cubeCards.add(new CardIdentity("Pentad Prism", ""));
cubeCards.add(new CardIdentity("Pest Infestation", ""));
cubeCards.add(new CardIdentity("Phantasmal Image", ""));
cubeCards.add(new CardIdentity("Phantom Interference", ""));
cubeCards.add(new CardIdentity("Phyrexian Fleshgorger", ""));
cubeCards.add(new CardIdentity("Phyrexian Metamorph", ""));
cubeCards.add(new CardIdentity("Phyrexian Revoker", ""));
cubeCards.add(new CardIdentity("Pick Your Poison", ""));
cubeCards.add(new CardIdentity("Pillage the Bog", ""));
cubeCards.add(new CardIdentity("Plateau", ""));
cubeCards.add(new CardIdentity("Polluted Delta", ""));
cubeCards.add(new CardIdentity("Ponder", ""));
cubeCards.add(new CardIdentity("Portable Hole", ""));
cubeCards.add(new CardIdentity("Portal to Phyrexia", ""));
cubeCards.add(new CardIdentity("Portent", ""));
cubeCards.add(new CardIdentity("Preacher of the Schism", ""));
cubeCards.add(new CardIdentity("Preordain", ""));
cubeCards.add(new CardIdentity("Prismatic Ending", ""));
cubeCards.add(new CardIdentity("Prismatic Vista", ""));
cubeCards.add(new CardIdentity("Proft's Eidetic Memory", ""));
cubeCards.add(new CardIdentity("Pyrite Spellbomb", ""));
cubeCards.add(new CardIdentity("Pyrokinesis", ""));
cubeCards.add(new CardIdentity("Qasali Pridemage", ""));
cubeCards.add(new CardIdentity("Questing Beast", ""));
cubeCards.add(new CardIdentity("Raffine's Tower", ""));
cubeCards.add(new CardIdentity("Ragavan, Nimble Pilferer", ""));
cubeCards.add(new CardIdentity("Raging Ravine", ""));
cubeCards.add(new CardIdentity("Railway Brawler", ""));
cubeCards.add(new CardIdentity("Rain of Filth", ""));
cubeCards.add(new CardIdentity("Rampaging Raptor", ""));
cubeCards.add(new CardIdentity("Ramunap Excavator", ""));
cubeCards.add(new CardIdentity("Ranger Class", ""));
cubeCards.add(new CardIdentity("Raucous Theater", ""));
cubeCards.add(new CardIdentity("Raugrin Triome", ""));
cubeCards.add(new CardIdentity("Razorverge Thicket", ""));
cubeCards.add(new CardIdentity("Reanimate", ""));
cubeCards.add(new CardIdentity("Recurring Nightmare", ""));
cubeCards.add(new CardIdentity("Regrowth", ""));
cubeCards.add(new CardIdentity("Relic of Progenitus", ""));
cubeCards.add(new CardIdentity("Relic of Sauron", ""));
cubeCards.add(new CardIdentity("Remand", ""));
cubeCards.add(new CardIdentity("Reprieve", ""));
cubeCards.add(new CardIdentity("Restless Vents", ""));
cubeCards.add(new CardIdentity("Retrofitter Foundry", ""));
cubeCards.add(new CardIdentity("Rite of Flame", ""));
cubeCards.add(new CardIdentity("Robber of the Rich", ""));
cubeCards.add(new CardIdentity("Rofellos, Llanowar Emissary", ""));
cubeCards.add(new CardIdentity("Runaway Steam-Kin", ""));
cubeCards.add(new CardIdentity("Sacred Foundry", ""));
cubeCards.add(new CardIdentity("Saheeli, Sublime Artificer", ""));
cubeCards.add(new CardIdentity("Sail into the West", ""));
cubeCards.add(new CardIdentity("Samwise the Stouthearted", ""));
cubeCards.add(new CardIdentity("Sandstorm Salvager", ""));
cubeCards.add(new CardIdentity("Sanguine Evangelist", ""));
cubeCards.add(new CardIdentity("Savai Triome", ""));
cubeCards.add(new CardIdentity("Savannah", ""));
cubeCards.add(new CardIdentity("Scalding Tarn", ""));
cubeCards.add(new CardIdentity("Scavenging Ooze", ""));
cubeCards.add(new CardIdentity("Scrapwork Mutt", ""));
cubeCards.add(new CardIdentity("Scrubland", ""));
cubeCards.add(new CardIdentity("Seachrome Coast", ""));
cubeCards.add(new CardIdentity("Seasoned Pyromancer", ""));
cubeCards.add(new CardIdentity("Seething Song", ""));
cubeCards.add(new CardIdentity("Selfless Spirit", ""));
cubeCards.add(new CardIdentity("Sensei's Divining Top", ""));
cubeCards.add(new CardIdentity("Sentinel of the Nameless City", ""));
cubeCards.add(new CardIdentity("Serra Paragon", ""));
cubeCards.add(new CardIdentity("Serum Visions", ""));
cubeCards.add(new CardIdentity("Sevinne's Reclamation", ""));
cubeCards.add(new CardIdentity("Shadowspear", ""));
cubeCards.add(new CardIdentity("Shadowy Backstreet", ""));
cubeCards.add(new CardIdentity("Shallow Grave", ""));
cubeCards.add(new CardIdentity("Shelldock Isle", ""));
cubeCards.add(new CardIdentity("Sheoldred's Edict", ""));
cubeCards.add(new CardIdentity("Sheoldred, the Apocalypse", ""));
cubeCards.add(new CardIdentity("Shorikai, Genesis Engine", ""));
cubeCards.add(new CardIdentity("Show and Tell", ""));
cubeCards.add(new CardIdentity("Showdown of the Skalds", ""));
cubeCards.add(new CardIdentity("Silent Clearing", ""));
cubeCards.add(new CardIdentity("Skullclamp", ""));
cubeCards.add(new CardIdentity("Skyclave Apparition", ""));
cubeCards.add(new CardIdentity("Slickshot Show-Off", ""));
cubeCards.add(new CardIdentity("Smuggler's Copter", ""));
cubeCards.add(new CardIdentity("Smuggler's Surprise", ""));
cubeCards.add(new CardIdentity("Snap", ""));
cubeCards.add(new CardIdentity("Snapcaster Mage", ""));
cubeCards.add(new CardIdentity("Sneak Attack", ""));
cubeCards.add(new CardIdentity("Snuff Out", ""));
cubeCards.add(new CardIdentity("Sol Ring", ""));
cubeCards.add(new CardIdentity("Solitude", ""));
cubeCards.add(new CardIdentity("Soul-Guide Lantern", ""));
cubeCards.add(new CardIdentity("Soul-Scar Mage", ""));
cubeCards.add(new CardIdentity("Spara's Headquarters", ""));
cubeCards.add(new CardIdentity("Spell Pierce", ""));
cubeCards.add(new CardIdentity("Spellseeker", ""));
cubeCards.add(new CardIdentity("Spirebluff Canal", ""));
cubeCards.add(new CardIdentity("Staff of the Storyteller", ""));
cubeCards.add(new CardIdentity("Steam Vents", ""));
cubeCards.add(new CardIdentity("Steel Seraph", ""));
cubeCards.add(new CardIdentity("Stern Scolding", ""));
cubeCards.add(new CardIdentity("Stomping Ground", ""));
cubeCards.add(new CardIdentity("Stoneforge Mystic", ""));
cubeCards.add(new CardIdentity("Strip Mine", ""));
cubeCards.add(new CardIdentity("Student of Warfare", ""));
cubeCards.add(new CardIdentity("Subtlety", ""));
cubeCards.add(new CardIdentity("Sunbaked Canyon", ""));
cubeCards.add(new CardIdentity("Sunfall", ""));
cubeCards.add(new CardIdentity("Sword of the Meek", ""));
cubeCards.add(new CardIdentity("Swords to Plowshares", ""));
cubeCards.add(new CardIdentity("Sylvan Caryatid", ""));
cubeCards.add(new CardIdentity("Sylvan Library", ""));
cubeCards.add(new CardIdentity("Sylvan Safekeeper", ""));
cubeCards.add(new CardIdentity("Taiga", ""));
cubeCards.add(new CardIdentity("Talisman of Conviction", ""));
cubeCards.add(new CardIdentity("Talisman of Creativity", ""));
cubeCards.add(new CardIdentity("Talisman of Curiosity", ""));
cubeCards.add(new CardIdentity("Talisman of Dominance", ""));
cubeCards.add(new CardIdentity("Talisman of Indulgence", ""));
cubeCards.add(new CardIdentity("Talisman of Progress", ""));
cubeCards.add(new CardIdentity("Tamiyo, Collector of Tales", ""));
cubeCards.add(new CardIdentity("Tarmogoyf", ""));
cubeCards.add(new CardIdentity("Tear Asunder", ""));
cubeCards.add(new CardIdentity("Teferi, Hero of Dominaria", ""));
cubeCards.add(new CardIdentity("Teferi, Time Raveler", ""));
cubeCards.add(new CardIdentity("Temple Garden", ""));
cubeCards.add(new CardIdentity("Tenacious Underdog", ""));
cubeCards.add(new CardIdentity("Tendrils of Agony", ""));
cubeCards.add(new CardIdentity("Territorial Kavu", ""));
cubeCards.add(new CardIdentity("Thalia, Guardian of Thraben", ""));
cubeCards.add(new CardIdentity("The Gitrog, Ravenous Ride", ""));
cubeCards.add(new CardIdentity("The Mightstone and Weakstone", ""));
cubeCards.add(new CardIdentity("The One Ring", ""));
cubeCards.add(new CardIdentity("The Wandering Emperor", ""));
cubeCards.add(new CardIdentity("Thieving Skydiver", ""));
cubeCards.add(new CardIdentity("Third Path Iconoclast", ""));
cubeCards.add(new CardIdentity("Thopter Foundry", ""));
cubeCards.add(new CardIdentity("Thought Scour", ""));
cubeCards.add(new CardIdentity("Thoughtseize", ""));
cubeCards.add(new CardIdentity("Thraben Inspector", ""));
cubeCards.add(new CardIdentity("Three Steps Ahead", ""));
cubeCards.add(new CardIdentity("Through the Breach", ""));
cubeCards.add(new CardIdentity("Thundering Falls", ""));
cubeCards.add(new CardIdentity("Thundermaw Hellkite", ""));
cubeCards.add(new CardIdentity("Tidehollow Sculler", ""));
cubeCards.add(new CardIdentity("Time Spiral", ""));
cubeCards.add(new CardIdentity("Time Walk", ""));
cubeCards.add(new CardIdentity("Time Warp", ""));
cubeCards.add(new CardIdentity("Timeless Dragon", ""));
cubeCards.add(new CardIdentity("Timetwister", ""));
cubeCards.add(new CardIdentity("Tinker", ""));
cubeCards.add(new CardIdentity("Tireless Tracker", ""));
cubeCards.add(new CardIdentity("Tishana's Tidebinder", ""));
cubeCards.add(new CardIdentity("Titania, Protector of Argoth", ""));
cubeCards.add(new CardIdentity("Tolarian Academy", ""));
cubeCards.add(new CardIdentity("Torsten, Founder of Benalia", ""));
cubeCards.add(new CardIdentity("Touch the Spirit Realm", ""));
cubeCards.add(new CardIdentity("Tough Cookie", ""));
cubeCards.add(new CardIdentity("Tourach, Dread Cantor", ""));
cubeCards.add(new CardIdentity("Toxic Deluge", ""));
cubeCards.add(new CardIdentity("Treachery", ""));
cubeCards.add(new CardIdentity("Treasure Cruise", ""));
cubeCards.add(new CardIdentity("Trinket Mage", ""));
cubeCards.add(new CardIdentity("Triplicate Titan", ""));
cubeCards.add(new CardIdentity("Troll of Khazad-dum", ""));
cubeCards.add(new CardIdentity("Tropical Island", ""));
cubeCards.add(new CardIdentity("True-Name Nemesis", ""));
cubeCards.add(new CardIdentity("Trumpeting Carnosaur", ""));
cubeCards.add(new CardIdentity("Tundra", ""));
cubeCards.add(new CardIdentity("Turnabout", ""));
cubeCards.add(new CardIdentity("Ulamog, the Infinite Gyre", ""));
cubeCards.add(new CardIdentity("Ulvenwald Oddity", ""));
cubeCards.add(new CardIdentity("Umezawa's Jitte", ""));
cubeCards.add(new CardIdentity("Undercity Sewers", ""));
cubeCards.add(new CardIdentity("Underground Mortuary", ""));
cubeCards.add(new CardIdentity("Underground Sea", ""));
cubeCards.add(new CardIdentity("Underworld Breach", ""));
cubeCards.add(new CardIdentity("Unearth", ""));
cubeCards.add(new CardIdentity("Unexpectedly Absent", ""));
cubeCards.add(new CardIdentity("Unholy Heat", ""));
cubeCards.add(new CardIdentity("Upheaval", ""));
cubeCards.add(new CardIdentity("Urborg, Tomb of Yawgmoth", ""));
cubeCards.add(new CardIdentity("Urza's Saga", ""));
cubeCards.add(new CardIdentity("Urza, Lord High Artificer", ""));
cubeCards.add(new CardIdentity("Usher of the Fallen", ""));
cubeCards.add(new CardIdentity("Utopia Sprawl", ""));
cubeCards.add(new CardIdentity("Valki, God of Lies", ""));
cubeCards.add(new CardIdentity("Vampiric Tutor", ""));
cubeCards.add(new CardIdentity("Vaultborn Tyrant", ""));
cubeCards.add(new CardIdentity("Verdant Catacombs", ""));
cubeCards.add(new CardIdentity("Vindicate", ""));
cubeCards.add(new CardIdentity("Virtue of Loyalty", ""));
cubeCards.add(new CardIdentity("Virtue of Persistence", ""));
cubeCards.add(new CardIdentity("Volcanic Island", ""));
cubeCards.add(new CardIdentity("Voldaren Epicure", ""));
cubeCards.add(new CardIdentity("Walking Ballista", ""));
cubeCards.add(new CardIdentity("Wasteland", ""));
cubeCards.add(new CardIdentity("Waterlogged Grove", ""));
cubeCards.add(new CardIdentity("Watery Grave", ""));
cubeCards.add(new CardIdentity("Wheel of Fortune", ""));
cubeCards.add(new CardIdentity("Winds of Abandon", ""));
cubeCards.add(new CardIdentity("Windswept Heath", ""));
cubeCards.add(new CardIdentity("Wishclaw Talisman", ""));
cubeCards.add(new CardIdentity("Wooded Foothills", ""));
cubeCards.add(new CardIdentity("Woodfall Primus", ""));
cubeCards.add(new CardIdentity("Worldspine Wurm", ""));
cubeCards.add(new CardIdentity("Wrath of God", ""));
cubeCards.add(new CardIdentity("Wrenn and Six", ""));
cubeCards.add(new CardIdentity("Xander's Lounge", ""));
cubeCards.add(new CardIdentity("Yavimaya, Cradle of Growth", ""));
cubeCards.add(new CardIdentity("Yawgmoth's Will", ""));
cubeCards.add(new CardIdentity("Zagoth Triome", ""));
cubeCards.add(new CardIdentity("Ziatora's Proving Ground", ""));
cubeCards.add(new CardIdentity("Zirda, the Dawnwaker", ""));
cubeCards.add(new CardIdentity("Zuran Orb", ""));
}
}

View file

@ -140,6 +140,9 @@
<draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCube"/>
<draftCube name="MTGO Legendary Cube April 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCubeApril2016"/>
<draftCube name="MTGO Modern Cube 2017" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.ModernCube2017"/>
<draftCube name="MTGO Vintage Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGOVintageCube"/>
<!-- outdated cubes - will be removed on next releases -->
<!--
<draftCube name="MTGO Vintage Cube 2013" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2013"/>
<draftCube name="MTGO Vintage Cube 2014" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2014"/>
<draftCube name="MTGO Vintage Cube 2015" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2015"/>
@ -158,6 +161,7 @@
<draftCube name="MTGO Vintage Cube July 2021" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeJuly2021"/>
<draftCube name="MTGO Vintage Cube February 2022" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeFebruary2022"/>
<draftCube name="MTGO Vintage Cube October 2023" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeOctober2023"/>
-->
<draftCube name="SCG Con Cube 2018 December" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.ScgConCube2018December"/>
<draftCube name="The Peasant's Toolbox" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.PeasantsToolboxCube"/>
<draftCube name="www.MTGCube.com" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGCube"/>

View file

@ -134,6 +134,9 @@
<draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegendaryCube"/>
<draftCube name="MTGO Legendary Cube April 2016" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegendaryCubeApril2016"/>
<draftCube name="MTGO Modern Cube 2017" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.ModernCube2017"/>
<draftCube name="MTGO Vintage Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGOVintageCube"/>
<!-- outdated cubes - will be removed on next releases -->
<!--
<draftCube name="MTGO Vintage Cube 2013" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCube2013"/>
<draftCube name="MTGO Vintage Cube 2014" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCube2014"/>
<draftCube name="MTGO Vintage Cube 2015" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCube2015"/>
@ -152,6 +155,7 @@
<draftCube name="MTGO Vintage Cube July 2021" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJuly2021"/>
<draftCube name="MTGO Vintage Cube February 2022" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeFebruary2022"/>
<draftCube name="MTGO Vintage Cube October 2023" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeOctober2023"/>
-->
<draftCube name="SCG Con Cube 2018 December" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.ScgConCube2018December"/>
<draftCube name="The Peasant's Toolbox" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.PeasantsToolboxCube"/>
<draftCube name="www.MTGCube.com" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGCube"/>

View file

@ -998,7 +998,7 @@ public class MageServerImpl implements MageServer {
public void handleException(Exception ex) throws MageException {
if (ex.getMessage() != null && !ex.getMessage().equals("No message")) {
throw new MageException("Server error: " + ex.getMessage());
throw new MageException(ex.getMessage());
}
if (ex instanceof ConcurrentModificationException) {

View file

@ -1,4 +1,3 @@
package mage.server.draft;
import mage.cards.decks.Deck;
@ -11,8 +10,7 @@ import java.util.Map;
import java.util.Set;
/**
*
* @author LevelX2
* @author LevelX2, JayDi85
*/
public enum CubeFactory {
@ -22,13 +20,12 @@ public enum CubeFactory {
private final Map<String, Class> draftCubes = new LinkedHashMap<>();
public DraftCube createDraftCube(String draftCubeName) {
DraftCube draftCube;
try {
Constructor<?> con = draftCubes.get(draftCubeName).getConstructor();
draftCube = (DraftCube)con.newInstance();
draftCube = (DraftCube) con.newInstance();
} catch (Exception ex) {
logger.fatal("CubeFactory error", ex);
return null;
@ -43,7 +40,7 @@ public enum CubeFactory {
DraftCube draftCube;
try {
Constructor<?> con = draftCubes.get(draftCubeName).getConstructor(Deck.class);
draftCube = (DraftCube)con.newInstance(cubeFromDeck);
draftCube = (DraftCube) con.newInstance(cubeFromDeck);
} catch (Exception ex) {
logger.fatal("CubeFactory error", ex);
return null;
@ -57,10 +54,24 @@ public enum CubeFactory {
return draftCubes.keySet();
}
public void addDraftCube(String name, Class draftCube) {
if (draftCube != null) {
this.draftCubes.put(name, draftCube);
}
public void addDraftCube(String configName, Class configCubeClass) {
// store cubes by auto-generated names, not from config
if (configCubeClass == null) {
return;
}
DraftCube draftCube = null;
try {
Constructor<?> con = configCubeClass.getConstructor();
draftCube = (DraftCube) con.newInstance();
if (this.draftCubes.containsKey(draftCube.getName())) {
throw new IllegalArgumentException("already exists " + draftCube.getName());
}
} catch (Exception e) {
logger.error("Can't create draft cube named by " + configName, e);
return;
}
this.draftCubes.put(draftCube.getName(), configCubeClass);
}
}

View file

@ -1,5 +1,3 @@
package mage.server.tournament;
import mage.cards.Sets;
@ -15,7 +13,6 @@ import java.lang.reflect.Constructor;
import java.util.*;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public enum TournamentFactory {
@ -27,7 +24,6 @@ public enum TournamentFactory {
private final List<TournamentTypeView> tournamentTypeViews = new ArrayList<>();
public Tournament createTournament(String tournamentType, TournamentOptions options) {
Tournament tournament;
@ -37,8 +33,8 @@ public enum TournamentFactory {
// transfer set information, create short info string for included sets
tournament.setTournamentType(tournamentTypes.get(tournamentType));
if (tournament.getTournamentType().isLimited()) {
Map<String,Integer> setInfo = new LinkedHashMap<>();
for (String setCode: options.getLimitedOptions().getSetCodes()) {
Map<String, Integer> setInfo = new LinkedHashMap<>();
for (String setCode : options.getLimitedOptions().getSetCodes()) {
tournament.getSets().add(Sets.findSet(setCode));
int count = setInfo.getOrDefault(setCode, 0);
setInfo.put(setCode, count + 1);
@ -52,25 +48,31 @@ public enum TournamentFactory {
} else {
draftCube = CubeFactory.instance.createDraftCube(tournament.getOptions().getLimitedOptions().getDraftCubeName());
}
String boosterInfo = "";
if (draftCube != null) {
// make sure all loaded (will raise error on empty cards list)
draftCube.validateData();
tournament.getOptions().getLimitedOptions().setDraftCube(draftCube);
tournament.setBoosterInfo(tournament.getOptions().getLimitedOptions().getDraftCubeName());
boosterInfo = draftCube.getName();
}
tournament.setBoosterInfo(boosterInfo);
} else if (tournament.getTournamentType().isRandom()) {
StringBuilder rv = new StringBuilder( "Chaos Draft using sets: ");
for (Map.Entry<String, Integer> entry: setInfo.entrySet()){
StringBuilder rv = new StringBuilder("Chaos Draft using sets: ");
for (Map.Entry<String, Integer> entry : setInfo.entrySet()) {
rv.append(entry.getKey());
rv.append(';');
}
tournament.setBoosterInfo(rv.toString());
} else if (tournament.getTournamentType().isReshuffled()) {
StringBuilder rv = new StringBuilder( "Chaos Reshuffled Draft using sets: ");
for (Map.Entry<String, Integer> entry: setInfo.entrySet()){
StringBuilder rv = new StringBuilder("Chaos Reshuffled Draft using sets: ");
for (Map.Entry<String, Integer> entry : setInfo.entrySet()) {
rv.append(entry.getKey());
rv.append(';');
}
tournament.setBoosterInfo(rv.toString());
} else {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String,Integer> entry:setInfo.entrySet()) {
for (Map.Entry<String, Integer> entry : setInfo.entrySet()) {
sb.append(entry.getValue().toString()).append('x').append(entry.getKey()).append(' ');
}
tournament.setBoosterInfo(sb.toString());
@ -78,12 +80,9 @@ public enum TournamentFactory {
} else {
tournament.setBoosterInfo("");
}
} catch (Exception ex) {
logger.fatal("TournamentFactory error ", ex);
return null;
} catch (Exception e) {
throw new IllegalStateException("Can't create new tourney: " + e, e);
}
logger.debug("Tournament created: " + tournamentType + ' ' + tournament.getId());
return tournament;
}

View file

@ -105,6 +105,9 @@
<draftCube name="MTGO Legendary Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCube"/>
<draftCube name="MTGO Legendary Cube April 2016" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegendaryCubeApril2016"/>
<draftCube name="MTGO Modern Cube 2017" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.ModernCube2017"/>
<draftCube name="MTGO Vintage Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGOVintageCube"/>
<!-- outdated cubes - will be removed on next releases -->
<!--
<draftCube name="MTGO Vintage Cube 2013" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2013"/>
<draftCube name="MTGO Vintage Cube 2014" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2014"/>
<draftCube name="MTGO Vintage Cube 2015" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCube2015"/>
@ -119,6 +122,7 @@
<draftCube name="MTGO Vintage Cube December 2019" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeDecember2019"/>
<draftCube name="MTGO Vintage Cube April 2020" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeApril2020"/>
<draftCube name="MTGO Vintage Cube July 2020" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeJuly2020"/>
-->
<draftCube name="SCG Con Cube 2018 December" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.ScgConCube2018December"/>
<draftCube name="The Peasant's Toolbox" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.PeasantsToolboxCube"/>
<draftCube name="www.MTGCube.com" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGCube"/>

View file

@ -24,6 +24,8 @@ import mage.abilities.hint.common.MonarchHint;
import mage.abilities.keyword.*;
import mage.cards.*;
import mage.cards.decks.CardNameUtil;
import mage.cards.decks.Deck;
import mage.cards.decks.DeckCardInfo;
import mage.cards.decks.DeckCardLists;
import mage.cards.decks.importer.DeckImporter;
import mage.cards.repository.*;
@ -42,6 +44,7 @@ import mage.game.permanent.token.custom.CreatureToken;
import mage.game.permanent.token.custom.XmageToken;
import mage.sets.TherosBeyondDeath;
import mage.target.targetpointer.TargetPointer;
import mage.tournament.cubes.CubeFromDeck;
import mage.util.CardUtil;
import mage.utils.SystemUtil;
import mage.verify.mtgjson.MtgJsonCard;
@ -3090,7 +3093,7 @@ public class VerifyCardDataTest {
}
@Test
public void test_checkCardsInCubes() {
public void test_checkCardsInCubes() throws Exception {
Reflections reflections = new Reflections("mage.tournament.cubes.");
Set<Class<? extends DraftCube>> cubesList = reflections.getSubTypesOf(DraftCube.class);
Assert.assertFalse("Can't find any cubes", cubesList.isEmpty());
@ -3103,7 +3106,24 @@ public class VerifyCardDataTest {
continue;
}
DraftCube cube = (DraftCube) createNewObject(cubeClass);
// cube from deck must use real deck to check complete
DraftCube cube;
if (cubeClass.isAssignableFrom(CubeFromDeck.class)) {
DeckCardLists deckCardLists = new DeckCardLists();
deckCardLists.setCards(Arrays.asList(
new DeckCardInfo("Adanto Vanguard", "1", "XLN"),
new DeckCardInfo("Boneyard Parley", "94", "XLN"),
new DeckCardInfo("Forest", "276", "XLN")
));
Deck deck = Deck.load(deckCardLists, true);
Constructor<?> con = cubeClass.getConstructor(Deck.class);
cube = (DraftCube) con.newInstance(deck);
Assert.assertFalse(deckCardLists.getCards().isEmpty());
Assert.assertEquals("deck must be loaded to cube", cube.getCubeCards().size(), deckCardLists.getCards().size());
Assert.assertTrue("cube's name must contains cards count", cube.getName().contains(deckCardLists.getCards().size() + " cards"));
} else {
cube = (DraftCube) createNewObject(cubeClass);
}
if (cube.getCubeCards().isEmpty()) {
errorsList.add("Error: broken cube, empty cards list: " + cube.getClass().getCanonicalName());
}

View file

@ -1,20 +1,27 @@
package mage.game.draft;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import mage.cards.Card;
import mage.cards.ExpansionSet;
import mage.cards.repository.CardInfo;
import mage.cards.repository.CardRepository;
import mage.util.RandomUtil;
import org.apache.log4j.Logger;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
*
* @author LevelX2
* @author LevelX2, JayDi85
*/
public abstract class DraftCube {
SimpleDateFormat UPDATE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
private static final Logger logger = Logger.getLogger(DraftCube.class);
public static class CardIdentity {
private final String name;
@ -38,36 +45,78 @@ public abstract class DraftCube {
public String getName() {
return name;
}
public String getExtension() {
return extension;
}
public String getCardNumber() {
return number;
}
}
private static final Logger logger = Logger.getLogger(DraftCube.class);
private final String name;
private final String code;
private String updateInfo;
private final Date updateDate;
private static final int boosterSize = 15;
protected List<CardIdentity> cubeCards = new ArrayList<>();
protected List<CardIdentity> leftCubeCards = new ArrayList<>();
protected DraftCube(String name) {
this(name, "", 0, 0, 0);
}
public DraftCube(String name, String updateInfo, int updateYear, int updateMonth, int updateDay) {
this.name = name;
this.code = getClass().getSimpleName();
this.updateInfo = updateInfo;
this.updateDate = updateYear == 0 ? null : ExpansionSet.buildDate(updateYear, updateMonth, updateDay);
}
public String getName() {
return name;
String res = this.name;
List<String> extra = new ArrayList<>();
if (this.updateInfo != null && !this.updateInfo.isEmpty()) {
extra.add(this.updateInfo);
}
if (this.updateDate != null) {
extra.add(UPDATE_DATE_FORMAT.format(this.updateDate));
}
if (!extra.isEmpty()) {
res += String.format(" (%s)", String.join(", ", extra));
}
return res;
}
/**
* Validate inner data - is it fine to start (example: cube from deck must has loaded cards)
*/
public void validateData() {
if (cubeCards.isEmpty()) {
throw new IllegalArgumentException("Can't create cube draft - found empty cards list: " + this.getName());
}
}
public String getCode() {
return code;
}
public String getUpdateInfo() {
return updateInfo;
}
public void setUpdateInfo(String info) {
this.updateInfo = info;
}
public Date getUpdateDate() {
return updateDate;
}
public List<CardIdentity> getCubeCards() {
return cubeCards;
}