diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java index 8cfdba4c96..ec431e4602 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java @@ -318,6 +318,33 @@ public class MageBook extends JComponent { } } + // dungeons + List allDungeons = getTokenCardUrls(); + for (CardDownloadData dungeon : allDungeons) { + if (dungeon.getSet().equals(currentSet)) { + try { + String className = dungeon.getName(); + if (dungeon.getTokenClassName() != null && dungeon.getTokenClassName().length() > 0) { + if (dungeon.getTokenClassName().toLowerCase(Locale.ENGLISH).matches(".*dungeon.*")) { + className = dungeon.getTokenClassName(); + className = "mage.game.command.dungeons." + className; + } + } else { + continue; + } + Class c = Class.forName(className); + Constructor cons = c.getConstructor(); + Object newDungeon = cons.newInstance(); + if (newDungeon instanceof Dungeon) { + ((Dungeon) newDungeon).setExpansionSetCodeForImage(currentSet); + res.add(newDungeon); + } + } catch (ClassNotFoundException | InvocationTargetException | IllegalArgumentException | IllegalAccessException | InstantiationException | SecurityException | NoSuchMethodException ex) { + // Swallow exception + } + } + } + return res; } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java index 414586c8fa..8e3e97ae7d 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java @@ -550,7 +550,6 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements CardDownloadData card = new CardDownloadData(params[3], set, "0", false, type, "", "", true); card.setTokenClassName(tokenClassName); list.add(card); - // logger.debug("Token: " + set + "/" + card.getName() + " type: " + type); } else if (params[1].toLowerCase(Locale.ENGLISH).equals("generate") && params[2].startsWith("EMBLEM:")) { String set = params[2].substring(7); CardDownloadData card = new CardDownloadData("Emblem " + params[3], set, "0", false, type, "", "", true, fileName); @@ -571,6 +570,11 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements CardDownloadData card = new CardDownloadData(params[3], set, "0", false, type, "", "", true, fileName); card.setTokenClassName(tokenClassName); list.add(card); + } else if (params[1].toLowerCase(Locale.ENGLISH).equals("generate") && params[2].startsWith("DUNGEON:")) { + String set = params[2].substring(8); + CardDownloadData card = new CardDownloadData(params[3], set, "0", false, type, "", "", true, fileName); + card.setTokenClassName(tokenClassName); + list.add(card); } else { logger.error("wrong line format in tokens file: " + line); } diff --git a/Mage.Client/src/main/resources/card-pictures-tok.txt b/Mage.Client/src/main/resources/card-pictures-tok.txt index 75ee26ffb0..4ee3e0b4d6 100644 --- a/Mage.Client/src/main/resources/card-pictures-tok.txt +++ b/Mage.Client/src/main/resources/card-pictures-tok.txt @@ -181,6 +181,11 @@ |Generate|TOK:AER|Gremlin|||GremlinToken| |Generate|TOK:AER|Ragavan|||RagavanToken| +# Dungeons +|Generate|DUNGEON:AFR|Tomb of Annihilation|||TombOfAnnihilationDungeon| +|Generate|DUNGEON:AFR|Lost Mine of Phandelver|||LostMineOfPhandelverDungeon| +|Generate|DUNGEON:AFR|Dungeon of the Mad Mage|||DungeonOfTheMadMageDungeon| + # AKH |Generate|TOK:AKH|Beast|||BeastToken3| |Generate|TOK:AKH|Cat|||CatToken2| diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 2825e22dd9..b657083410 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -19,6 +19,7 @@ import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.SubType; import mage.constants.SuperType; +import mage.game.command.Dungeon; import mage.game.command.Plane; import mage.game.draft.DraftCube; import mage.game.draft.RateCard; @@ -1188,6 +1189,47 @@ public class VerifyCardDataTest { } } + @Test + public void test_checkMissingDungeonsData() { + Collection errorsList = new ArrayList<>(); + + Reflections reflections = new Reflections("mage."); + Set> dungeonClassesList = reflections.getSubTypesOf(Dungeon.class); + + // 1. correct class name + for (Class dungeonClass : dungeonClassesList) { + if (!dungeonClass.getName().endsWith("Dungeon")) { + String className = extractShortClass(dungeonClass); + errorsList.add("Error: dungeon class must ends with Dungeon: " + className + " from " + dungeonClass.getName()); + } + } + + // 2. correct package + for (Class dungeonClass : dungeonClassesList) { + String fullClass = dungeonClass.getName(); + if (!fullClass.startsWith("mage.game.command.dungeons.")) { + String className = extractShortClass(dungeonClass); + errorsList.add("Error: dungeon must be stored in mage.game.command.dungeons package: " + className + " from " + dungeonClass.getName()); + } + } + + // 3. correct constructor + for (Class dungeonClass : dungeonClassesList) { + String className = extractShortClass(dungeonClass); + Dungeon dungeon; + try { + dungeon = (Dungeon) createNewObject(dungeonClass); + } catch (Throwable e) { + errorsList.add("Error: can't create dungeon with default constructor: " + className + " from " + dungeonClass.getName()); + } + } + + printMessages(errorsList); + if (errorsList.size() > 0) { + Assert.fail("Found dungeon errors: " + errorsList.size()); + } + } + private void check(Card card, int cardIndex, boolean skipWarning) { MtgJsonCard ref = MtgJsonService.cardFromSet(card.getExpansionSetCode(), card.getName(), card.getCardNumber()); if (ref != null) { diff --git a/Mage/src/main/java/mage/game/command/Dungeon.java b/Mage/src/main/java/mage/game/command/Dungeon.java index eca4f340a1..96c7fe0a9a 100644 --- a/Mage/src/main/java/mage/game/command/Dungeon.java +++ b/Mage/src/main/java/mage/game/command/Dungeon.java @@ -21,9 +21,9 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.SuperType; import mage.game.Game; -import mage.game.command.dungeons.DungeonOfTheMadMage; -import mage.game.command.dungeons.LostMineOfPhandelver; -import mage.game.command.dungeons.TombOfAnnihilation; +import mage.game.command.dungeons.DungeonOfTheMadMageDungeon; +import mage.game.command.dungeons.LostMineOfPhandelverDungeon; +import mage.game.command.dungeons.TombOfAnnihilationDungeon; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.players.Player; @@ -56,7 +56,7 @@ public class Dungeon implements CommandObject { private MageObject copyFrom; // copied card INFO (used to call original adjusters) private FrameStyle frameStyle; private final Abilities abilites = new AbilitiesImpl<>(); - private final String expansionSetCodeForImage; + private String expansionSetCodeForImage; private final List dungeonRooms = new ArrayList<>(); private DungeonRoom currentRoom = null; @@ -141,11 +141,11 @@ public class Dungeon implements CommandObject { public static Dungeon createDungeon(String name) { switch (name) { case "Tomb of Annihilation": - return new TombOfAnnihilation(); + return new TombOfAnnihilationDungeon(); case "Lost Mine of Phandelver": - return new LostMineOfPhandelver(); + return new LostMineOfPhandelverDungeon(); case "Dungeon of the Mad Mage": - return new DungeonOfTheMadMage(); + return new DungeonOfTheMadMageDungeon(); default: throw new UnsupportedOperationException("A dungeon should have been chosen"); } @@ -322,6 +322,10 @@ public class Dungeon implements CommandObject { return expansionSetCodeForImage; } + public void setExpansionSetCodeForImage(String expansionSetCodeForImage) { + this.expansionSetCodeForImage = expansionSetCodeForImage; + } + @Override public int getZoneChangeCounter(Game game) { return 1; diff --git a/Mage/src/main/java/mage/game/command/dungeons/DungeonOfTheMadMage.java b/Mage/src/main/java/mage/game/command/dungeons/DungeonOfTheMadMageDungeon.java similarity index 96% rename from Mage/src/main/java/mage/game/command/dungeons/DungeonOfTheMadMage.java rename to Mage/src/main/java/mage/game/command/dungeons/DungeonOfTheMadMageDungeon.java index 55cfb0bc4e..b38d4b5c05 100644 --- a/Mage/src/main/java/mage/game/command/dungeons/DungeonOfTheMadMage.java +++ b/Mage/src/main/java/mage/game/command/dungeons/DungeonOfTheMadMageDungeon.java @@ -26,9 +26,9 @@ import mage.target.common.TargetCreaturePermanent; /** * @author TheElk801 */ -public class DungeonOfTheMadMage extends Dungeon { +public class DungeonOfTheMadMageDungeon extends Dungeon { - public DungeonOfTheMadMage() { + public DungeonOfTheMadMageDungeon() { super("Dungeon of the Mad Mage", "AFR"); // (1) Yawning Portal — You gain 1 life. (→ 2) DungeonRoom yawningPortal = new DungeonRoom("Yawning Portal", new GainLifeEffect(1)); @@ -86,12 +86,12 @@ public class DungeonOfTheMadMage extends Dungeon { this.addRoom(madWizardsLair); } - private DungeonOfTheMadMage(final DungeonOfTheMadMage dungeon) { + private DungeonOfTheMadMageDungeon(final DungeonOfTheMadMageDungeon dungeon) { super(dungeon); } - public DungeonOfTheMadMage copy() { - return new DungeonOfTheMadMage(this); + public DungeonOfTheMadMageDungeon copy() { + return new DungeonOfTheMadMageDungeon(this); } } diff --git a/Mage/src/main/java/mage/game/command/dungeons/LostMineOfPhandelver.java b/Mage/src/main/java/mage/game/command/dungeons/LostMineOfPhandelverDungeon.java similarity index 91% rename from Mage/src/main/java/mage/game/command/dungeons/LostMineOfPhandelver.java rename to Mage/src/main/java/mage/game/command/dungeons/LostMineOfPhandelverDungeon.java index e3fc369b35..c7e4b18c59 100644 --- a/Mage/src/main/java/mage/game/command/dungeons/LostMineOfPhandelver.java +++ b/Mage/src/main/java/mage/game/command/dungeons/LostMineOfPhandelverDungeon.java @@ -18,9 +18,9 @@ import mage.target.common.TargetCreaturePermanent; /** * @author TheElk801 */ -public class LostMineOfPhandelver extends Dungeon { +public class LostMineOfPhandelverDungeon extends Dungeon { - public LostMineOfPhandelver() { + public LostMineOfPhandelverDungeon() { super("Lost Mine of Phandelver", "AFR"); // (1) Cave Entrance — Scry 1. (→ 2a or 2b) DungeonRoom caveEntrance = new DungeonRoom( @@ -75,12 +75,12 @@ public class LostMineOfPhandelver extends Dungeon { this.addRoom(templeOfDumathoin); } - private LostMineOfPhandelver(final LostMineOfPhandelver dungeon) { + private LostMineOfPhandelverDungeon(final LostMineOfPhandelverDungeon dungeon) { super(dungeon); } @Override - public LostMineOfPhandelver copy() { - return new LostMineOfPhandelver(this); + public LostMineOfPhandelverDungeon copy() { + return new LostMineOfPhandelverDungeon(this); } } diff --git a/Mage/src/main/java/mage/game/command/dungeons/TombOfAnnihilation.java b/Mage/src/main/java/mage/game/command/dungeons/TombOfAnnihilationDungeon.java similarity index 96% rename from Mage/src/main/java/mage/game/command/dungeons/TombOfAnnihilation.java rename to Mage/src/main/java/mage/game/command/dungeons/TombOfAnnihilationDungeon.java index bdf49b4766..02a250a6ae 100644 --- a/Mage/src/main/java/mage/game/command/dungeons/TombOfAnnihilation.java +++ b/Mage/src/main/java/mage/game/command/dungeons/TombOfAnnihilationDungeon.java @@ -28,7 +28,7 @@ import java.util.*; /** * @author TheElk801 */ -public final class TombOfAnnihilation extends Dungeon { +public final class TombOfAnnihilationDungeon extends Dungeon { static final FilterControlledPermanent filter = new FilterControlledPermanent("an artifact, a creature, or a land"); @@ -41,7 +41,7 @@ public final class TombOfAnnihilation extends Dungeon { )); } - public TombOfAnnihilation() { + public TombOfAnnihilationDungeon() { super("Tomb of Annihilation", "AFR"); // (1) Trapped Entry — Each player loses 1 life. (→ 2a or 2b) DungeonRoom trappedEntry = new DungeonRoom("Trapped Entry", new LoseLifeAllPlayersEffect(1)); @@ -71,12 +71,12 @@ public final class TombOfAnnihilation extends Dungeon { this.addRoom(cradleOfTheDeathGod); } - private TombOfAnnihilation(final TombOfAnnihilation dungeon) { + private TombOfAnnihilationDungeon(final TombOfAnnihilationDungeon dungeon) { super(dungeon); } - public TombOfAnnihilation copy() { - return new TombOfAnnihilation(this); + public TombOfAnnihilationDungeon copy() { + return new TombOfAnnihilationDungeon(this); } } @@ -169,7 +169,7 @@ class OublietteTarget extends TargetControlledPermanent { CardType.CREATURE, CardType.LAND ); - private static final FilterControlledPermanent filter = TombOfAnnihilation.filter.copy(); + private static final FilterControlledPermanent filter = TombOfAnnihilationDungeon.filter.copy(); static { filter.setMessage("an artifact, a creature, and a land"); @@ -245,7 +245,7 @@ class SandfallCellEffect extends OneShotEffect { if (player == null) { continue; } - TargetPermanent target = new TargetPermanent(0, 1, TombOfAnnihilation.filter, true); + TargetPermanent target = new TargetPermanent(0, 1, TombOfAnnihilationDungeon.filter, true); player.choose(Outcome.PreventDamage, target, source.getSourceId(), game); map.put(playerId, game.getPermanent(target.getFirstTarget())); }