From 7926193e34cfea7802f2db2a727227452bb22950 Mon Sep 17 00:00:00 2001 From: "Alex W. Jackson" Date: Wed, 13 Oct 2021 11:47:23 -0400 Subject: [PATCH] Refactor ExpansionSet and its subclasses (#8382) * Don't purge cards-by-rarity cache between tournaments * Move DOM and WAR specific checks out of base ExpansionSet class * Move Battlebond specific methods out of base ExpansionSet class * Refactor ExpansionSet and subclasses * Zendikar boosters also only have full-art basic lands * Fix Eldritch Moon (#8171) --- Mage.Sets/src/mage/sets/AetherRevolt.java | 20 +- Mage.Sets/src/mage/sets/Amonkhet.java | 21 +- .../src/mage/sets/AmonkhetRemastered.java | 22 -- .../src/mage/sets/BattleForZendikar.java | 24 +- Mage.Sets/src/mage/sets/Battlebond.java | 90 ++++- Mage.Sets/src/mage/sets/Coldsnap.java | 25 +- Mage.Sets/src/mage/sets/CoreSet2019.java | 46 --- Mage.Sets/src/mage/sets/CoreSet2020.java | 46 --- Mage.Sets/src/mage/sets/CoreSet2021.java | 49 +-- Mage.Sets/src/mage/sets/DarkAscension.java | 23 ++ Mage.Sets/src/mage/sets/Dominaria.java | 8 +- Mage.Sets/src/mage/sets/DragonsMaze.java | 78 ++-- Mage.Sets/src/mage/sets/EldritchMoon.java | 61 +++ Mage.Sets/src/mage/sets/FateReforged.java | 78 +--- Mage.Sets/src/mage/sets/GuildsOfRavnica.java | 52 +-- .../src/mage/sets/HourOfDevastation.java | 21 +- .../src/mage/sets/IkoriaLairOfBehemoths.java | 47 +-- Mage.Sets/src/mage/sets/Kaladesh.java | 21 +- .../src/mage/sets/KaladeshRemastered.java | 2 - Mage.Sets/src/mage/sets/Kaldheim.java | 50 +-- Mage.Sets/src/mage/sets/MastersEditionIV.java | 24 +- Mage.Sets/src/mage/sets/ModernHorizons2.java | 37 +- .../src/mage/sets/OathOfTheGatewatch.java | 29 +- .../src/mage/sets/RavnicaAllegiance.java | 48 +-- .../src/mage/sets/ShadowsOverInnistrad.java | 63 +-- .../mage/sets/StrixhavenSchoolOfMages.java | 44 +-- Mage.Sets/src/mage/sets/TimeSpiral.java | 16 +- .../src/mage/sets/TimeSpiralRemastered.java | 16 - .../src/mage/sets/TimeSpiralTimeshifted.java | 82 ++-- Mage.Sets/src/mage/sets/VintageMasters.java | 62 ++- Mage.Sets/src/mage/sets/WarOfTheSpark.java | 9 +- Mage.Sets/src/mage/sets/Zendikar.java | 11 + .../mage/test/sets/BoosterGenerationTest.java | 23 -- .../main/java/mage/cards/ExpansionSet.java | 370 +++++------------- .../java/mage/cards/repository/CardInfo.java | 10 + .../java/mage/game/draft/BoosterDraft.java | 1 - Mage/src/main/java/mage/game/draft/Draft.java | 2 - .../main/java/mage/game/draft/DraftImpl.java | 12 - .../mage/game/draft/RichManBoosterDraft.java | 1 - .../game/draft/RichManCubeBoosterDraft.java | 1 - .../mage/game/tournament/TournamentImpl.java | 11 - 41 files changed, 589 insertions(+), 1067 deletions(-) diff --git a/Mage.Sets/src/mage/sets/AetherRevolt.java b/Mage.Sets/src/mage/sets/AetherRevolt.java index ae1c213c45..138c72ce07 100644 --- a/Mage.Sets/src/mage/sets/AetherRevolt.java +++ b/Mage.Sets/src/mage/sets/AetherRevolt.java @@ -7,7 +7,6 @@ import mage.cards.repository.CardRepository; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.ArrayList; import java.util.List; /** @@ -21,8 +20,6 @@ public final class AetherRevolt extends ExpansionSet { return instance; } - private final List savedSpecialLand = new ArrayList<>(); - private AetherRevolt() { super("Aether Revolt", "AER", ExpansionSet.buildDate(2017, 1, 20), SetType.EXPANSION); this.blockName = "Kaladesh"; @@ -34,8 +31,8 @@ public final class AetherRevolt extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + this.ratioBoosterSpecialCommon = 144; this.maxCardNumberInBooster = 184; - this.ratioBoosterSpecialLand = 144; cards.add(new SetCardInfo("Aegis Automaton", 141, Rarity.COMMON, mage.cards.a.AegisAutomaton.class)); cards.add(new SetCardInfo("Aerial Modification", 1, Rarity.UNCOMMON, mage.cards.a.AerialModification.class)); @@ -237,15 +234,12 @@ public final class AetherRevolt extends ExpansionSet { } @Override - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes("MPS"); - criteria.minCardNumber(31); - criteria.maxCardNumber(54); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); + protected List findCardsByRarity(Rarity rarity) { + List cardInfos = super.findCardsByRarity(rarity); + if (rarity == Rarity.SPECIAL) { + cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes("MPS"))); + cardInfos.removeIf(cardInfo -> cardInfo.getCardNumberAsInt() < 31); } - - return new ArrayList<>(savedSpecialLand); + return cardInfos; } } diff --git a/Mage.Sets/src/mage/sets/Amonkhet.java b/Mage.Sets/src/mage/sets/Amonkhet.java index 4cfcba2fbb..17787ed28b 100644 --- a/Mage.Sets/src/mage/sets/Amonkhet.java +++ b/Mage.Sets/src/mage/sets/Amonkhet.java @@ -1,4 +1,3 @@ - package mage.sets; import mage.cards.ExpansionSet; @@ -8,7 +7,6 @@ import mage.cards.repository.CardRepository; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.ArrayList; import java.util.List; /** @@ -23,8 +21,6 @@ public final class Amonkhet extends ExpansionSet { return instance; } - private final List savedSpecialLand = new ArrayList<>(); - private Amonkhet() { super("Amonkhet", "AKH", ExpansionSet.buildDate(2017, 4, 28), SetType.EXPANSION); this.blockName = "Amonkhet"; @@ -35,8 +31,8 @@ public final class Amonkhet extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + this.ratioBoosterSpecialCommon = 129; this.maxCardNumberInBooster = 269; - this.ratioBoosterSpecialLand = 144; cards.add(new SetCardInfo("Ahn-Crop Champion", 194, Rarity.UNCOMMON, mage.cards.a.AhnCropChampion.class)); cards.add(new SetCardInfo("Ahn-Crop Crasher", 117, Rarity.UNCOMMON, mage.cards.a.AhnCropCrasher.class)); @@ -328,15 +324,12 @@ public final class Amonkhet extends ExpansionSet { } @Override - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes("MP2"); - criteria.minCardNumber(1); - criteria.maxCardNumber(30); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); + protected List findCardsByRarity(Rarity rarity) { + List cardInfos = super.findCardsByRarity(rarity); + if (rarity == Rarity.SPECIAL) { + cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes("MP2"))); + cardInfos.removeIf(cardInfo -> cardInfo.getCardNumberAsInt() > 30); } - - return new ArrayList<>(savedSpecialLand); + return cardInfos; } } diff --git a/Mage.Sets/src/mage/sets/AmonkhetRemastered.java b/Mage.Sets/src/mage/sets/AmonkhetRemastered.java index 58263f0206..cd79bced4b 100644 --- a/Mage.Sets/src/mage/sets/AmonkhetRemastered.java +++ b/Mage.Sets/src/mage/sets/AmonkhetRemastered.java @@ -1,14 +1,9 @@ package mage.sets; import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.ArrayList; import java.util.List; /** @@ -22,8 +17,6 @@ public class AmonkhetRemastered extends ExpansionSet { return instance; } - private final List savedSpecialLand = new ArrayList<>(); - private AmonkhetRemastered() { super("Amonkhet Remastered", "AKR", ExpansionSet.buildDate(2020, 8, 13), SetType.MAGIC_ARENA); this.hasBoosters = true; @@ -376,19 +369,4 @@ public class AmonkhetRemastered extends ExpansionSet { cards.add(new SetCardInfo("Wrath of God", 46, Rarity.RARE, mage.cards.w.WrathOfGod.class)); cards.add(new SetCardInfo("Zealot of the God-Pharaoh", 181, Rarity.COMMON, mage.cards.z.ZealotOfTheGodPharaoh.class)); } - - @Override - // the common taplands replacing the basic land - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(this.code); - criteria.rarities(Rarity.COMMON); - criteria.types(CardType.LAND); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); - } - - return new ArrayList<>(savedSpecialLand); - } - } diff --git a/Mage.Sets/src/mage/sets/BattleForZendikar.java b/Mage.Sets/src/mage/sets/BattleForZendikar.java index 03aace3d54..186bf18606 100644 --- a/Mage.Sets/src/mage/sets/BattleForZendikar.java +++ b/Mage.Sets/src/mage/sets/BattleForZendikar.java @@ -7,7 +7,6 @@ import mage.cards.repository.CardRepository; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.ArrayList; import java.util.List; /** @@ -21,8 +20,6 @@ public final class BattleForZendikar extends ExpansionSet { return instance; } - private final List savedSpecialLand = new ArrayList<>(); - private BattleForZendikar() { super("Battle for Zendikar", "BFZ", ExpansionSet.buildDate(2015, 10, 2), SetType.EXPANSION); this.blockName = "Battle for Zendikar"; @@ -33,8 +30,7 @@ public final class BattleForZendikar extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; - this.numBoosterSpecial = 0; - this.ratioBoosterSpecialLand = 144; + this.ratioBoosterSpecialCommon = 144; cards.add(new SetCardInfo("Adverse Conditions", 54, Rarity.UNCOMMON, mage.cards.a.AdverseConditions.class)); cards.add(new SetCardInfo("Akoum Firebird", 138, Rarity.MYTHIC, mage.cards.a.AkoumFirebird.class)); @@ -338,15 +334,15 @@ public final class BattleForZendikar extends ExpansionSet { } @Override - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes("EXP"); - criteria.minCardNumber(1); - criteria.maxCardNumber(45); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); + protected List findCardsByRarity(Rarity rarity) { + List cardInfos = super.findCardsByRarity(rarity); + if (rarity == Rarity.LAND) { + // only the full-art basic lands are found in boosters + cardInfos.removeIf(cardInfo -> cardInfo.getCardNumber().contains("a")); + } else if (rarity == Rarity.SPECIAL) { + cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes("EXP"))); + cardInfos.removeIf(cardInfo -> cardInfo.getCardNumberAsInt() > 25); } - - return new ArrayList<>(savedSpecialLand); + return cardInfos; } } diff --git a/Mage.Sets/src/mage/sets/Battlebond.java b/Mage.Sets/src/mage/sets/Battlebond.java index 881718498c..3cecbae6fd 100644 --- a/Mage.Sets/src/mage/sets/Battlebond.java +++ b/Mage.Sets/src/mage/sets/Battlebond.java @@ -1,9 +1,17 @@ package mage.sets; +import mage.abilities.Ability; +import mage.abilities.keyword.PartnerWithAbility; +import mage.cards.Card; import mage.cards.ExpansionSet; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; import mage.constants.Rarity; import mage.constants.SetType; +import java.util.ArrayList; +import java.util.List; + /** * @author TheElk801 */ @@ -20,7 +28,6 @@ public final class Battlebond extends ExpansionSet { this.blockName = "Battlebond"; this.hasBasicLands = true; this.hasBoosters = true; - this.hasPartnerMechanic = true; this.numBoosterLands = 1; this.numBoosterCommon = 10; this.numBoosterUncommon = 3; @@ -287,4 +294,85 @@ public final class Battlebond extends ExpansionSet { cards.add(new SetCardInfo("Zndrsplt, Eye of Wisdom", 5, Rarity.RARE, mage.cards.z.ZndrspltEyeOfWisdom.class)); } + @Override + public List tryBooster() { + List booster = new ArrayList<>(); + boolean partnerAllowed = true; + List uncommons = getCardsByRarity(Rarity.UNCOMMON); + for (int i = 0; i < numBoosterUncommon; i++) { + while (true) { + addToBooster(booster, uncommons); + int check = addMissingPartner(booster, partnerAllowed, numBoosterUncommon - 1, i); + if (check == 1) { + break; + } + if (check == 2) { + partnerAllowed = false; + //Be sure to account for the added card + if (i != numBoosterUncommon - 1) { + i += 1; + } + break; + } + } + } + + List commons = getCardsByRarity(Rarity.COMMON); + for (int i = 0; i < numBoosterCommon; i++) { + addToBooster(booster, commons); + } + + List rares = getCardsByRarity(Rarity.RARE); + List mythics = getCardsByRarity(Rarity.MYTHIC); + for (int i = 0; i < numBoosterRare; i++) { + List cards = (checkMythic() ? mythics : rares); + while (true) { + addToBooster(booster, cards); + int check = addMissingPartner(booster, partnerAllowed, -1, 1); + if (check == 1) { + break; + } + if (check == 2) { + partnerAllowed = false; + break; + } + } + } + + List basicLands = getCardsByRarity(Rarity.LAND); + for (int i = 0; i < numBoosterLands; i++) { + addToBooster(booster, basicLands); + } + + return booster; + } + + private int addMissingPartner(List booster, boolean partnerAllowed, int max, int i) { + + Card sourceCard = booster.get(booster.size() - 1); + for (Ability ability : sourceCard.getAbilities()) { + + //Check if fetched card has the PartnerWithAbility + if (ability instanceof PartnerWithAbility) { + String partnerName = ((PartnerWithAbility) ability).getPartnerName(); + //Check if the pack already contains a partner pair + if (partnerAllowed) { + //Added card always replaces an uncommon card + Card card = CardRepository.instance.findCardWPreferredSet(partnerName, sourceCard.getExpansionSetCode(), false).getCard(); + if (i < max) { + booster.add(card); + } else { + booster.set(0, card); + } + //2 return value indicates found partner + return 2; + } else { + //If partner already exists, remove card and loop again + booster.remove(booster.size() - 1); + return 0; + } + } + } + return 1; + } } diff --git a/Mage.Sets/src/mage/sets/Coldsnap.java b/Mage.Sets/src/mage/sets/Coldsnap.java index 297fb01dbf..dee3d0c599 100644 --- a/Mage.Sets/src/mage/sets/Coldsnap.java +++ b/Mage.Sets/src/mage/sets/Coldsnap.java @@ -1,4 +1,3 @@ - package mage.sets; import mage.cards.ExpansionSet; @@ -8,7 +7,6 @@ import mage.cards.repository.CardRepository; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.ArrayList; import java.util.List; /** @@ -192,23 +190,12 @@ public final class Coldsnap extends ExpansionSet { } @Override - public List getCardsByRarity(Rarity rarity) { - if (rarity != Rarity.COMMON) { - return super.getCardsByRarity(rarity); + protected List findCardsByRarity(Rarity rarity) { + List cardInfos = super.findCardsByRarity(rarity); + if (rarity == Rarity.COMMON) { + // Snow basic lands are included in boosters as regular commons + cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).rarities(Rarity.LAND))); } - List savedCardsInfos = savedCards.get(rarity); - if (savedCardsInfos != null) { - return new ArrayList(savedCardsInfos); - } - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(this.code).rarities(rarity); - savedCardsInfos = CardRepository.instance.findCards(criteria); - // Snow basic lands are included in boosters as regular commons, not in a land slot - criteria = new CardCriteria(); - criteria.setCodes(this.code).rarities(Rarity.LAND); - savedCardsInfos.addAll(CardRepository.instance.findCards(criteria)); - savedCards.put(rarity, savedCardsInfos); - // Return a copy of the saved cards information, as not to modify the original. - return new ArrayList(savedCardsInfos); + return cardInfos; } } diff --git a/Mage.Sets/src/mage/sets/CoreSet2019.java b/Mage.Sets/src/mage/sets/CoreSet2019.java index ec4614f367..1cf4c17f8d 100644 --- a/Mage.Sets/src/mage/sets/CoreSet2019.java +++ b/Mage.Sets/src/mage/sets/CoreSet2019.java @@ -1,16 +1,9 @@ package mage.sets; import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.ArrayList; -import java.util.List; - /** * @author TheElk801 */ @@ -22,13 +15,10 @@ public final class CoreSet2019 extends ExpansionSet { return instance; } - private final List savedSpecialLand = new ArrayList<>(); - private CoreSet2019() { super("Core Set 2019", "M19", ExpansionSet.buildDate(2018, 7, 13), SetType.CORE); this.hasBoosters = true; this.hasBasicLands = true; - this.numBoosterSpecial = 0; this.numBoosterLands = 1; this.numBoosterCommon = 10; this.numBoosterUncommon = 3; @@ -358,40 +348,4 @@ public final class CoreSet2019 extends ExpansionSet { cards.add(new SetCardInfo("Windreader Sphinx", 84, Rarity.RARE, mage.cards.w.WindreaderSphinx.class)); cards.add(new SetCardInfo("Woodland Stream", 260, Rarity.COMMON, mage.cards.w.WoodlandStream.class)); } - - @Override - public List getCardsByRarity(Rarity rarity) { - // Common cards retrievement of Core Set 2019 boosters - prevent the retrievement of the common lands (e.g. Meandering River) - if (rarity == Rarity.COMMON) { - List savedCardsInfos = savedCards.get(rarity); - if (savedCardsInfos == null) { - CardCriteria criteria = new CardCriteria(); - criteria.rarities(Rarity.COMMON); - criteria.setCodes(this.code).notTypes(CardType.LAND); - savedCardsInfos = CardRepository.instance.findCards(criteria); - if (maxCardNumberInBooster != Integer.MAX_VALUE) { - savedCardsInfos.removeIf(next -> next.getCardNumberAsInt() > maxCardNumberInBooster); - } - savedCards.put(rarity, savedCardsInfos); - } - // Return a copy of the saved cards information, as not to let modify the original. - return new ArrayList<>(savedCardsInfos); - } else { - return super.getCardsByRarity(rarity); - } - } - - @Override - // the common taplands replacing the basic land - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(this.code); - criteria.rarities(Rarity.COMMON); - criteria.types(CardType.LAND); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); - } - - return new ArrayList<>(savedSpecialLand); - } } diff --git a/Mage.Sets/src/mage/sets/CoreSet2020.java b/Mage.Sets/src/mage/sets/CoreSet2020.java index 6099b875cb..3b9eda3f47 100644 --- a/Mage.Sets/src/mage/sets/CoreSet2020.java +++ b/Mage.Sets/src/mage/sets/CoreSet2020.java @@ -1,16 +1,9 @@ package mage.sets; import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.ArrayList; -import java.util.List; - /** * @author TheElk801 */ @@ -22,13 +15,10 @@ public final class CoreSet2020 extends ExpansionSet { return instance; } - private final List savedSpecialLand = new ArrayList<>(); - private CoreSet2020() { super("Core Set 2020", "M20", ExpansionSet.buildDate(2019, 7, 12), SetType.CORE); this.hasBoosters = true; this.hasBasicLands = true; - this.numBoosterSpecial = 0; this.numBoosterLands = 1; this.numBoosterCommon = 10; this.numBoosterUncommon = 3; @@ -387,40 +377,4 @@ public final class CoreSet2020 extends ExpansionSet { cards.add(new SetCardInfo("Yoked Ox", 41, Rarity.COMMON, mage.cards.y.YokedOx.class)); cards.add(new SetCardInfo("Zephyr Charge", 82, Rarity.COMMON, mage.cards.z.ZephyrCharge.class)); } - - @Override - public List getCardsByRarity(Rarity rarity) { - // Common cards retrievement of Core Set 2020 boosters - prevent the retrievement of the common lands - if (rarity == Rarity.COMMON) { - List savedCardsInfos = savedCards.get(rarity); - if (savedCardsInfos == null) { - CardCriteria criteria = new CardCriteria(); - criteria.rarities(Rarity.COMMON); - criteria.setCodes(this.code).notTypes(CardType.LAND); - savedCardsInfos = CardRepository.instance.findCards(criteria); - if (maxCardNumberInBooster != Integer.MAX_VALUE) { - savedCardsInfos.removeIf(next -> next.getCardNumberAsInt() > maxCardNumberInBooster); - } - savedCards.put(rarity, savedCardsInfos); - } - // Return a copy of the saved cards information, as not to let modify the original. - return new ArrayList<>(savedCardsInfos); - } else { - return super.getCardsByRarity(rarity); - } - } - - @Override - // the common taplands replacing the basic land - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(this.code); - criteria.rarities(Rarity.COMMON); - criteria.types(CardType.LAND); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); - } - - return new ArrayList<>(savedSpecialLand); - } } diff --git a/Mage.Sets/src/mage/sets/CoreSet2021.java b/Mage.Sets/src/mage/sets/CoreSet2021.java index 0db411aaa9..bb377fdf99 100644 --- a/Mage.Sets/src/mage/sets/CoreSet2021.java +++ b/Mage.Sets/src/mage/sets/CoreSet2021.java @@ -1,14 +1,10 @@ package mage.sets; import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.ArrayList; import java.util.List; /** @@ -22,13 +18,10 @@ public final class CoreSet2021 extends ExpansionSet { return instance; } - private final List savedSpecialLand = new ArrayList<>(); - private CoreSet2021() { super("Core Set 2021", "M21", ExpansionSet.buildDate(2020, 7, 3), SetType.CORE); this.hasBoosters = true; this.hasBasicLands = true; - this.numBoosterSpecial = 0; this.numBoosterLands = 1; this.numBoosterCommon = 10; this.numBoosterUncommon = 3; @@ -437,43 +430,13 @@ public final class CoreSet2021 extends ExpansionSet { cards.add(new SetCardInfo("Witch's Cauldron", 129, Rarity.UNCOMMON, mage.cards.w.WitchsCauldron.class)); } - @Override - public List getCardsByRarity(Rarity rarity) { - if (rarity != Rarity.COMMON) { - return super.getCardsByRarity(rarity); + protected List findSpecialCardsByRarity(Rarity rarity) { + List cardInfos = super.findSpecialCardsByRarity(rarity); + if (rarity == Rarity.LAND) { + // Radiant Fountain is a normal common + cardInfos.removeIf(cardInfo -> "Radiant Fountain".equals(cardInfo.getName())); } - List savedCardsInfos = savedCards.get(rarity); - if (savedCardsInfos != null) { - return new ArrayList(savedCardsInfos); - } - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(this.code).notTypes(CardType.LAND); - criteria.rarities(rarity).doubleFaced(false); - savedCardsInfos = CardRepository.instance.findCards(criteria); - if (maxCardNumberInBooster != Integer.MAX_VALUE) { - savedCardsInfos.removeIf(next -> next.getCardNumberAsInt() > maxCardNumberInBooster); - } - criteria = new CardCriteria(); - criteria.setCodes(this.code).nameExact("Radiant Fountain"); - savedCardsInfos.addAll(CardRepository.instance.findCards(criteria)); - savedCards.put(rarity, savedCardsInfos); - // Return a copy of the saved cards information, as not to modify the original. - return new ArrayList(savedCardsInfos); - } - - @Override - // the common taplands replacing the basic land - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(this.code); - criteria.rarities(Rarity.COMMON); - criteria.types(CardType.LAND); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); - savedSpecialLand.removeIf(cardInfo -> "Radiant Fountain".equals(cardInfo.getName())); - } - - return new ArrayList<>(savedSpecialLand); + return cardInfos; } } diff --git a/Mage.Sets/src/mage/sets/DarkAscension.java b/Mage.Sets/src/mage/sets/DarkAscension.java index 930e9c466c..956e2e75c5 100644 --- a/Mage.Sets/src/mage/sets/DarkAscension.java +++ b/Mage.Sets/src/mage/sets/DarkAscension.java @@ -1,13 +1,17 @@ package mage.sets; +import mage.cards.Card; import mage.cards.ExpansionSet; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; import mage.collation.BoosterCollator; import mage.collation.BoosterStructure; import mage.collation.CardRun; import mage.collation.RarityConfiguration; import mage.constants.Rarity; import mage.constants.SetType; +import mage.util.RandomUtil; import java.util.ArrayList; import java.util.List; @@ -209,6 +213,25 @@ public final class DarkAscension extends ExpansionSet { cards.add(new SetCardInfo("Zombie Apocalypse", 80, Rarity.RARE, mage.cards.z.ZombieApocalypse.class)); } + @Override + protected void addDoubleFace(List booster) { + Rarity rarity; + for (int i = 0; i < numBoosterDoubleFaced; i++) { + int rarityKey = RandomUtil.nextInt(121); + if (rarityKey < 72) { + rarity = Rarity.COMMON; + } else if (rarityKey < 108) { + rarity = Rarity.UNCOMMON; + } else if (rarityKey < 117) { + rarity = Rarity.RARE; + } else { + rarity = Rarity.MYTHIC; + } + List doubleFacedCards = getSpecialCardsByRarity(rarity); + addToBooster(booster, doubleFacedCards); + } + } + @Override public BoosterCollator createCollator() { return new DarkAscensionCollator(); diff --git a/Mage.Sets/src/mage/sets/Dominaria.java b/Mage.Sets/src/mage/sets/Dominaria.java index 8d4a4d441c..cb6616a8c4 100644 --- a/Mage.Sets/src/mage/sets/Dominaria.java +++ b/Mage.Sets/src/mage/sets/Dominaria.java @@ -1,5 +1,6 @@ package mage.sets; +import mage.cards.Card; import mage.cards.ExpansionSet; import mage.collation.BoosterCollator; import mage.collation.BoosterStructure; @@ -32,7 +33,6 @@ public final class Dominaria extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; - this.needsLegendCreature = true; this.maxCardNumberInBooster = 269; cards.add(new SetCardInfo("Academy Drake", 40, Rarity.COMMON, mage.cards.a.AcademyDrake.class)); @@ -317,6 +317,12 @@ public final class Dominaria extends ExpansionSet { cards.add(new SetCardInfo("Zhalfirin Void", 249, Rarity.UNCOMMON, mage.cards.z.ZhalfirinVoid.class)); } + @Override + protected boolean boosterIsValid(List booster) { + return super.boosterIsValid(booster) + && booster.stream().anyMatch(card -> card.isLegendary() && card.isCreature()); + } + @Override public BoosterCollator createCollator() { return new DominariaCollator(); diff --git a/Mage.Sets/src/mage/sets/DragonsMaze.java b/Mage.Sets/src/mage/sets/DragonsMaze.java index 7e2f75227c..f8fe289a01 100644 --- a/Mage.Sets/src/mage/sets/DragonsMaze.java +++ b/Mage.Sets/src/mage/sets/DragonsMaze.java @@ -1,5 +1,6 @@ package mage.sets; +import mage.cards.Card; import mage.cards.ExpansionSet; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; @@ -7,8 +8,8 @@ import mage.cards.repository.CardRepository; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.SetType; +import mage.util.RandomUtil; -import java.util.ArrayList; import java.util.List; /** @@ -22,8 +23,6 @@ public final class DragonsMaze extends ExpansionSet { return instance; } - private final List savedSpecialRares = new ArrayList<>(); - private DragonsMaze() { super("Dragon's Maze", "DGM", ExpansionSet.buildDate(2013, 5, 3), SetType.EXPANSION); this.blockName = "Return to Ravnica"; @@ -194,61 +193,36 @@ public final class DragonsMaze extends ExpansionSet { } @Override - public List getCardsByRarity(Rarity rarity) { - if (rarity == Rarity.COMMON) { - List savedCardsInfos = savedCards.get(rarity); - if (savedCardsInfos == null) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(this.code).notTypes(CardType.LAND); - criteria.rarities(rarity).doubleFaced(false); - savedCardsInfos = CardRepository.instance.findCards(criteria); - if (maxCardNumberInBooster != Integer.MAX_VALUE) { - savedCardsInfos.removeIf(next -> next.getCardNumberAsInt() > maxCardNumberInBooster); - } - savedCards.put(rarity, savedCardsInfos); - } - // Return a copy of the saved cards information, as not to modify the original. - return new ArrayList<>(savedCardsInfos); + protected void addSpecialCards(List booster, int number) { + // number is here always 1 + // the land print sheets are believed to contain 23 copies of each Guildgate, + // one copy of each RTR and GTC shockland, and two copies of Maze's End + Rarity rarity; + int rarityKey = RandomUtil.nextInt(242); + if (rarityKey < 230) { + rarity = Rarity.COMMON; + } else if (rarityKey < 240) { + rarity = Rarity.RARE; } else { - return super.getCardsByRarity(rarity); + rarity = Rarity.MYTHIC; } + addToBooster(booster, getSpecialCardsByRarity(rarity)); } @Override - public List getSpecialCommon() { + protected List findSpecialCardsByRarity(Rarity rarity) { CardCriteria criteria = new CardCriteria(); - criteria.rarities(Rarity.COMMON).setCodes(this.code).types(CardType.LAND); - return CardRepository.instance.findCards(criteria); - } - - @Override - public List getSpecialRare() { - if (savedSpecialRares.isEmpty()) { - fillSpecialRares("GTC", "Breeding Pool"); - fillSpecialRares("GTC", "Godless Shrine"); - fillSpecialRares("GTC", "Sacred Foundry"); - fillSpecialRares("GTC", "Stomping Ground"); - fillSpecialRares("GTC", "Watery Grave"); - fillSpecialRares("RTR", "Blood Crypt"); - fillSpecialRares("RTR", "Hallowed Fountain"); - fillSpecialRares("RTR", "Overgrown Tomb"); - fillSpecialRares("RTR", "Steam Vents"); - fillSpecialRares("RTR", "Temple Garden"); + criteria.rarities(rarity).types(CardType.LAND); + if (rarity == Rarity.RARE) { + // shocklands + criteria.setCodes("RTR", "GTC"); + } else { + // Guildgates and Maze's End + criteria.setCodes(this.code); } - return new ArrayList<>(savedSpecialRares); + List cardInfos = CardRepository.instance.findCards(criteria); + cardInfos.removeIf(cardInfo -> (cardInfo.getName().equals("Grove of the Guardian") + || cardInfo.getName().equals("Thespian's Stage"))); + return cardInfos; } - - private void fillSpecialRares(String setCode, String cardName) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(setCode).name(cardName); - savedSpecialRares.addAll(CardRepository.instance.findCards(criteria)); - } - - @Override - public List getSpecialMythic() { - CardCriteria criteria = new CardCriteria(); - criteria.rarities(Rarity.MYTHIC).setCodes(this.code).types(CardType.LAND); - return CardRepository.instance.findCards(criteria); - } - } diff --git a/Mage.Sets/src/mage/sets/EldritchMoon.java b/Mage.Sets/src/mage/sets/EldritchMoon.java index a4c43aecac..f952aebb4a 100644 --- a/Mage.Sets/src/mage/sets/EldritchMoon.java +++ b/Mage.Sets/src/mage/sets/EldritchMoon.java @@ -1,8 +1,15 @@ package mage.sets; +import mage.cards.Card; import mage.cards.ExpansionSet; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; import mage.constants.Rarity; import mage.constants.SetType; +import mage.util.RandomUtil; + +import java.util.List; /** * @author fireshoes @@ -26,6 +33,7 @@ public final class EldritchMoon extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + this.ratioBoosterSpecialCommon = 8; this.numBoosterDoubleFaced = 1; cards.add(new SetCardInfo("Abandon Reason", 115, Rarity.UNCOMMON, mage.cards.a.AbandonReason.class)); @@ -252,4 +260,57 @@ public final class EldritchMoon extends ExpansionSet { cards.add(new SetCardInfo("Woodland Patrol", 180, Rarity.COMMON, mage.cards.w.WoodlandPatrol.class)); cards.add(new SetCardInfo("Wretched Gryff", 12, Rarity.COMMON, mage.cards.w.WretchedGryff.class)); } + + // add common or uncommon double faced card to booster + // 60/120 packs contain one of 4 common DFCs and 60/120 packs contain one of 10 uncommon DFCs + @Override + protected void addDoubleFace(List booster) { + Rarity rarity; + for (int i = 0; i < numBoosterDoubleFaced; i++) { + if (RandomUtil.nextInt(120) < 60) { + rarity = Rarity.COMMON; + } else { + rarity = Rarity.UNCOMMON; + } + addToBooster(booster, getSpecialCardsByRarity(rarity)); + } + } + + // Then about an eighth of the packs will have a second double-faced card, which will be a rare or mythic rare + // 10/12 of such packs contain one of 5 rare DFCs and 2/12 packs contain one of 2 mythic DFCs + @Override + protected void addSpecialCards(List booster, int number) { + // number is here always 1 + Rarity rarity; + if (RandomUtil.nextInt(12) < 10) { + rarity = Rarity.RARE; + } else { + rarity = Rarity.MYTHIC; + } + addToBooster(booster, getSpecialCardsByRarity(rarity)); + } + + // xmage doesn't recognize meldable cards as DFCs, so have to add them manually for now + private static final String[] commonMeldCards = {"Graf Rats", "Midnight Scavengers"}; + private static final String[] rareMeldCards = {"Bruna, the Fading Light", "Hanweir Battlements", "Hanweir Garrison"}; + private static final String[] mythicMeldCards = {"Gisela, the Broken Blade"}; + + @Override + protected List findSpecialCardsByRarity(Rarity rarity) { + List cardInfos = super.findSpecialCardsByRarity(rarity); + String[] meldCardNames = {}; + if (rarity == Rarity.COMMON) { + meldCardNames = commonMeldCards; + } else if (rarity == Rarity.RARE) { + meldCardNames = rareMeldCards; + } else if (rarity == Rarity.MYTHIC) { + meldCardNames = mythicMeldCards; + } + for (String name : meldCardNames) { + cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria() + .setCodes(this.code) + .nameExact(name))); + } + return cardInfos; + } } diff --git a/Mage.Sets/src/mage/sets/FateReforged.java b/Mage.Sets/src/mage/sets/FateReforged.java index 3b6abc7104..819536d0dd 100644 --- a/Mage.Sets/src/mage/sets/FateReforged.java +++ b/Mage.Sets/src/mage/sets/FateReforged.java @@ -1,9 +1,6 @@ - package mage.sets; -import java.util.ArrayList; -import java.util.List; - +import mage.cards.Card; import mage.cards.ExpansionSet; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; @@ -11,6 +8,9 @@ import mage.cards.repository.CardRepository; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.SetType; +import mage.util.RandomUtil; + +import java.util.List; /** * @author fireshoes @@ -19,9 +19,6 @@ public final class FateReforged extends ExpansionSet { private static final FateReforged instance = new FateReforged(); - private List savedSpecialRares = new ArrayList<>(); - private List savedSpecialCommon = new ArrayList<>(); - public static FateReforged getInstance() { return instance; } @@ -37,7 +34,6 @@ public final class FateReforged extends ExpansionSet { this.numBoosterCommon = 10; this.numBoosterUncommon = 3; this.numBoosterRare = 1; - this.numBoosterDoubleFaced = -1; this.ratioBoosterMythic = 8; cards.add(new SetCardInfo("Abzan Advantage", 2, Rarity.COMMON, mage.cards.a.AbzanAdvantage.class)); @@ -228,60 +224,28 @@ public final class FateReforged extends ExpansionSet { } @Override - public List getCardsByRarity(Rarity rarity) { - // Common cards retrievement of Fate Reforged boosters - prevent the retrievement of the common lands (e.g. Blossoming Sands) - if (rarity == Rarity.COMMON) { - List savedCardsInfos = savedCards.get(rarity); - if (savedCardsInfos == null) { - CardCriteria criteria = new CardCriteria(); - criteria.rarities(Rarity.COMMON); - criteria.setCodes(this.code).notTypes(CardType.LAND); - savedCardsInfos = CardRepository.instance.findCards(criteria); - if (maxCardNumberInBooster != Integer.MAX_VALUE) { - savedCardsInfos.removeIf(next -> next.getCardNumberAsInt() > maxCardNumberInBooster); - } - savedCards.put(rarity, savedCardsInfos); - } - // Return a copy of the saved cards information, as not to let modify the original. - return new ArrayList<>(savedCardsInfos); + protected void addSpecialCards(List booster, int number) { + // number is here always 1 + Rarity rarity; + if (RandomUtil.nextInt(24) < 23) { + rarity = Rarity.COMMON; } else { - return super.getCardsByRarity(rarity); + rarity = Rarity.RARE; } + addToBooster(booster, getSpecialCardsByRarity(rarity)); } @Override - public List getSpecialCommon() { - if (savedSpecialCommon.isEmpty()) { - // the 10 common lands from Fate Reforged can show up in the basic lands slot - // http://magic.wizards.com/en/articles/archive/feature/fetching-look-fate-reforged-2014-12-24 - CardCriteria criteria = new CardCriteria(); - criteria.rarities(Rarity.COMMON).setCodes(this.code).types(CardType.LAND); - savedSpecialCommon = CardRepository.instance.findCards(criteria); - criteria.rarities(Rarity.LAND).setCodes(this.code); - savedSpecialCommon.addAll(CardRepository.instance.findCards(criteria)); + protected List findSpecialCardsByRarity(Rarity rarity) { + CardCriteria criteria = new CardCriteria(); + criteria.rarities(rarity).types(CardType.LAND); + if (rarity == Rarity.RARE) { + // fetchlands + criteria.setCodes("KTK"); + } else { + // gainlands + criteria.setCodes(this.code); } - return new ArrayList<>(savedSpecialCommon); - } - - @Override - public List getSpecialRare() { - if (savedSpecialRares.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes("KTK").name("Bloodstained Mire"); - savedSpecialRares.addAll(CardRepository.instance.findCards(criteria)); - criteria = new CardCriteria(); - criteria.setCodes("KTK").name("Flooded Strand"); - savedSpecialRares.addAll(CardRepository.instance.findCards(criteria)); - criteria = new CardCriteria(); - criteria.setCodes("KTK").name("Polluted Delta"); - savedSpecialRares.addAll(CardRepository.instance.findCards(criteria)); - criteria = new CardCriteria(); - criteria.setCodes("KTK").name("Windswept Heath"); - savedSpecialRares.addAll(CardRepository.instance.findCards(criteria)); - criteria = new CardCriteria(); - criteria.setCodes("KTK").name("Wooded Foothills"); - savedSpecialRares.addAll(CardRepository.instance.findCards(criteria)); - } - return new ArrayList<>(savedSpecialRares); + return CardRepository.instance.findCards(criteria); } } diff --git a/Mage.Sets/src/mage/sets/GuildsOfRavnica.java b/Mage.Sets/src/mage/sets/GuildsOfRavnica.java index 2dcf4088b8..dc1c4412d8 100644 --- a/Mage.Sets/src/mage/sets/GuildsOfRavnica.java +++ b/Mage.Sets/src/mage/sets/GuildsOfRavnica.java @@ -1,16 +1,12 @@ package mage.sets; -import java.util.ArrayList; -import java.util.List; - import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.SetType; +import java.util.List; + public final class GuildsOfRavnica extends ExpansionSet { private static final GuildsOfRavnica instance = new GuildsOfRavnica(); @@ -23,12 +19,12 @@ public final class GuildsOfRavnica extends ExpansionSet { super("Guilds of Ravnica", "GRN", ExpansionSet.buildDate(2018, 10, 5), SetType.EXPANSION); this.blockName = "Guilds of Ravnica"; this.hasBoosters = true; - this.numBoosterSpecial = 1; - this.numBoosterLands = 0; + this.numBoosterLands = 1; this.numBoosterCommon = 10; this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + this.ratioBoosterSpecialLand = 1; // replace all basic lands this.maxCardNumberInBooster = 259; cards.add(new SetCardInfo("Affectionate Indrik", 121, Rarity.UNCOMMON, mage.cards.a.AffectionateIndrik.class)); @@ -307,40 +303,12 @@ public final class GuildsOfRavnica extends ExpansionSet { } @Override - public List getCardsByRarity(Rarity rarity) { - if (rarity == Rarity.COMMON) { - List savedCardsInfos = savedCards.get(rarity); - if (savedCardsInfos == null) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(this.code).notTypes(CardType.LAND); - criteria.rarities(rarity).doubleFaced(false); - savedCardsInfos = CardRepository.instance.findCards(criteria); - if (maxCardNumberInBooster != Integer.MAX_VALUE) { - savedCardsInfos.removeIf(next -> next.getCardNumberAsInt() > maxCardNumberInBooster); - } - criteria = new CardCriteria(); - // Gateway Plaza is a normal common: https://twitter.com/EliShffrn/status/1043156989218414593s - criteria.setCodes(this.code).nameExact("Gateway Plaza"); - savedCardsInfos.addAll(CardRepository.instance.findCards(criteria)); - savedCards.put(rarity, savedCardsInfos); - } - // Return a copy of the saved cards information, as not to modify the original. - return new ArrayList<>(savedCardsInfos); - } else { - return super.getCardsByRarity(rarity); + protected List findSpecialCardsByRarity(Rarity rarity) { + List cardInfos = super.findSpecialCardsByRarity(rarity); + if (rarity == Rarity.LAND) { + // Gateway Plaza is a normal common + cardInfos.removeIf(cardInfo -> "Gateway Plaza".equals(cardInfo.getName())); } - } - - @Override - public List getSpecialCommon() { - List specialCards = getCardsByRarity(Rarity.SPECIAL); - if (specialCards.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.rarities(Rarity.COMMON).setCodes(this.code).name("Guildgate"); - List specialCardsSave = CardRepository.instance.findCards(criteria); - savedCards.put(Rarity.SPECIAL, specialCardsSave); - specialCards.addAll(specialCardsSave); - } - return specialCards; + return cardInfos; } } diff --git a/Mage.Sets/src/mage/sets/HourOfDevastation.java b/Mage.Sets/src/mage/sets/HourOfDevastation.java index 2e6fdebbbf..95172107e2 100644 --- a/Mage.Sets/src/mage/sets/HourOfDevastation.java +++ b/Mage.Sets/src/mage/sets/HourOfDevastation.java @@ -1,4 +1,3 @@ - package mage.sets; import mage.cards.ExpansionSet; @@ -8,7 +7,6 @@ import mage.cards.repository.CardRepository; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.ArrayList; import java.util.List; /** @@ -22,8 +20,6 @@ public final class HourOfDevastation extends ExpansionSet { return instance; } - private final List savedSpecialLand = new ArrayList<>(); - private HourOfDevastation() { super("Hour of Devastation", "HOU", ExpansionSet.buildDate(2017, 7, 14), SetType.EXPANSION); this.blockName = "Amonkhet"; @@ -35,7 +31,7 @@ public final class HourOfDevastation extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; - this.ratioBoosterSpecialLand = 144; + this.ratioBoosterSpecialCommon = 129; this.maxCardNumberInBooster = 199; cards.add(new SetCardInfo("Abandoned Sarcophagus", 158, Rarity.RARE, mage.cards.a.AbandonedSarcophagus.class)); @@ -250,15 +246,12 @@ public final class HourOfDevastation extends ExpansionSet { } @Override - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes("MP2"); - criteria.minCardNumber(31); - criteria.maxCardNumber(54); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); + protected List findCardsByRarity(Rarity rarity) { + List cardInfos = super.findCardsByRarity(rarity); + if (rarity == Rarity.SPECIAL) { + cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes("MP2"))); + cardInfos.removeIf(cardInfo -> cardInfo.getCardNumberAsInt() < 31); } - - return new ArrayList<>(savedSpecialLand); + return cardInfos; } } diff --git a/Mage.Sets/src/mage/sets/IkoriaLairOfBehemoths.java b/Mage.Sets/src/mage/sets/IkoriaLairOfBehemoths.java index 277192e12b..675e014a50 100644 --- a/Mage.Sets/src/mage/sets/IkoriaLairOfBehemoths.java +++ b/Mage.Sets/src/mage/sets/IkoriaLairOfBehemoths.java @@ -1,14 +1,10 @@ package mage.sets; import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -56,8 +52,6 @@ public final class IkoriaLairOfBehemoths extends ExpansionSet { return instance; } - private final List savedSpecialLand = new ArrayList<>(); - private IkoriaLairOfBehemoths() { super("Ikoria: Lair of Behemoths", "IKO", ExpansionSet.buildDate(2020, 4, 24), SetType.EXPANSION); this.blockName = "Ikoria: Lair of Behemoths"; @@ -463,41 +457,12 @@ public final class IkoriaLairOfBehemoths extends ExpansionSet { } @Override - public List getCardsByRarity(Rarity rarity) { - if (rarity != Rarity.COMMON) { - return super.getCardsByRarity(rarity); + protected List findSpecialCardsByRarity(Rarity rarity) { + List cardInfos = super.findSpecialCardsByRarity(rarity); + if (rarity == Rarity.LAND) { + // Evolving Wilds is a normal common + cardInfos.removeIf(cardInfo -> "Evolving Wilds".equals(cardInfo.getName())); } - List savedCardsInfos = savedCards.get(rarity); - if (savedCardsInfos != null) { - return new ArrayList(savedCardsInfos); - } - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(this.code).notTypes(CardType.LAND); - criteria.rarities(rarity).doubleFaced(false); - savedCardsInfos = CardRepository.instance.findCards(criteria); - if (maxCardNumberInBooster != Integer.MAX_VALUE) { - savedCardsInfos.removeIf(next -> next.getCardNumberAsInt() > maxCardNumberInBooster); - } - criteria = new CardCriteria(); - criteria.setCodes(this.code).nameExact("Evolving Wilds"); - savedCardsInfos.addAll(CardRepository.instance.findCards(criteria)); - savedCards.put(rarity, savedCardsInfos); - // Return a copy of the saved cards information, as not to modify the original. - return new ArrayList(savedCardsInfos); - } - - @Override - // the common taplands replacing the basic land - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(this.code); - criteria.rarities(Rarity.COMMON); - criteria.types(CardType.LAND); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); - savedSpecialLand.removeIf(cardInfo -> "Evolving Wilds".equals(cardInfo.getName())); - } - - return new ArrayList(savedSpecialLand); + return cardInfos; } } diff --git a/Mage.Sets/src/mage/sets/Kaladesh.java b/Mage.Sets/src/mage/sets/Kaladesh.java index 19ea7be55a..b393ad22dc 100644 --- a/Mage.Sets/src/mage/sets/Kaladesh.java +++ b/Mage.Sets/src/mage/sets/Kaladesh.java @@ -7,7 +7,6 @@ import mage.cards.repository.CardRepository; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.ArrayList; import java.util.List; /** @@ -21,8 +20,6 @@ public final class Kaladesh extends ExpansionSet { return instance; } - private final List savedSpecialLand = new ArrayList<>(); - private Kaladesh() { super("Kaladesh", "KLD", ExpansionSet.buildDate(2016, 9, 30), SetType.EXPANSION); this.blockName = "Kaladesh"; @@ -33,9 +30,8 @@ public final class Kaladesh extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; - this.numBoosterSpecial = 0; + this.ratioBoosterSpecialCommon = 144; this.maxCardNumberInBooster = 264; - this.ratioBoosterSpecialLand = 144; cards.add(new SetCardInfo("Accomplished Automaton", 191, Rarity.COMMON, mage.cards.a.AccomplishedAutomaton.class)); cards.add(new SetCardInfo("Acrobatic Maneuver", 1, Rarity.COMMON, mage.cards.a.AcrobaticManeuver.class)); @@ -318,15 +314,12 @@ public final class Kaladesh extends ExpansionSet { } @Override - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes("MPS"); - criteria.minCardNumber(1); - criteria.maxCardNumber(30); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); + protected List findCardsByRarity(Rarity rarity) { + List cardInfos = super.findCardsByRarity(rarity); + if (rarity == Rarity.SPECIAL) { + cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes("MPS"))); + cardInfos.removeIf(cardInfo -> cardInfo.getCardNumberAsInt() > 30); } - - return new ArrayList<>(savedSpecialLand); + return cardInfos; } } diff --git a/Mage.Sets/src/mage/sets/KaladeshRemastered.java b/Mage.Sets/src/mage/sets/KaladeshRemastered.java index 89844ee738..5ddb7b4a43 100644 --- a/Mage.Sets/src/mage/sets/KaladeshRemastered.java +++ b/Mage.Sets/src/mage/sets/KaladeshRemastered.java @@ -1,11 +1,9 @@ package mage.sets; import mage.cards.ExpansionSet; -import mage.cards.repository.CardInfo; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.ArrayList; import java.util.List; /** diff --git a/Mage.Sets/src/mage/sets/Kaldheim.java b/Mage.Sets/src/mage/sets/Kaldheim.java index 060c1c4bbf..dd96f68209 100644 --- a/Mage.Sets/src/mage/sets/Kaldheim.java +++ b/Mage.Sets/src/mage/sets/Kaldheim.java @@ -1,14 +1,11 @@ package mage.sets; import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; import mage.collation.BoosterCollator; import mage.collation.BoosterStructure; import mage.collation.CardRun; import mage.collation.RarityConfiguration; -import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.SetType; import mage.constants.SuperType; @@ -27,8 +24,6 @@ public final class Kaldheim extends ExpansionSet { return instance; } - private final List savedSpecialLand = new ArrayList<>(); - private Kaldheim() { super("Kaldheim", "KHM", ExpansionSet.buildDate(2021, 2, 5), SetType.EXPANSION); this.blockName = "Kaldheim"; @@ -451,46 +446,13 @@ public final class Kaldheim extends ExpansionSet { } @Override - public List getCardsByRarity(Rarity rarity) { - if (savedCards.containsKey(rarity)) { - return new ArrayList<>(savedCards.get(rarity)); + protected List findSpecialCardsByRarity(Rarity rarity) { + List cardInfos = super.findSpecialCardsByRarity(rarity); + if (rarity == Rarity.LAND) { + // Shimmerdrift Vale is a normal common + cardInfos.removeIf(cardInfo -> "Shimmerdrift Vale".equals(cardInfo.getName())); } - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(this.code); - criteria.rarities(rarity); - List savedCardsInfos = CardRepository.instance.findCards(criteria); - switch (rarity) { - case LAND: - savedCardsInfos.removeIf(cardInfo -> !cardInfo.getSupertypes().contains(SuperType.SNOW)); - savedCardsInfos.removeIf(cardInfo -> !cardInfo.getSupertypes().contains(SuperType.BASIC)); - break; - case COMMON: - savedCardsInfos.removeIf(cardInfo -> - cardInfo.getCard().isSnow() - && cardInfo.getCard().isLand() - && !cardInfo.getCard().getName().equals("Shimmerdrift Vale") - ); - break; - } - savedCardsInfos.removeIf(next -> next.getCardNumberAsInt() > maxCardNumberInBooster); - savedCards.put(rarity, savedCardsInfos); - return new ArrayList<>(savedCardsInfos); - } - - @Override - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(this.code); - criteria.types(CardType.LAND); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); - savedSpecialLand.removeIf(cardInfo -> cardInfo.getSupertypes().contains(SuperType.BASIC)); - savedSpecialLand.removeIf(cardInfo -> !cardInfo.getSupertypes().contains(SuperType.SNOW)); - savedSpecialLand.removeIf(cardInfo -> cardInfo.getName().equals("Shimmerdrift Vale")); - savedSpecialLand.removeIf(cardInfo -> cardInfo.getName().equals("Faceless Haven")); - savedSpecialLand.removeIf(cardInfo -> cardInfo.getCardNumberAsInt() > maxCardNumberInBooster); - } - return new ArrayList<>(savedSpecialLand); + return cardInfos; } @Override diff --git a/Mage.Sets/src/mage/sets/MastersEditionIV.java b/Mage.Sets/src/mage/sets/MastersEditionIV.java index 9c6fedd163..12991d5f3b 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionIV.java +++ b/Mage.Sets/src/mage/sets/MastersEditionIV.java @@ -1,14 +1,10 @@ - package mage.sets; import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.ArrayList; import java.util.List; /** @@ -22,8 +18,6 @@ public final class MastersEditionIV extends ExpansionSet { return instance; } - private final List savedSpecialLand = new ArrayList<>(); - private MastersEditionIV() { super("Masters Edition IV", "ME4", ExpansionSet.buildDate(2011, 1, 10), SetType.MAGIC_ONLINE); this.hasBasicLands = false; @@ -305,16 +299,12 @@ public final class MastersEditionIV extends ExpansionSet { } @Override - public List getSpecialLand() { - // ME4 replace all basic lands with special (1 per booster) - // https://mtg.gamepedia.com/Masters_Edition_IV - - if (savedSpecialLand.isEmpty()) { - savedSpecialLand.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).name("Urza's Mine"))); - savedSpecialLand.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).name("Urza's Power Plant"))); - savedSpecialLand.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).name("Urza's Tower"))); + protected List findSpecialCardsByRarity(Rarity rarity) { + List cardInfos = super.findSpecialCardsByRarity(rarity); + if (rarity == Rarity.LAND) { + // Oasis is a normal common + cardInfos.removeIf(cardInfo -> "Oasis".equals(cardInfo.getName())); } - - return new ArrayList<>(savedSpecialLand); + return cardInfos; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons2.java b/Mage.Sets/src/mage/sets/ModernHorizons2.java index f8d7b6843e..168baee9ab 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons2.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons2.java @@ -2,7 +2,9 @@ package mage.sets; import mage.cards.Card; import mage.cards.ExpansionSet; +import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; import mage.collation.BoosterCollator; import mage.collation.BoosterStructure; import mage.collation.CardRun; @@ -34,6 +36,7 @@ public final class ModernHorizons2 extends ExpansionSet { this.numBoosterCommon = 10; this.numBoosterUncommon = 3; this.numBoosterRare = 1; + this.numBoosterSpecial = 1; this.ratioBoosterMythic = 7; this.maxCardNumberInBooster = 303; @@ -532,32 +535,30 @@ public final class ModernHorizons2 extends ExpansionSet { } @Override - public List tryBooster() { - List booster = super.tryBooster(); - addReprints(booster); - return booster; - } - - private void addReprints(List booster) { - final Rarity rarity; - int i = RandomUtil.nextInt(120); - if (i < 4) { + protected void addSpecialCards(List booster, int number) { + // number is here always 1 + Rarity rarity; + int rarityKey = RandomUtil.nextInt(120); + if (rarityKey < 4) { rarity = Rarity.MYTHIC; - } else if (i < 40) { + } else if (rarityKey < 40) { rarity = Rarity.RARE; } else { rarity = Rarity.UNCOMMON; } - List cards = super.getCardsByRarity(rarity); - cards.removeIf(cardInfo -> cardInfo.getCardNumberAsInt() < 262); - addToBooster(booster, cards); + List reprintCards = getSpecialCardsByRarity(rarity); + addToBooster(booster, reprintCards); } @Override - public List getCardsByRarity(Rarity rarity) { - List cards = super.getCardsByRarity(rarity); - cards.removeIf(cardInfo -> cardInfo.getCardNumberAsInt() >= 262); - return cards; + protected List findSpecialCardsByRarity(Rarity rarity) { + List cardInfos = CardRepository + .instance + .findCards(new CardCriteria().setCodes(this.code).rarities(rarity)); + cardInfos.removeIf(cardInfo -> ( + cardInfo.getCardNumberAsInt() < 262 + || cardInfo.getCardNumberAsInt() > maxCardNumberInBooster)); + return cardInfos; } @Override diff --git a/Mage.Sets/src/mage/sets/OathOfTheGatewatch.java b/Mage.Sets/src/mage/sets/OathOfTheGatewatch.java index 025e70c4c5..b09fea6761 100644 --- a/Mage.Sets/src/mage/sets/OathOfTheGatewatch.java +++ b/Mage.Sets/src/mage/sets/OathOfTheGatewatch.java @@ -7,7 +7,6 @@ import mage.cards.repository.CardRepository; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.ArrayList; import java.util.List; /** @@ -21,8 +20,6 @@ public final class OathOfTheGatewatch extends ExpansionSet { return instance; } - private final List savedSpecialLand = new ArrayList<>(); - private OathOfTheGatewatch() { super("Oath of the Gatewatch", "OGW", ExpansionSet.buildDate(2016, 1, 22), SetType.EXPANSION); this.blockName = "Battle for Zendikar"; @@ -34,7 +31,7 @@ public final class OathOfTheGatewatch extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; - this.ratioBoosterSpecialLand = 48; + this.ratioBoosterSpecialCommon = 144; cards.add(new SetCardInfo("Abstruse Interference", 40, Rarity.COMMON, mage.cards.a.AbstruseInterference.class)); cards.add(new SetCardInfo("Affa Protector", 14, Rarity.COMMON, mage.cards.a.AffaProtector.class)); @@ -226,25 +223,15 @@ public final class OathOfTheGatewatch extends ExpansionSet { } @Override - public List getCardsByRarity(Rarity rarity) { - List cards = super.getCardsByRarity(rarity); + protected List findCardsByRarity(Rarity rarity) { + List cardInfos = super.findCardsByRarity(rarity); if (rarity == Rarity.COMMON) { // only the full-art versions of Wastes are found in boosters - cards.removeIf(cardInfo -> cardInfo.getCardNumber().contains("a")); + cardInfos.removeIf(cardInfo -> cardInfo.getCardNumber().contains("a")); + } else if (rarity == Rarity.SPECIAL) { + cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes("EXP"))); + cardInfos.removeIf(cardInfo -> cardInfo.getCardNumberAsInt() < 26); } - return cards; - } - - @Override - public List getSpecialLand() { - if (savedSpecialLand.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes("EXP"); - criteria.minCardNumber(26); - criteria.maxCardNumber(45); - savedSpecialLand.addAll(CardRepository.instance.findCards(criteria)); - } - - return new ArrayList<>(savedSpecialLand); + return cardInfos; } } diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index 735ad45eb1..480b4e6b71 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -1,14 +1,10 @@ package mage.sets; import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.SetType; -import java.util.ArrayList; import java.util.List; public final class RavnicaAllegiance extends ExpansionSet { @@ -23,12 +19,12 @@ public final class RavnicaAllegiance extends ExpansionSet { super("Ravnica Allegiance", "RNA", ExpansionSet.buildDate(2019, 1, 25), SetType.EXPANSION); this.blockName = "Guilds of Ravnica"; this.hasBoosters = true; - this.numBoosterSpecial = 1; - this.numBoosterLands = 0; + this.numBoosterLands = 1; this.numBoosterCommon = 10; this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + this.ratioBoosterSpecialLand = 1; // replace all basic lands this.maxCardNumberInBooster = 259; cards.add(new SetCardInfo("Absorb", 151, Rarity.RARE, mage.cards.a.Absorb.class)); @@ -307,40 +303,12 @@ public final class RavnicaAllegiance extends ExpansionSet { } @Override - public List getCardsByRarity(Rarity rarity) { - if (rarity == Rarity.COMMON) { - List savedCardsInfos = savedCards.get(rarity); - if (savedCardsInfos == null) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(this.code).notTypes(CardType.LAND); - criteria.rarities(rarity).doubleFaced(false); - savedCardsInfos = CardRepository.instance.findCards(criteria); - if (maxCardNumberInBooster != Integer.MAX_VALUE) { - savedCardsInfos.removeIf(next -> next.getCardNumberAsInt() > maxCardNumberInBooster); - } - criteria = new CardCriteria(); - // Gateway Plaza is a normal common: https://twitter.com/EliShffrn/status/1043156989218414593s - criteria.setCodes(this.code).nameExact("Gateway Plaza"); - savedCardsInfos.addAll(CardRepository.instance.findCards(criteria)); - savedCards.put(rarity, savedCardsInfos); - } - // Return a copy of the saved cards information, as not to modify the original. - return new ArrayList<>(savedCardsInfos); - } else { - return super.getCardsByRarity(rarity); + protected List findSpecialCardsByRarity(Rarity rarity) { + List cardInfos = super.findSpecialCardsByRarity(rarity); + if (rarity == Rarity.LAND) { + // Gateway Plaza is a normal common + cardInfos.removeIf(cardInfo -> "Gateway Plaza".equals(cardInfo.getName())); } - } - - @Override - public List getSpecialCommon() { - List specialCards = getCardsByRarity(Rarity.SPECIAL); - if (specialCards.isEmpty()) { - CardCriteria criteria = new CardCriteria(); - criteria.rarities(Rarity.COMMON).setCodes(this.code).name("Guildgate"); - List specialCardsSave = CardRepository.instance.findCards(criteria); - savedCards.put(Rarity.SPECIAL, specialCardsSave); - specialCards.addAll(specialCardsSave); - } - return specialCards; + return cardInfos; } } diff --git a/Mage.Sets/src/mage/sets/ShadowsOverInnistrad.java b/Mage.Sets/src/mage/sets/ShadowsOverInnistrad.java index 186098b1f5..cbc0699a32 100644 --- a/Mage.Sets/src/mage/sets/ShadowsOverInnistrad.java +++ b/Mage.Sets/src/mage/sets/ShadowsOverInnistrad.java @@ -2,15 +2,10 @@ package mage.sets; import mage.cards.Card; import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; import mage.constants.Rarity; import mage.constants.SetType; import mage.util.RandomUtil; -import java.util.ArrayList; -import java.util.EnumMap; import java.util.List; /** @@ -24,8 +19,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet { return instance; } - private final EnumMap> savedDoubleFacedCards; - private ShadowsOverInnistrad() { super("Shadows over Innistrad", "SOI", ExpansionSet.buildDate(2016, 4, 8), SetType.EXPANSION); this.blockName = "Shadows over Innistrad"; @@ -36,10 +29,9 @@ public final class ShadowsOverInnistrad extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + this.ratioBoosterSpecialCommon = 8; this.numBoosterDoubleFaced = 1; - savedDoubleFacedCards = new EnumMap<>(Rarity.class); - cards.add(new SetCardInfo("Aberrant Researcher", 49, Rarity.UNCOMMON, mage.cards.a.AberrantResearcher.class)); cards.add(new SetCardInfo("Accursed Witch", 97, Rarity.UNCOMMON, mage.cards.a.AccursedWitch.class)); cards.add(new SetCardInfo("Aim High", 193, Rarity.COMMON, mage.cards.a.AimHigh.class)); @@ -377,53 +369,32 @@ public final class ShadowsOverInnistrad extends ExpansionSet { cards.add(new SetCardInfo("Woodland Stream", 282, Rarity.UNCOMMON, mage.cards.w.WoodlandStream.class)); } - /* add double faced card for SOI booster - * add only common or uncommon - 80/120 packs contain one of 20 uncommon DFCs and 40/120 packs contain one of 4 common DFCs - */ + // add common or uncommon double faced card to booster + // 40/120 packs contain one of 4 common DFCs and 80/120 packs contain one of 20 uncommon DFCs @Override - public void addDoubleFace(List booster) { + protected void addDoubleFace(List booster) { + Rarity rarity; for (int i = 0; i < numBoosterDoubleFaced; i++) { - List doubleFacedCards; - if (RandomUtil.nextInt(15) < 10) { - doubleFacedCards = getDoubleFacedCardsByRarity(Rarity.UNCOMMON); + if (RandomUtil.nextInt(120) < 40) { + rarity = Rarity.COMMON; } else { - doubleFacedCards = getDoubleFacedCardsByRarity(Rarity.COMMON); + rarity = Rarity.UNCOMMON; } - addToBooster(booster, doubleFacedCards); + addToBooster(booster, getSpecialCardsByRarity(rarity)); } } - private List getDoubleFacedCardsByRarity(Rarity rarity) { - List savedCardsInfos = savedDoubleFacedCards.get(rarity); - if (savedCardsInfos == null) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(getCode()); - criteria.rarities(rarity); - criteria.doubleFaced(true); - savedCardsInfos = CardRepository.instance.findCards(criteria); - savedDoubleFacedCards.put(rarity, savedCardsInfos); - } - // Return a copy of the saved cards information, as not to let modify the original. - return new ArrayList<>(savedCardsInfos); - } - + // Then about an eighth of the packs will have a second double-faced card, which will be a rare or mythic rare + // 12/15 of such packs contain one of 6 rare DFCs and 3/15 packs contain one of 3 mythic DFCs @Override - public int getNumberOfSpecialCommons() { - // Then about an eighth of the packs will have a second double-faced card, which will be a rare or mythic rare. - return RandomUtil.nextInt(8) == 0 ? 1 : 0; - } - - @Override - public void addSpecialCommon(List booster, int number) { + protected void addSpecialCards(List booster, int number) { // number is here always 1 - List doubleFacedCards; - if (RandomUtil.nextInt(8) > 0) { - doubleFacedCards = getDoubleFacedCardsByRarity(Rarity.RARE); + Rarity rarity; + if (RandomUtil.nextInt(15) < 12) { + rarity = Rarity.RARE; } else { - doubleFacedCards = getDoubleFacedCardsByRarity(Rarity.MYTHIC); + rarity = Rarity.MYTHIC; } - addToBooster(booster, doubleFacedCards); + addToBooster(booster, getSpecialCardsByRarity(rarity)); } - } diff --git a/Mage.Sets/src/mage/sets/StrixhavenSchoolOfMages.java b/Mage.Sets/src/mage/sets/StrixhavenSchoolOfMages.java index d9c1aaa788..6f397e65c9 100644 --- a/Mage.Sets/src/mage/sets/StrixhavenSchoolOfMages.java +++ b/Mage.Sets/src/mage/sets/StrixhavenSchoolOfMages.java @@ -36,6 +36,7 @@ public final class StrixhavenSchoolOfMages extends ExpansionSet { this.numBoosterCommon = 9; this.numBoosterUncommon = 3; this.numBoosterRare = 1; + this.numBoosterSpecial = 2; this.ratioBoosterMythic = 7.4; this.maxCardNumberInBooster = 275; @@ -424,50 +425,43 @@ public final class StrixhavenSchoolOfMages extends ExpansionSet { } @Override - public List tryBooster() { - List booster = super.tryBooster(); - addArchive(booster); - addLesson(booster); - return booster; - } - - private void addArchive(List booster) { + protected void addSpecialCards(List booster, int number) { + // number is here always 2 // Boosters have one card from STA, odds are 2/3 for uncommon, 4/15 for rare, 1/15 for mythic - final Rarity rarity; - int i = RandomUtil.nextInt(15); - if (i == 14) { + Rarity rarity; + int rarityKey = RandomUtil.nextInt(15); + if (rarityKey == 14) { rarity = Rarity.MYTHIC; - } else if (i >= 10) { + } else if (rarityKey >= 10) { rarity = Rarity.RARE; } else { rarity = Rarity.UNCOMMON; } addToBooster(booster, StrixhavenMysticalArchive.getInstance().getCardsByRarity(rarity)); - } - private void addLesson(List booster) { // Boosters have one Lesson card - final Rarity rarity; - int i = RandomUtil.nextInt(148); - if (i == 0) { + rarityKey = RandomUtil.nextInt(148); + if (rarityKey == 0) { rarity = Rarity.MYTHIC; - } else if (i < 11) { + } else if (rarityKey < 11) { rarity = Rarity.RARE; } else { rarity = Rarity.COMMON; } - List cards = super.getCardsByRarity(rarity); - cards.removeIf(cardInfo -> !cardInfo.getCard().hasSubtype(SubType.LESSON, null)); - addToBooster(booster, cards); + addToBooster(booster, getSpecialCardsByRarity(rarity)); } @Override - public List getCardsByRarity(Rarity rarity) { - List cards = super.getCardsByRarity(rarity); + protected List findSpecialCardsByRarity(Rarity rarity) { + List cardInfos = super.findSpecialCardsByRarity(rarity); if (rarity != Rarity.UNCOMMON) { - cards.removeIf(cardInfo -> cardInfo.getCard().hasSubtype(SubType.LESSON, null)); + cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria() + .setCodes(this.code) + .rarities(rarity) + .subtypes("Lesson"))); + cardInfos.removeIf(cardInfo -> cardInfo.getCardNumberAsInt() > maxCardNumberInBooster); } - return cards; + return cardInfos; } @Override diff --git a/Mage.Sets/src/mage/sets/TimeSpiral.java b/Mage.Sets/src/mage/sets/TimeSpiral.java index 1e80b06faa..94047a0d74 100644 --- a/Mage.Sets/src/mage/sets/TimeSpiral.java +++ b/Mage.Sets/src/mage/sets/TimeSpiral.java @@ -1,8 +1,8 @@ package mage.sets; -import mage.cards.Card; import mage.cards.ExpansionSet; import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.constants.Rarity; import mage.constants.SetType; @@ -25,7 +25,9 @@ public final class TimeSpiral extends ExpansionSet { this.numBoosterCommon = 10; this.numBoosterUncommon = 3; this.numBoosterRare = 1; + this.numBoosterSpecial = 1; this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Academy Ruins", 269, Rarity.RARE, mage.cards.a.AcademyRuins.class)); cards.add(new SetCardInfo("Aether Web", 189, Rarity.COMMON, mage.cards.a.AetherWeb.class)); cards.add(new SetCardInfo("Aetherflame Wall", 142, Rarity.COMMON, mage.cards.a.AetherflameWall.class)); @@ -330,11 +332,11 @@ public final class TimeSpiral extends ExpansionSet { } @Override - public List createBooster() { - List booster = super.createBooster(); - CardCriteria criteria = new CardCriteria(); - criteria.rarities(Rarity.SPECIAL).setCodes("TSB"); - addToBooster(booster, CardRepository.instance.findCards(criteria)); - return booster; + protected List findCardsByRarity(Rarity rarity) { + List cardInfos = super.findCardsByRarity(rarity); + if (rarity == Rarity.SPECIAL) { + cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes("TSB"))); + } + return cardInfos; } } diff --git a/Mage.Sets/src/mage/sets/TimeSpiralRemastered.java b/Mage.Sets/src/mage/sets/TimeSpiralRemastered.java index 431c3b0731..5fcd4f9040 100644 --- a/Mage.Sets/src/mage/sets/TimeSpiralRemastered.java +++ b/Mage.Sets/src/mage/sets/TimeSpiralRemastered.java @@ -1,9 +1,6 @@ package mage.sets; import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; import mage.collation.BoosterCollator; import mage.collation.BoosterStructure; import mage.collation.CardRun; @@ -25,8 +22,6 @@ public class TimeSpiralRemastered extends ExpansionSet { return instance; } - private final List savedSpecialBonus = new ArrayList<>(); - private TimeSpiralRemastered() { super("Time Spiral Remastered", "TSR", ExpansionSet.buildDate(2021, 3, 19), SetType.SUPPLEMENTAL); this.hasBoosters = true; @@ -451,17 +446,6 @@ public class TimeSpiralRemastered extends ExpansionSet { cards.add(new SetCardInfo("Zulaport Cutthroat", 337, Rarity.SPECIAL, mage.cards.z.ZulaportCutthroat.class)); } - @Override - public List getSpecialBonus() { - if (savedSpecialBonus.isEmpty()) { - savedSpecialBonus.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code))); - savedSpecialBonus.removeIf(cardInfo -> cardInfo.getCardNumberAsInt() > 410); - savedSpecialBonus.removeIf(cardInfo -> cardInfo.getCardNumberAsInt() <= 289); - } - - return new ArrayList<>(savedSpecialBonus); - } - @Override public BoosterCollator createCollator() { return new TimeSpiralRemasteredCollator(); diff --git a/Mage.Sets/src/mage/sets/TimeSpiralTimeshifted.java b/Mage.Sets/src/mage/sets/TimeSpiralTimeshifted.java index 350e324ddc..ed1e4c0565 100644 --- a/Mage.Sets/src/mage/sets/TimeSpiralTimeshifted.java +++ b/Mage.Sets/src/mage/sets/TimeSpiralTimeshifted.java @@ -24,31 +24,31 @@ public final class TimeSpiralTimeshifted extends ExpansionSet { cards.add(new SetCardInfo("Akroma, Angel of Wrath", 1, Rarity.SPECIAL, mage.cards.a.AkromaAngelOfWrath.class)); cards.add(new SetCardInfo("Arena", 117, Rarity.SPECIAL, mage.cards.a.Arena.class)); cards.add(new SetCardInfo("Assault // Battery", 106, Rarity.SPECIAL, mage.cards.a.AssaultBattery.class)); - cards.add(new SetCardInfo("Auratog", 2, Rarity.COMMON, mage.cards.a.Auratog.class)); - cards.add(new SetCardInfo("Avalanche Riders", 55, Rarity.COMMON, mage.cards.a.AvalancheRiders.class)); + cards.add(new SetCardInfo("Auratog", 2, Rarity.SPECIAL, mage.cards.a.Auratog.class)); + cards.add(new SetCardInfo("Avalanche Riders", 55, Rarity.SPECIAL, mage.cards.a.AvalancheRiders.class)); cards.add(new SetCardInfo("Avatar of Woe", 37, Rarity.SPECIAL, mage.cards.a.AvatarOfWoe.class)); cards.add(new SetCardInfo("Avoid Fate", 73, Rarity.SPECIAL, mage.cards.a.AvoidFate.class)); - cards.add(new SetCardInfo("Bad Moon", 38, Rarity.RARE, mage.cards.b.BadMoon.class)); + cards.add(new SetCardInfo("Bad Moon", 38, Rarity.SPECIAL, mage.cards.b.BadMoon.class)); cards.add(new SetCardInfo("Browbeat", 56, Rarity.SPECIAL, mage.cards.b.Browbeat.class)); - cards.add(new SetCardInfo("Call of the Herd", 74, Rarity.COMMON, mage.cards.c.CallOfTheHerd.class)); + cards.add(new SetCardInfo("Call of the Herd", 74, Rarity.SPECIAL, mage.cards.c.CallOfTheHerd.class)); cards.add(new SetCardInfo("Celestial Dawn", 3, Rarity.SPECIAL, mage.cards.c.CelestialDawn.class)); - cards.add(new SetCardInfo("Claws of Gix", 107, Rarity.COMMON, mage.cards.c.ClawsOfGix.class)); - cards.add(new SetCardInfo("Coalition Victory", 91, Rarity.RARE, mage.cards.c.CoalitionVictory.class)); + cards.add(new SetCardInfo("Claws of Gix", 107, Rarity.SPECIAL, mage.cards.c.ClawsOfGix.class)); + cards.add(new SetCardInfo("Coalition Victory", 91, Rarity.SPECIAL, mage.cards.c.CoalitionVictory.class)); cards.add(new SetCardInfo("Cockatrice", 75, Rarity.SPECIAL, mage.cards.c.Cockatrice.class)); cards.add(new SetCardInfo("Consecrate Land", 4, Rarity.SPECIAL, mage.cards.c.ConsecrateLand.class)); cards.add(new SetCardInfo("Conspiracy", 39, Rarity.SPECIAL, mage.cards.c.Conspiracy.class)); cards.add(new SetCardInfo("Craw Giant", 76, Rarity.SPECIAL, mage.cards.c.CrawGiant.class)); cards.add(new SetCardInfo("Dandan", 19, Rarity.SPECIAL, mage.cards.d.Dandan.class)); - cards.add(new SetCardInfo("Darkness", 40, Rarity.COMMON, mage.cards.d.Darkness.class)); - cards.add(new SetCardInfo("Dauthi Slayer", 41, Rarity.COMMON, mage.cards.d.DauthiSlayer.class)); + cards.add(new SetCardInfo("Darkness", 40, Rarity.SPECIAL, mage.cards.d.Darkness.class)); + cards.add(new SetCardInfo("Dauthi Slayer", 41, Rarity.SPECIAL, mage.cards.d.DauthiSlayer.class)); cards.add(new SetCardInfo("Defiant Vanguard", 5, Rarity.SPECIAL, mage.cards.d.DefiantVanguard.class)); cards.add(new SetCardInfo("Desert", 118, Rarity.SPECIAL, mage.cards.d.Desert.class)); cards.add(new SetCardInfo("Desolation Giant", 57, Rarity.SPECIAL, mage.cards.d.DesolationGiant.class)); - cards.add(new SetCardInfo("Disenchant", 6, Rarity.COMMON, mage.cards.d.Disenchant.class)); + cards.add(new SetCardInfo("Disenchant", 6, Rarity.SPECIAL, mage.cards.d.Disenchant.class)); cards.add(new SetCardInfo("Disintegrate", 58, Rarity.SPECIAL, mage.cards.d.Disintegrate.class)); cards.add(new SetCardInfo("Dodecapod", 108, Rarity.SPECIAL, mage.cards.d.Dodecapod.class)); cards.add(new SetCardInfo("Dragonstorm", 60, Rarity.SPECIAL, mage.cards.d.Dragonstorm.class)); - cards.add(new SetCardInfo("Dragon Whelp", 59, Rarity.COMMON, mage.cards.d.DragonWhelp.class)); + cards.add(new SetCardInfo("Dragon Whelp", 59, Rarity.SPECIAL, mage.cards.d.DragonWhelp.class)); cards.add(new SetCardInfo("Enduring Renewal", 7, Rarity.SPECIAL, mage.cards.e.EnduringRenewal.class)); cards.add(new SetCardInfo("Eron the Relentless", 61, Rarity.SPECIAL, mage.cards.e.EronTheRelentless.class)); cards.add(new SetCardInfo("Essence Sliver", 8, Rarity.SPECIAL, mage.cards.e.EssenceSliver.class)); @@ -58,43 +58,43 @@ public final class TimeSpiralTimeshifted extends ExpansionSet { cards.add(new SetCardInfo("Fiery Justice", 92, Rarity.SPECIAL, mage.cards.f.FieryJustice.class)); cards.add(new SetCardInfo("Fiery Temper", 62, Rarity.SPECIAL, mage.cards.f.FieryTemper.class)); cards.add(new SetCardInfo("Fire Whip", 63, Rarity.SPECIAL, mage.cards.f.FireWhip.class)); - cards.add(new SetCardInfo("Flying Men", 20, Rarity.COMMON, mage.cards.f.FlyingMen.class)); - cards.add(new SetCardInfo("Funeral Charm", 44, Rarity.COMMON, mage.cards.f.FuneralCharm.class)); + cards.add(new SetCardInfo("Flying Men", 20, Rarity.SPECIAL, mage.cards.f.FlyingMen.class)); + cards.add(new SetCardInfo("Funeral Charm", 44, Rarity.SPECIAL, mage.cards.f.FuneralCharm.class)); cards.add(new SetCardInfo("Gaea's Blessing", 77, Rarity.SPECIAL, mage.cards.g.GaeasBlessing.class)); cards.add(new SetCardInfo("Gaea's Liege", 78, Rarity.SPECIAL, mage.cards.g.GaeasLiege.class)); - cards.add(new SetCardInfo("Gemstone Mine", 119, Rarity.RARE, mage.cards.g.GemstoneMine.class)); + cards.add(new SetCardInfo("Gemstone Mine", 119, Rarity.SPECIAL, mage.cards.g.GemstoneMine.class)); cards.add(new SetCardInfo("Ghost Ship", 21, Rarity.SPECIAL, mage.cards.g.GhostShip.class)); cards.add(new SetCardInfo("Giant Oyster", 22, Rarity.SPECIAL, mage.cards.g.GiantOyster.class)); - cards.add(new SetCardInfo("Goblin Snowman", 64, Rarity.UNCOMMON, mage.cards.g.GoblinSnowman.class)); + cards.add(new SetCardInfo("Goblin Snowman", 64, Rarity.SPECIAL, mage.cards.g.GoblinSnowman.class)); cards.add(new SetCardInfo("Grinning Totem", 110, Rarity.SPECIAL, mage.cards.g.GrinningTotem.class)); cards.add(new SetCardInfo("Hail Storm", 79, Rarity.SPECIAL, mage.cards.h.HailStorm.class)); cards.add(new SetCardInfo("Honorable Passage", 9, Rarity.SPECIAL, mage.cards.h.HonorablePassage.class)); - cards.add(new SetCardInfo("Hunting Moa", 80, Rarity.COMMON, mage.cards.h.HuntingMoa.class)); + cards.add(new SetCardInfo("Hunting Moa", 80, Rarity.SPECIAL, mage.cards.h.HuntingMoa.class)); cards.add(new SetCardInfo("Icatian Javelineers", 10, Rarity.SPECIAL, mage.cards.i.IcatianJavelineers.class)); - cards.add(new SetCardInfo("Jasmine Boreal", 93, Rarity.COMMON, mage.cards.j.JasmineBoreal.class)); + cards.add(new SetCardInfo("Jasmine Boreal", 93, Rarity.SPECIAL, mage.cards.j.JasmineBoreal.class)); cards.add(new SetCardInfo("Jolrael, Empress of Beasts", 81, Rarity.SPECIAL, mage.cards.j.JolraelEmpressOfBeasts.class)); cards.add(new SetCardInfo("Kobold Taskmaster", 65, Rarity.SPECIAL, mage.cards.k.KoboldTaskmaster.class)); cards.add(new SetCardInfo("Krosan Cloudscraper", 82, Rarity.SPECIAL, mage.cards.k.KrosanCloudscraper.class)); - cards.add(new SetCardInfo("Leviathan", 23, Rarity.RARE, mage.cards.l.Leviathan.class)); - cards.add(new SetCardInfo("Lightning Angel", 94, Rarity.COMMON, mage.cards.l.LightningAngel.class)); - cards.add(new SetCardInfo("Lord of Atlantis", 24, Rarity.RARE, mage.cards.l.LordOfAtlantis.class)); + cards.add(new SetCardInfo("Leviathan", 23, Rarity.SPECIAL, mage.cards.l.Leviathan.class)); + cards.add(new SetCardInfo("Lightning Angel", 94, Rarity.SPECIAL, mage.cards.l.LightningAngel.class)); + cards.add(new SetCardInfo("Lord of Atlantis", 24, Rarity.SPECIAL, mage.cards.l.LordOfAtlantis.class)); cards.add(new SetCardInfo("Merfolk Assassin", 25, Rarity.SPECIAL, mage.cards.m.MerfolkAssassin.class)); cards.add(new SetCardInfo("Merieke Ri Berit", 95, Rarity.SPECIAL, mage.cards.m.MeriekeRiBerit.class)); cards.add(new SetCardInfo("Mindless Automaton", 111, Rarity.SPECIAL, mage.cards.m.MindlessAutomaton.class)); cards.add(new SetCardInfo("Mirari", 112, Rarity.SPECIAL, mage.cards.m.Mirari.class)); cards.add(new SetCardInfo("Mistform Ultimus", 26, Rarity.SPECIAL, mage.cards.m.MistformUltimus.class)); - cards.add(new SetCardInfo("Moorish Cavalry", 11, Rarity.COMMON, mage.cards.m.MoorishCavalry.class)); + cards.add(new SetCardInfo("Moorish Cavalry", 11, Rarity.SPECIAL, mage.cards.m.MoorishCavalry.class)); cards.add(new SetCardInfo("Mystic Enforcer", 96, Rarity.SPECIAL, mage.cards.m.MysticEnforcer.class)); - cards.add(new SetCardInfo("Mystic Snake", 97, Rarity.COMMON, mage.cards.m.MysticSnake.class)); + cards.add(new SetCardInfo("Mystic Snake", 97, Rarity.SPECIAL, mage.cards.m.MysticSnake.class)); cards.add(new SetCardInfo("Nicol Bolas", 98, Rarity.SPECIAL, mage.cards.n.NicolBolas.class)); cards.add(new SetCardInfo("Orcish Librarian", 66, Rarity.SPECIAL, mage.cards.o.OrcishLibrarian.class)); cards.add(new SetCardInfo("Orgg", 67, Rarity.SPECIAL, mage.cards.o.Orgg.class)); cards.add(new SetCardInfo("Ovinomancer", 27, Rarity.SPECIAL, mage.cards.o.Ovinomancer.class)); cards.add(new SetCardInfo("Pandemonium", 68, Rarity.SPECIAL, mage.cards.p.Pandemonium.class)); - cards.add(new SetCardInfo("Pendelhaven", 120, Rarity.COMMON, mage.cards.p.Pendelhaven.class)); + cards.add(new SetCardInfo("Pendelhaven", 120, Rarity.SPECIAL, mage.cards.p.Pendelhaven.class)); cards.add(new SetCardInfo("Pirate Ship", 28, Rarity.SPECIAL, mage.cards.p.PirateShip.class)); - cards.add(new SetCardInfo("Prodigal Sorcerer", 29, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class)); - cards.add(new SetCardInfo("Psionic Blast", 30, Rarity.COMMON, mage.cards.p.PsionicBlast.class)); + cards.add(new SetCardInfo("Prodigal Sorcerer", 29, Rarity.SPECIAL, mage.cards.p.ProdigalSorcerer.class)); + cards.add(new SetCardInfo("Psionic Blast", 30, Rarity.SPECIAL, mage.cards.p.PsionicBlast.class)); cards.add(new SetCardInfo("Resurrection", 12, Rarity.SPECIAL, mage.cards.r.Resurrection.class)); cards.add(new SetCardInfo("Sacred Mesa", 13, Rarity.SPECIAL, mage.cards.s.SacredMesa.class)); cards.add(new SetCardInfo("Safe Haven", 121, Rarity.SPECIAL, mage.cards.s.SafeHaven.class)); @@ -102,29 +102,29 @@ public final class TimeSpiralTimeshifted extends ExpansionSet { cards.add(new SetCardInfo("Sengir Autocrat", 45, Rarity.SPECIAL, mage.cards.s.SengirAutocrat.class)); cards.add(new SetCardInfo("Serrated Arrows", 114, Rarity.SPECIAL, mage.cards.s.SerratedArrows.class)); cards.add(new SetCardInfo("Shadow Guildmage", 46, Rarity.SPECIAL, mage.cards.s.ShadowGuildmage.class)); - cards.add(new SetCardInfo("Shadowmage Infiltrator", 99, Rarity.COMMON, mage.cards.s.ShadowmageInfiltrator.class)); + cards.add(new SetCardInfo("Shadowmage Infiltrator", 99, Rarity.SPECIAL, mage.cards.s.ShadowmageInfiltrator.class)); cards.add(new SetCardInfo("Sindbad", 31, Rarity.SPECIAL, mage.cards.s.Sindbad.class)); - cards.add(new SetCardInfo("Sol'kanar the Swamp King", 100, Rarity.COMMON, mage.cards.s.SolkanarTheSwampKing.class)); - cards.add(new SetCardInfo("Soltari Priest", 14, Rarity.COMMON, mage.cards.s.SoltariPriest.class)); + cards.add(new SetCardInfo("Sol'kanar the Swamp King", 100, Rarity.SPECIAL, mage.cards.s.SolkanarTheSwampKing.class)); + cards.add(new SetCardInfo("Soltari Priest", 14, Rarity.SPECIAL, mage.cards.s.SoltariPriest.class)); cards.add(new SetCardInfo("Soul Collector", 47, Rarity.SPECIAL, mage.cards.s.SoulCollector.class)); - cards.add(new SetCardInfo("Spike Feeder", 84, Rarity.COMMON, mage.cards.s.SpikeFeeder.class)); + cards.add(new SetCardInfo("Spike Feeder", 84, Rarity.SPECIAL, mage.cards.s.SpikeFeeder.class)); cards.add(new SetCardInfo("Spined Sliver", 101, Rarity.SPECIAL, mage.cards.s.SpinedSliver.class)); cards.add(new SetCardInfo("Spitting Slug", 85, Rarity.SPECIAL, mage.cards.s.SpittingSlug.class)); - cards.add(new SetCardInfo("Squire", 15, Rarity.COMMON, mage.cards.s.Squire.class)); + cards.add(new SetCardInfo("Squire", 15, Rarity.SPECIAL, mage.cards.s.Squire.class)); cards.add(new SetCardInfo("Stormbind", 102, Rarity.SPECIAL, mage.cards.s.Stormbind.class)); - cards.add(new SetCardInfo("Stormscape Familiar", 32, Rarity.COMMON, mage.cards.s.StormscapeFamiliar.class)); - cards.add(new SetCardInfo("Stupor", 48, Rarity.COMMON, mage.cards.s.Stupor.class)); - cards.add(new SetCardInfo("Suq'Ata Lancer", 69, Rarity.COMMON, mage.cards.s.SuqAtaLancer.class)); + cards.add(new SetCardInfo("Stormscape Familiar", 32, Rarity.SPECIAL, mage.cards.s.StormscapeFamiliar.class)); + cards.add(new SetCardInfo("Stupor", 48, Rarity.SPECIAL, mage.cards.s.Stupor.class)); + cards.add(new SetCardInfo("Suq'Ata Lancer", 69, Rarity.SPECIAL, mage.cards.s.SuqAtaLancer.class)); cards.add(new SetCardInfo("Swamp Mosquito", 49, Rarity.SPECIAL, mage.cards.s.SwampMosquito.class)); cards.add(new SetCardInfo("Teferi's Moat", 103, Rarity.SPECIAL, mage.cards.t.TeferisMoat.class)); - cards.add(new SetCardInfo("Thallid", 86, Rarity.COMMON, mage.cards.t.Thallid.class)); + cards.add(new SetCardInfo("Thallid", 86, Rarity.SPECIAL, mage.cards.t.Thallid.class)); cards.add(new SetCardInfo("The Rack", 113, Rarity.SPECIAL, mage.cards.t.TheRack.class)); cards.add(new SetCardInfo("Thornscape Battlemage", 87, Rarity.SPECIAL, mage.cards.t.ThornscapeBattlemage.class)); - cards.add(new SetCardInfo("Tormod's Crypt", 115, Rarity.COMMON, mage.cards.t.TormodsCrypt.class)); - cards.add(new SetCardInfo("Tribal Flames", 70, Rarity.COMMON, mage.cards.t.TribalFlames.class)); - cards.add(new SetCardInfo("Twisted Abomination", 50, Rarity.COMMON, mage.cards.t.TwistedAbomination.class)); + cards.add(new SetCardInfo("Tormod's Crypt", 115, Rarity.SPECIAL, mage.cards.t.TormodsCrypt.class)); + cards.add(new SetCardInfo("Tribal Flames", 70, Rarity.SPECIAL, mage.cards.t.TribalFlames.class)); + cards.add(new SetCardInfo("Twisted Abomination", 50, Rarity.SPECIAL, mage.cards.t.TwistedAbomination.class)); cards.add(new SetCardInfo("Uncle Istvan", 51, Rarity.SPECIAL, mage.cards.u.UncleIstvan.class)); - cards.add(new SetCardInfo("Undead Warchief", 52, Rarity.UNCOMMON, mage.cards.u.UndeadWarchief.class)); + cards.add(new SetCardInfo("Undead Warchief", 52, Rarity.SPECIAL, mage.cards.u.UndeadWarchief.class)); cards.add(new SetCardInfo("Undertaker", 53, Rarity.SPECIAL, mage.cards.u.Undertaker.class)); cards.add(new SetCardInfo("Unstable Mutation", 33, Rarity.SPECIAL, mage.cards.u.UnstableMutation.class)); cards.add(new SetCardInfo("Uthden Troll", 71, Rarity.SPECIAL, mage.cards.u.UthdenTroll.class)); @@ -133,14 +133,14 @@ public final class TimeSpiralTimeshifted extends ExpansionSet { cards.add(new SetCardInfo("Vhati il-Dal", 104, Rarity.SPECIAL, mage.cards.v.VhatiIlDal.class)); cards.add(new SetCardInfo("Void", 105, Rarity.SPECIAL, mage.cards.v.Void.class)); cards.add(new SetCardInfo("Voidmage Prodigy", 34, Rarity.SPECIAL, mage.cards.v.VoidmageProdigy.class)); - cards.add(new SetCardInfo("Wall of Roots", 89, Rarity.COMMON, mage.cards.w.WallOfRoots.class)); + cards.add(new SetCardInfo("Wall of Roots", 89, Rarity.SPECIAL, mage.cards.w.WallOfRoots.class)); cards.add(new SetCardInfo("War Barge", 116, Rarity.SPECIAL, mage.cards.w.WarBarge.class)); - cards.add(new SetCardInfo("Whirling Dervish", 90, Rarity.COMMON, mage.cards.w.WhirlingDervish.class)); + cards.add(new SetCardInfo("Whirling Dervish", 90, Rarity.SPECIAL, mage.cards.w.WhirlingDervish.class)); cards.add(new SetCardInfo("Whispers of the Muse", 35, Rarity.SPECIAL, mage.cards.w.WhispersOfTheMuse.class)); cards.add(new SetCardInfo("Wildfire Emissary", 72, Rarity.SPECIAL, mage.cards.w.WildfireEmissary.class)); cards.add(new SetCardInfo("Willbender", 36, Rarity.SPECIAL, mage.cards.w.Willbender.class)); cards.add(new SetCardInfo("Witch Hunter", 17, Rarity.SPECIAL, mage.cards.w.WitchHunter.class)); - cards.add(new SetCardInfo("Withered Wretch", 54, Rarity.RARE, mage.cards.w.WitheredWretch.class)); - cards.add(new SetCardInfo("Zhalfirin Commander", 18, Rarity.COMMON, mage.cards.z.ZhalfirinCommander.class)); + cards.add(new SetCardInfo("Withered Wretch", 54, Rarity.SPECIAL, mage.cards.w.WitheredWretch.class)); + cards.add(new SetCardInfo("Zhalfirin Commander", 18, Rarity.SPECIAL, mage.cards.z.ZhalfirinCommander.class)); } } diff --git a/Mage.Sets/src/mage/sets/VintageMasters.java b/Mage.Sets/src/mage/sets/VintageMasters.java index 3347805d4f..6ddaf2d0ab 100644 --- a/Mage.Sets/src/mage/sets/VintageMasters.java +++ b/Mage.Sets/src/mage/sets/VintageMasters.java @@ -1,11 +1,11 @@ package mage.sets; +import mage.cards.Card; import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; import mage.constants.Rarity; import mage.constants.SetType; +import mage.util.RandomUtil; import java.util.List; @@ -30,6 +30,7 @@ public final class VintageMasters extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + cards.add(new SetCardInfo("Academy Elite", 55, Rarity.RARE, mage.cards.a.AcademyElite.class)); cards.add(new SetCardInfo("Addle", 103, Rarity.COMMON, mage.cards.a.Addle.class)); cards.add(new SetCardInfo("Aether Mutation", 241, Rarity.UNCOMMON, mage.cards.a.AetherMutation.class)); cards.add(new SetCardInfo("Afterlife", 10, Rarity.COMMON, mage.cards.a.Afterlife.class)); @@ -92,6 +93,7 @@ public final class VintageMasters extends ExpansionSet { cards.add(new SetCardInfo("Control Magic", 63, Rarity.RARE, mage.cards.c.ControlMagic.class)); cards.add(new SetCardInfo("Council's Judgment", 20, Rarity.RARE, mage.cards.c.CouncilsJudgment.class)); cards.add(new SetCardInfo("Counterspell", 64, Rarity.COMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Crater Hellion", 157, Rarity.RARE, mage.cards.c.CraterHellion.class)); cards.add(new SetCardInfo("Crescendo of War", 21, Rarity.RARE, mage.cards.c.CrescendoOfWar.class)); cards.add(new SetCardInfo("Crovax the Cursed", 110, Rarity.RARE, mage.cards.c.CrovaxTheCursed.class)); cards.add(new SetCardInfo("Cruel Bargain", 111, Rarity.RARE, mage.cards.c.CruelBargain.class)); @@ -154,6 +156,7 @@ public final class VintageMasters extends ExpansionSet { cards.add(new SetCardInfo("Goblin Goon", 166, Rarity.UNCOMMON, mage.cards.g.GoblinGoon.class)); cards.add(new SetCardInfo("Goblin Lackey", 167, Rarity.RARE, mage.cards.g.GoblinLackey.class)); cards.add(new SetCardInfo("Goblin Matron", 168, Rarity.COMMON, mage.cards.g.GoblinMatron.class)); + cards.add(new SetCardInfo("Goblin Patrol", 169, Rarity.COMMON, mage.cards.g.GoblinPatrol.class)); cards.add(new SetCardInfo("Goblin Piledriver", 170, Rarity.RARE, mage.cards.g.GoblinPiledriver.class)); cards.add(new SetCardInfo("Goblin Ringleader", 171, Rarity.UNCOMMON, mage.cards.g.GoblinRingleader.class)); cards.add(new SetCardInfo("Goblin Settler", 172, Rarity.UNCOMMON, mage.cards.g.GoblinSettler.class)); @@ -190,6 +193,7 @@ public final class VintageMasters extends ExpansionSet { cards.add(new SetCardInfo("Lake of the Dead", 302, Rarity.RARE, mage.cards.l.LakeOfTheDead.class)); cards.add(new SetCardInfo("Laquatus's Champion", 125, Rarity.RARE, mage.cards.l.LaquatussChampion.class)); cards.add(new SetCardInfo("Library of Alexandria", 303, Rarity.MYTHIC, mage.cards.l.LibraryOfAlexandria.class)); + cards.add(new SetCardInfo("Lightning Dragon", 177, Rarity.RARE, mage.cards.l.LightningDragon.class)); cards.add(new SetCardInfo("Lightning Rift", 178, Rarity.UNCOMMON, mage.cards.l.LightningRift.class)); cards.add(new SetCardInfo("Lion's Eye Diamond", 271, Rarity.MYTHIC, mage.cards.l.LionsEyeDiamond.class)); cards.add(new SetCardInfo("Living Death", 126, Rarity.RARE, mage.cards.l.LivingDeath.class)); @@ -230,6 +234,7 @@ public final class VintageMasters extends ExpansionSet { cards.add(new SetCardInfo("Obsessive Search", 83, Rarity.COMMON, mage.cards.o.ObsessiveSearch.class)); cards.add(new SetCardInfo("Ophidian", 84, Rarity.COMMON, mage.cards.o.Ophidian.class)); cards.add(new SetCardInfo("Orcish Lumberjack", 179, Rarity.COMMON, mage.cards.o.OrcishLumberjack.class)); + cards.add(new SetCardInfo("Owl Familiar", 85, Rarity.COMMON, mage.cards.o.OwlFamiliar.class)); cards.add(new SetCardInfo("Palinchron", 86, Rarity.RARE, mage.cards.p.Palinchron.class)); cards.add(new SetCardInfo("Parallax Wave", 37, Rarity.RARE, mage.cards.p.ParallaxWave.class)); cards.add(new SetCardInfo("Paralyze", 132, Rarity.COMMON, mage.cards.p.Paralyze.class)); @@ -353,38 +358,25 @@ public final class VintageMasters extends ExpansionSet { } @Override - public List getSpecialCommon() { - CardCriteria criteria = new CardCriteria(); - criteria.rarities(Rarity.COMMON).setCodes(this.code); - return CardRepository.instance.findCards(criteria); + protected void addSpecialCards(List booster, int number) { + // number is here always 1 + Rarity rarity; + // You will open a Power Nine card about once in 53 packs + if (RandomUtil.nextInt(53) == 0) { + rarity = Rarity.BONUS; + } else { + // assuming same distribution as foils in paper Masters sets, 10:3:1 C:U:R + int rarityKey = RandomUtil.nextInt(112); + if (rarityKey < 80) { + rarity = Rarity.COMMON; + } else if (rarityKey < 104) { + rarity = Rarity.UNCOMMON; + } else if (rarityKey < 111) { + rarity = Rarity.RARE; + } else { + rarity = Rarity.MYTHIC; + } + } + addToBooster(booster, getCardsByRarity(rarity)); } - - @Override - public List getSpecialUncommon() { - CardCriteria criteria = new CardCriteria(); - criteria.rarities(Rarity.UNCOMMON).setCodes(this.code); - return CardRepository.instance.findCards(criteria); - } - - @Override - public List getSpecialRare() { - CardCriteria criteria = new CardCriteria(); - criteria.rarities(Rarity.RARE).setCodes(this.code); - return CardRepository.instance.findCards(criteria); - } - - @Override - public List getSpecialMythic() { - CardCriteria criteria = new CardCriteria(); - criteria.rarities(Rarity.MYTHIC).setCodes(this.code); - return CardRepository.instance.findCards(criteria); - } - - @Override - public List getSpecialBonus() { - CardCriteria criteria = new CardCriteria(); - criteria.rarities(Rarity.BONUS).setCodes(this.code); - return CardRepository.instance.findCards(criteria); - } - } diff --git a/Mage.Sets/src/mage/sets/WarOfTheSpark.java b/Mage.Sets/src/mage/sets/WarOfTheSpark.java index e86c4dbfe2..67c0da9674 100644 --- a/Mage.Sets/src/mage/sets/WarOfTheSpark.java +++ b/Mage.Sets/src/mage/sets/WarOfTheSpark.java @@ -1,5 +1,7 @@ package mage.sets; +import mage.MageObject; +import mage.cards.Card; import mage.cards.ExpansionSet; import mage.collation.BoosterCollator; import mage.collation.BoosterStructure; @@ -28,7 +30,6 @@ public final class WarOfTheSpark extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; - this.needsPlaneswalker = true; this.maxCardNumberInBooster = 264; cards.add(new SetCardInfo("Ahn-Crop Invader", 113, Rarity.COMMON, mage.cards.a.AhnCropInvader.class)); @@ -344,6 +345,12 @@ public final class WarOfTheSpark extends ExpansionSet { cards.add(new SetCardInfo("Widespread Brutality", 226, Rarity.RARE, mage.cards.w.WidespreadBrutality.class)); } + @Override + protected boolean boosterIsValid(List booster) { + return super.boosterIsValid(booster) + && booster.stream().filter(MageObject::isPlaneswalker).count() == 1; + } + @Override public BoosterCollator createCollator() { return new WarOfTheSparkCollator(); diff --git a/Mage.Sets/src/mage/sets/Zendikar.java b/Mage.Sets/src/mage/sets/Zendikar.java index 9521768efb..368d679621 100644 --- a/Mage.Sets/src/mage/sets/Zendikar.java +++ b/Mage.Sets/src/mage/sets/Zendikar.java @@ -3,6 +3,7 @@ package mage.sets; import mage.ObjectColor; import mage.cards.CardGraphicInfo; import mage.cards.ExpansionSet; +import mage.cards.repository.CardInfo; import mage.collation.BoosterCollator; import mage.collation.BoosterStructure; import mage.collation.CardRun; @@ -305,6 +306,16 @@ public final class Zendikar extends ExpansionSet { cards.add(new SetCardInfo("Zendikar Farguide", 194, Rarity.COMMON, mage.cards.z.ZendikarFarguide.class)); } + @Override + protected List findCardsByRarity(Rarity rarity) { + List cardInfos = super.findCardsByRarity(rarity); + if (rarity == Rarity.LAND) { + // only the full-art basic lands are found in boosters + cardInfos.removeIf(cardInfo -> cardInfo.getCardNumber().contains("a")); + } + return cardInfos; + } + @Override public BoosterCollator createCollator() { return new ZendikarCollator(); diff --git a/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java b/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java index 42802f2e02..21d6366576 100644 --- a/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java @@ -177,29 +177,6 @@ public class BoosterGenerationTest extends MageTestBase { assertFalse(str(booster), contains(booster, basics, null)); } - @Test - public void testMastersEditionIV_UrzaSpecialLandsList() { - - List needUrzaList = new ArrayList<>(Arrays.asList( - "Urza's Mine", - "Urza's Power Plant", - "Urza's Tower" - )); - - List setOrzaList = MastersEditionIV.getInstance().getSpecialLand(); - Assert.assertEquals("Urza special lands must have 4 variation for each of 3 card", 3 * 4, setOrzaList.size()); - - List foundUrzaList = new ArrayList<>(); - for (CardInfo cardInfo : setOrzaList) { - Assert.assertTrue("card " + cardInfo.getName() + " must be in urza's list", needUrzaList.contains(cardInfo.getName())); - foundUrzaList.add(cardInfo.getName()); - } - - for (String needName : needUrzaList) { - Assert.assertTrue("can't find need card " + needName + " in special land list", foundUrzaList.contains(needName)); - } - } - @Test public void testMastersEditionIV_UrzaSpecialLandInBoosters() { // ME4 replace all basic lands with special (1 per booster) diff --git a/Mage/src/main/java/mage/cards/ExpansionSet.java b/Mage/src/main/java/mage/cards/ExpansionSet.java index 4afae0f608..f6205e90fe 100644 --- a/Mage/src/main/java/mage/cards/ExpansionSet.java +++ b/Mage/src/main/java/mage/cards/ExpansionSet.java @@ -1,13 +1,11 @@ package mage.cards; -import mage.MageObject; import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.keyword.PartnerWithAbility; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.collation.BoosterCollator; +import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.SetType; import mage.util.CardUtil; @@ -118,23 +116,22 @@ public abstract class ExpansionSet implements Serializable { protected int numBoosterLands; protected int ratioBoosterSpecialLand = 0; // if > 0 basic lands are replaced with special land with probability ratioBoosterSpecialLandNumerator / ratioBoosterSpecialLand protected int ratioBoosterSpecialLandNumerator = 1; + protected int ratioBoosterSpecialCommon = 0; // if > 0 one common is replaced with special card with probability 1 / ratioBoosterSpecialCommon protected int numBoosterCommon; protected int numBoosterUncommon; protected int numBoosterRare; protected int numBoosterDoubleFaced; // -1 = include normally 0 = exclude 1-n = include explicit protected double ratioBoosterMythic; - protected boolean hasPartnerMechanic = false; - protected boolean needsLegendCreature = false; - protected boolean needsPlaneswalker = false; protected boolean validateBoosterColors = true; protected double rejectMissingColorProbability = 0.8; protected double rejectSameColorUncommonsProbability = 0.8; protected int maxCardNumberInBooster; // used to omit cards with collector numbers beyond the regular cards in a set for boosters - protected final EnumMap> savedCards; + protected final EnumMap> savedCards = new EnumMap<>(Rarity.class); + protected final EnumMap> savedSpecialCards = new EnumMap<>(Rarity.class); protected final Map inBoosterMap = new HashMap<>(); public ExpansionSet(String name, String code, Date releaseDate, SetType setType) { @@ -143,7 +140,6 @@ public abstract class ExpansionSet implements Serializable { this.releaseDate = releaseDate; this.setType = setType; this.maxCardNumberInBooster = Integer.MAX_VALUE; - savedCards = new EnumMap<>(Rarity.class); } public String getName() { @@ -214,35 +210,6 @@ public abstract class ExpansionSet implements Serializable { return theBooster; } - protected int addMissingPartner(List booster, boolean partnerAllowed, int max, int i) { - - Card sourceCard = booster.get(booster.size() - 1); - for (Ability ability : sourceCard.getAbilities()) { - - //Check if fetched card has the PartnerWithAbility - if (ability instanceof PartnerWithAbility) { - String partnerName = ((PartnerWithAbility) ability).getPartnerName(); - //Check if the pack already contains a partner pair - if (partnerAllowed) { - //Added card always replaces an uncommon card - Card card = CardRepository.instance.findCardWPreferredSet(partnerName, sourceCard.getExpansionSetCode(), false).getCard(); - if (i < max) { - booster.add(card); - } else { - booster.set(0, card); - } - //2 return value indicates found partner - return 2; - } else { - //If partner already exists, remove card and loop again - booster.remove(booster.size() - 1); - return 0; - } - } - } - return 1; - } - protected void addToBooster(List booster, List cards) { if (!cards.isEmpty()) { CardInfo cardInfo = cards.remove(RandomUtil.nextInt(cards.size())); @@ -266,16 +233,7 @@ public abstract class ExpansionSet implements Serializable { } for (int i = 0; i < 100; i++) {//don't want to somehow loop forever - - List booster; - if (hasPartnerMechanic) { - // battlebond's partners cards - booster = createPartnerBooster(); - } else { - // all other sets - booster = tryBooster(); - } - + List booster = tryBooster(); if (boosterIsValid(booster)) { return booster; } @@ -324,13 +282,6 @@ public abstract class ExpansionSet implements Serializable { } } - if (needsLegendCreature) { - return booster.stream().anyMatch(card -> card.isLegendary() && card.isCreature()); - } - if (needsPlaneswalker) { - return booster.stream().filter(MageObject::isPlaneswalker).count() == 1; - } - // TODO: add partner check // TODO: add booster size check? return true; @@ -388,88 +339,10 @@ public abstract class ExpansionSet implements Serializable { return true; } - private boolean checkMythic() { + protected boolean checkMythic() { return ratioBoosterMythic > 0 && ratioBoosterMythic * RandomUtil.nextDouble() <= 1; } - public List createPartnerBooster() { - - List booster = new ArrayList<>(); - - boolean partnerAllowed = true; - - List uncommons = getCardsByRarity(Rarity.UNCOMMON); - for (int i = 0; i < numBoosterUncommon; i++) { - while (true) { - addToBooster(booster, uncommons); - int check = addMissingPartner(booster, partnerAllowed, numBoosterUncommon - 1, i); - if (check == 1) { - break; - } - if (check == 2) { - partnerAllowed = false; - //Be sure to account for the added card - if (i != numBoosterUncommon - 1) { - i += 1; - } - break; - } - } - } - - int numSpecialCommons = getNumberOfSpecialCommons(); - int numCommonsToGenerate = numBoosterCommon - numSpecialCommons; - - List commons = getCardsByRarity(Rarity.COMMON); - for (int i = 0; i < numCommonsToGenerate; i++) { - addToBooster(booster, commons); - } - - List rares = getCardsByRarity(Rarity.RARE); - List mythics = getCardsByRarity(Rarity.MYTHIC); - for (int i = 0; i < numBoosterRare; i++) { - if (checkMythic()) { - while (true) { - addToBooster(booster, mythics); - int check = addMissingPartner(booster, partnerAllowed, -1, 1); - if (check == 1) { - break; - } - if (check == 2) { - partnerAllowed = false; - break; - } - } - } else { - while (true) { - addToBooster(booster, rares); - int check = addMissingPartner(booster, partnerAllowed, -1, 1); - if (check == 1) { - break; - } - if (check == 2) { - partnerAllowed = false; - break; - } - } - } - } - - if (numBoosterLands > 0) { - List specialLands = getSpecialLand(); - List basicLands = getCardsByRarity(Rarity.LAND); - for (int i = 0; i < numBoosterLands; i++) { - if (ratioBoosterSpecialLand > 0 && RandomUtil.nextInt(ratioBoosterSpecialLand) < ratioBoosterSpecialLandNumerator && specialLands != null) { - addToBooster(booster, specialLands); - } else { - addToBooster(booster, basicLands); - } - } - } - - return booster; - } - public List tryBooster() { List booster = new ArrayList<>(); if (!hasBoosters) { @@ -477,28 +350,29 @@ public abstract class ExpansionSet implements Serializable { } if (numBoosterLands > 0) { - List specialLands = getSpecialLand(); + List specialLands = getSpecialCardsByRarity(Rarity.LAND); List basicLands = getCardsByRarity(Rarity.LAND); for (int i = 0; i < numBoosterLands; i++) { - if (ratioBoosterSpecialLand > 0 && RandomUtil.nextInt(ratioBoosterSpecialLand) < ratioBoosterSpecialLandNumerator && specialLands != null) { + if (ratioBoosterSpecialLand > 0 && RandomUtil.nextInt(ratioBoosterSpecialLand) < ratioBoosterSpecialLandNumerator) { addToBooster(booster, specialLands); } else { addToBooster(booster, basicLands); } } } - int numSpecialCommons = getNumberOfSpecialCommons(); - int numCommonsToGenerate = numBoosterCommon - numSpecialCommons; + + int numCommonsToGenerate = numBoosterCommon; + int numSpecialToGenerate = numBoosterSpecial; + if (ratioBoosterSpecialCommon > 0 && RandomUtil.nextInt(ratioBoosterSpecialCommon) < 1) { + --numCommonsToGenerate; + ++numSpecialToGenerate; + } List commons = getCardsByRarity(Rarity.COMMON); for (int i = 0; i < numCommonsToGenerate; i++) { addToBooster(booster, commons); } - if (numSpecialCommons > 0) { // e.g. used to conditionally replace common cards in the booster - addSpecialCommon(booster, numSpecialCommons); - } - List uncommons = getCardsByRarity(Rarity.UNCOMMON); for (int i = 0; i < numBoosterUncommon; i++) { addToBooster(booster, uncommons); @@ -518,8 +392,8 @@ public abstract class ExpansionSet implements Serializable { addDoubleFace(booster); } - if (numBoosterSpecial > 0) { - addSpecial(booster); + if (numSpecialToGenerate > 0) { + addSpecialCards(booster, numSpecialToGenerate); } return booster; @@ -528,21 +402,27 @@ public abstract class ExpansionSet implements Serializable { /* add double faced card for Innistrad booster * rarity near as the normal distribution */ - public void addDoubleFace(List booster) { + protected void addDoubleFace(List booster) { + Rarity rarity; for (int i = 0; i < numBoosterDoubleFaced; i++) { - CardCriteria criteria = new CardCriteria(); - criteria.setCodes(this.code).doubleFaced(true); - if (RandomUtil.nextInt(15) < 10) { - criteria.rarities(Rarity.COMMON); - } else if (RandomUtil.nextInt(5) < 4) { - criteria.rarities(Rarity.UNCOMMON); - } else if (RandomUtil.nextInt(8) < 7) { - criteria.rarities(Rarity.RARE); + int rarityKey = RandomUtil.nextInt(121); + if (rarityKey < 66) { + rarity = Rarity.COMMON; + } else if (rarityKey < 108) { + rarity = Rarity.UNCOMMON; + } else if (rarityKey < 120) { + rarity = Rarity.RARE; } else { - criteria.rarities(Rarity.MYTHIC); + rarity = Rarity.MYTHIC; } - List doubleFacedCards = CardRepository.instance.findCards(criteria); - addToBooster(booster, doubleFacedCards); + addToBooster(booster, getSpecialCardsByRarity(rarity)); + } + } + + protected void addSpecialCards(List booster, int number) { + List specialCards = getCardsByRarity(Rarity.SPECIAL); + for (int i = 0; i < number; i++) { + addToBooster(booster, specialCards); } } @@ -551,75 +431,6 @@ public abstract class ExpansionSet implements Serializable { return new GregorianCalendar(year, month - 1, day).getTime(); } - /** - * Can be overwritten if sometimes special cards will be generated instead - * of common slots - * - * @return - */ - public int getNumberOfSpecialCommons() { - return 0; - } - - /** - * Can be overwritten to add a replacement for common card in boosters - * - * @param booster - * @param number - */ - public void addSpecialCommon(List booster, int number) { - - } - - private void addSpecial(List booster) { - int specialCards = 0; - List specialBonus = getSpecialBonus(); - specialCards += specialBonus.size(); - - List specialMythic = getSpecialMythic(); - specialCards += specialMythic.size(); - - List specialRare = getSpecialRare(); - specialCards += specialRare.size(); - - List specialUncommon = getSpecialUncommon(); - specialCards += specialUncommon.size(); - - List specialCommon = getSpecialCommon(); - specialCards += specialCommon.size(); - - if (specialCards > 0) { - for (int i = 0; i < numBoosterSpecial; i++) { - if (!specialCommon.isEmpty() - && RandomUtil.nextInt(15) < 10) { - addToBooster(booster, specialCommon); - continue; - } - if (!specialUncommon.isEmpty() - && RandomUtil.nextInt(4) < 3) { - addToBooster(booster, specialUncommon); - continue; - } - if (!specialRare.isEmpty() - && RandomUtil.nextInt(8) < 7) { - addToBooster(booster, specialRare); - continue; - } - if (!specialMythic.isEmpty()) { - if (specialBonus.isEmpty() || RandomUtil.nextInt(3) < 2) { - addToBooster(booster, specialMythic); - continue; - } - } - if (!specialBonus.isEmpty()) { - addToBooster(booster, specialBonus); - continue; - } - i--; - } - } - } - public boolean hasBoosters() { return hasBoosters; } @@ -628,58 +439,89 @@ public abstract class ExpansionSet implements Serializable { return hasBasicLands; } - public List getCardsByRarity(Rarity rarity) { - List savedCardsInfos = savedCards.get(rarity); - if (savedCardsInfos == null) { - CardCriteria criteria = new CardCriteria(); - if (rarity == Rarity.LAND && !hasBasicLands && parentSet != null) { - // get basic lands from parent set if this set doesn't have them - criteria.setCodes(parentSet.code); - } else { - criteria.setCodes(this.code); - } - criteria.rarities(rarity); - if (numBoosterDoubleFaced > -1) { - criteria.doubleFaced(false); - } - savedCardsInfos = CardRepository.instance.findCards(criteria); - // Workaround after card number is numeric - if (maxCardNumberInBooster != Integer.MAX_VALUE) { - savedCardsInfos.removeIf(next -> next.getCardNumberAsInt() > maxCardNumberInBooster && rarity != Rarity.LAND); - } - - savedCards.put(rarity, savedCardsInfos); + public final synchronized List getCardsByRarity(Rarity rarity) { + List savedCardInfos = savedCards.get(rarity); + if (savedCardInfos == null) { + savedCardInfos = findCardsByRarity(rarity); + savedCards.put(rarity, savedCardInfos); } // Return a copy of the saved cards information, as not to let modify the original. - return new ArrayList<>(savedCardsInfos); + return new ArrayList<>(savedCardInfos); } - public List getSpecialCommon() { - return new ArrayList<>(); + public final synchronized List getSpecialCardsByRarity(Rarity rarity) { + List savedCardInfos = savedSpecialCards.get(rarity); + if (savedCardInfos == null) { + savedCardInfos = findSpecialCardsByRarity(rarity); + savedSpecialCards.put(rarity, savedCardInfos); + } + // Return a copy of the saved cards information, as not to let modify the original. + return new ArrayList<>(savedCardInfos); } - public List getSpecialUncommon() { - return new ArrayList<>(); + protected List findCardsByRarity(Rarity rarity) { + // get basic lands from parent set if this set doesn't have them + if (rarity == Rarity.LAND && !hasBasicLands && parentSet != null) { + return parentSet.getCardsByRarity(rarity); + } + + List cardInfos = CardRepository.instance.findCards(new CardCriteria() + .setCodes(this.code) + .rarities(rarity)); + + cardInfos.removeIf(next -> ( + next.getCardNumberAsInt() > maxCardNumberInBooster + || next.getCardNumber().contains("*") + || next.getCardNumber().contains("+"))); + + // special slot cards must not also appear in regular slots of their rarity + // special land slot cards must not appear in regular common slots either + List specialCards = getSpecialCardsByRarity(rarity); + if (rarity == Rarity.COMMON && ratioBoosterSpecialLand > 0) { + specialCards.addAll(getSpecialCardsByRarity(Rarity.LAND)); + } + cardInfos.removeAll(specialCards); + return cardInfos; } - public List getSpecialRare() { - return new ArrayList<>(); - } + /** + * "Special cards" are cards that have common/uncommon/rare/mythic rarities + * but can only appear in a specific slot in boosters. Examples are DFCs in + * Innistrad sets and common nonbasic lands in many post-2018 sets. + * + * Note that Rarity.SPECIAL and Rarity.BONUS cards are not normally treated + * as "special cards" because by default boosters don't even have slots for + * those rarities. + * + * Also note that getCardsByRarity calls getSpecialCardsByRarity to exclude + * special cards from non-special booster slots, so sets that override this + * method must not call getCardsByRarity in it or infinite recursion will occur. + */ + protected List findSpecialCardsByRarity(Rarity rarity) { + List cardInfos = new ArrayList<>(); - public List getSpecialMythic() { - return new ArrayList<>(); - } + // if set has special land slot, assume all common lands are special cards + if (rarity == Rarity.LAND && ratioBoosterSpecialLand > 0) { + cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria() + .setCodes(this.code) + .rarities(Rarity.COMMON) + .types(CardType.LAND))); + } - public List getSpecialBonus() { - return new ArrayList<>(); - } + // if set has special slot(s) for DFCs, they are special cards + if (numBoosterDoubleFaced > 0) { + cardInfos.addAll(CardRepository.instance.findCards(new CardCriteria() + .setCodes(this.code) + .rarities(rarity) + .doubleFaced(true))); + } - public List getSpecialLand() { - return new ArrayList<>(); - } + cardInfos.removeIf(next -> ( + next.getCardNumberAsInt() > maxCardNumberInBooster + || next.getCardNumber().contains("*") + || next.getCardNumber().contains("+"))); - public void removeSavedCards() { - savedCards.clear(); + return cardInfos; } public int getMaxCardNumberInBooster() { diff --git a/Mage/src/main/java/mage/cards/repository/CardInfo.java b/Mage/src/main/java/mage/cards/repository/CardInfo.java index 4576179609..776738cb2d 100644 --- a/Mage/src/main/java/mage/cards/repository/CardInfo.java +++ b/Mage/src/main/java/mage/cards/repository/CardInfo.java @@ -479,6 +479,16 @@ public class CardInfo { return modalDoubleFacesSecondSideName; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof CardInfo)) return false; + CardInfo other = (CardInfo) o; + return (this.name.equals(other.name) + && this.setCode.equals(other.setCode) + && this.cardNumber.equals(other.cardNumber)); + } + @Override public String toString() { return String.format("%s (%s, %s)", getName(), getSetCode(), getCardNumber()); diff --git a/Mage/src/main/java/mage/game/draft/BoosterDraft.java b/Mage/src/main/java/mage/game/draft/BoosterDraft.java index 152834226b..a0063f8ae6 100644 --- a/Mage/src/main/java/mage/game/draft/BoosterDraft.java +++ b/Mage/src/main/java/mage/game/draft/BoosterDraft.java @@ -34,7 +34,6 @@ public class BoosterDraft extends DraftImpl { } boosterNum++; } - resetBufferedCards(); this.fireEndDraftEvent(); } diff --git a/Mage/src/main/java/mage/game/draft/Draft.java b/Mage/src/main/java/mage/game/draft/Draft.java index 8fef779f78..c935698047 100644 --- a/Mage/src/main/java/mage/game/draft/Draft.java +++ b/Mage/src/main/java/mage/game/draft/Draft.java @@ -44,8 +44,6 @@ public interface Draft extends MageItem, Serializable { void addPlayerQueryEventListener(Listener listener); void firePickCardEvent(UUID playerId); - void resetBufferedCards(); - boolean isAbort(); void setAbort(boolean abort); diff --git a/Mage/src/main/java/mage/game/draft/DraftImpl.java b/Mage/src/main/java/mage/game/draft/DraftImpl.java index 9a78e7e98d..2cab35ab60 100644 --- a/Mage/src/main/java/mage/game/draft/DraftImpl.java +++ b/Mage/src/main/java/mage/game/draft/DraftImpl.java @@ -305,16 +305,4 @@ public abstract class DraftImpl implements Draft { started = true; } - @Override - public void resetBufferedCards() { - Set setsDone = new HashSet<>(); - for (ExpansionSet set : sets) { - if (!setsDone.contains(set)) { - set.removeSavedCards(); - setsDone.add(set); - } - } - - } - } diff --git a/Mage/src/main/java/mage/game/draft/RichManBoosterDraft.java b/Mage/src/main/java/mage/game/draft/RichManBoosterDraft.java index 8f7e3ca70e..7ca3de815f 100644 --- a/Mage/src/main/java/mage/game/draft/RichManBoosterDraft.java +++ b/Mage/src/main/java/mage/game/draft/RichManBoosterDraft.java @@ -38,7 +38,6 @@ public class RichManBoosterDraft extends DraftImpl { } boosterNum++; } - resetBufferedCards(); this.fireEndDraftEvent(); } diff --git a/Mage/src/main/java/mage/game/draft/RichManCubeBoosterDraft.java b/Mage/src/main/java/mage/game/draft/RichManCubeBoosterDraft.java index e2d9c02361..b930a0e80c 100644 --- a/Mage/src/main/java/mage/game/draft/RichManCubeBoosterDraft.java +++ b/Mage/src/main/java/mage/game/draft/RichManCubeBoosterDraft.java @@ -36,7 +36,6 @@ public class RichManCubeBoosterDraft extends DraftImpl { } boosterNum++; } - resetBufferedCards(); this.fireEndDraftEvent(); } diff --git a/Mage/src/main/java/mage/game/tournament/TournamentImpl.java b/Mage/src/main/java/mage/game/tournament/TournamentImpl.java index 47f1214b6d..b7e53a8645 100644 --- a/Mage/src/main/java/mage/game/tournament/TournamentImpl.java +++ b/Mage/src/main/java/mage/game/tournament/TournamentImpl.java @@ -419,20 +419,9 @@ public abstract class TournamentImpl implements Tournament { } } } - resetBufferedCards(); nextStep(); } - public void resetBufferedCards() { - Set setsDone = new HashSet<>(); - for (ExpansionSet set : sets) { - if (!setsDone.contains(set)) { - set.removeSavedCards(); - setsDone.add(set); - } - } - } - public void playMatch(TournamentPairing pair) { options.getMatchOptions().getPlayerTypes().clear(); options.getMatchOptions().getPlayerTypes().add(pair.getPlayer1().getPlayerType());