Merge remote-tracking branch 'upstream/master' into deck-importer-decks-file-format

This commit is contained in:
leriomaggio
2021-10-28 23:20:48 +01:00
76 changed files with 874 additions and 277 deletions

View File

@@ -208,7 +208,7 @@ public class AiAttackController {
*/
public final boolean isEffectiveAttacker(final Player ai, final Card attacker, final Combat combat, final GameEntity defender) {
// if the attacker will die when attacking don't attack
if ((attacker.getNetToughness() + ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, null, combat, true)) <= 0) {
if (attacker.getNetToughness() + ComputerUtilCombat.predictToughnessBonusOfAttacker(attacker, null, combat, true) <= 0) {
return false;
}

View File

@@ -17,19 +17,11 @@
*/
package forge.ai;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.esotericsoftware.minlog.Log;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.ai.ability.ChangeZoneAi;
import forge.ai.ability.ExploreAi;
import forge.ai.ability.LearnAi;
@@ -40,39 +32,17 @@ import forge.card.mana.ManaCost;
import forge.deck.CardPool;
import forge.deck.Deck;
import forge.deck.DeckSection;
import forge.game.CardTraitBase;
import forge.game.CardTraitPredicates;
import forge.game.Direction;
import forge.game.Game;
import forge.game.GameActionUtil;
import forge.game.GameEntity;
import forge.game.GlobalRuleChange;
import forge.game.*;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.SpellApiBased;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPlayOption;
import forge.game.card.CardPredicates;
import forge.game.card.*;
import forge.game.card.CardPredicates.Accessors;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.Cost;
import forge.game.cost.CostAdjustment;
import forge.game.cost.CostDiscard;
import forge.game.cost.CostPart;
import forge.game.cost.CostPayEnergy;
import forge.game.cost.CostPayLife;
import forge.game.cost.CostPutCounter;
import forge.game.cost.CostRemoveCounter;
import forge.game.cost.CostSacrifice;
import forge.game.cost.*;
import forge.game.keyword.Keyword;
import forge.game.mana.ManaCostBeingPaid;
import forge.game.phase.PhaseType;
@@ -82,15 +52,7 @@ import forge.game.replacement.ReplaceMoved;
import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementLayer;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.LandAbility;
import forge.game.spellability.OptionalCost;
import forge.game.spellability.OptionalCostValue;
import forge.game.spellability.Spell;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityCondition;
import forge.game.spellability.SpellAbilityPredicates;
import forge.game.spellability.SpellPermanent;
import forge.game.spellability.*;
import forge.game.staticability.StaticAbility;
import forge.game.staticability.StaticAbilityMustTarget;
import forge.game.trigger.Trigger;
@@ -106,6 +68,9 @@ import forge.util.collect.FCollectionView;
import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
import java.util.*;
import java.util.Map.Entry;
/**
* <p>
* AiController class.
@@ -1968,6 +1933,38 @@ public class AiController {
// Whims of the Fates {all, 0, 0}
result.addAll(pool);
break;
case FlipOntoBattlefield:
if ("DamageCreatures".equals(sa.getParam("AILogic"))) {
int maxToughness = Integer.valueOf(sa.getSubAbility().getParam("NumDmg"));
CardCollectionView rightToughness = CardLists.filter(pool, new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return card.getController().isOpponentOf(sa.getActivatingPlayer())
&& card.getNetToughness() <= maxToughness
&& card.canBeDestroyed();
}
});
Card bestCreature = ComputerUtilCard.getBestCreatureAI(rightToughness.isEmpty() ? pool : rightToughness);
if (bestCreature != null) {
result.add(bestCreature);
} else {
result.add(Aggregates.random(pool)); // should ideally never get here
}
} else {
CardCollectionView viableOptions = CardLists.filter(pool, Predicates.and(CardPredicates.isControlledByAnyOf(sa.getActivatingPlayer().getOpponents())),
new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return card.canBeDestroyed();
}
});
Card best = ComputerUtilCard.getBestAI(viableOptions);
if (best == null) {
best = Aggregates.random(pool); // should ideally never get here either
}
result.add(best);
}
break;
default:
CardCollection editablePool = new CardCollection(pool);
for (int i = 0; i < max; i++) {

View File

@@ -40,7 +40,6 @@ import forge.game.card.CardFactory;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.combat.Combat;
@@ -905,7 +904,7 @@ public class ComputerUtilCard {
}
for (final Card crd : list) {
ColorSet color = CardUtil.getColors(crd);
ColorSet color = crd.determineColor();
if (color.hasWhite()) map.get(0).setValue(Integer.valueOf(map.get(0).getValue()+1));
if (color.hasBlue()) map.get(1).setValue(Integer.valueOf(map.get(1).getValue()+1));
if (color.hasBlack()) map.get(2).setValue(Integer.valueOf(map.get(2).getValue()+1));

View File

@@ -1478,7 +1478,7 @@ public class ComputerUtilCombat {
// DealDamage triggers
if (ApiType.DealDamage.equals(sa.getApi())) {
if ("TriggeredAttacker".equals(sa.getParam("Defined"))) {
if (!sa.hasParam("Defined") || !sa.getParam("Defined").startsWith("TriggeredAttacker")) {
continue;
}
int damage = AbilityUtils.calculateAmount(source, sa.getParam("NumDmg"), sa);

View File

@@ -87,6 +87,7 @@ public enum SpellApiToAi {
.put(ApiType.Explore, ExploreAi.class)
.put(ApiType.Fight, FightAi.class)
.put(ApiType.FlipACoin, FlipACoinAi.class)
.put(ApiType.FlipOntoBattlefield, FlipOntoBattlefieldAi.class)
.put(ApiType.Fog, FogAi.class)
.put(ApiType.GainControl, ControlGainAi.class)
.put(ApiType.GainControlVariant, ControlGainVariantAi.class)
@@ -140,6 +141,7 @@ public enum SpellApiToAi {
.put(ApiType.RemoveCounterAll, CannotPlayAi.class)
.put(ApiType.RemoveFromCombat, RemoveFromCombatAi.class)
.put(ApiType.RemoveFromGame, AlwaysPlayAi.class)
.put(ApiType.RemoveFromMatch, AlwaysPlayAi.class)
.put(ApiType.ReorderZone, AlwaysPlayAi.class)
.put(ApiType.Repeat, RepeatAi.class)
.put(ApiType.RepeatEach, RepeatEachAi.class)

View File

@@ -260,8 +260,9 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
// minimum card advantage unless the hand will be fully reloaded
int minAdv = logic.contains(".minAdv") ? Integer.parseInt(logic.substring(logic.indexOf(".minAdv") + 7)) : 0;
boolean noDiscard = logic.contains(".noDiscard");
if (numExiledWithSrc > curHandSize) {
if (numExiledWithSrc > curHandSize || (noDiscard && numExiledWithSrc > 0)) {
if (ComputerUtil.predictThreatenedObjects(ai, sa, true).contains(source)) {
// Try to gain some card advantage if the card will die anyway
// TODO: ideally, should evaluate the hand value and not discard good hands to it
@@ -269,7 +270,7 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
}
}
return (curHandSize + minAdv - 1 < numExiledWithSrc) || (numExiledWithSrc >= ai.getMaxHandSize());
return (curHandSize + minAdv - 1 < numExiledWithSrc) || (!noDiscard && numExiledWithSrc >= ai.getMaxHandSize());
}
} else if (origin.equals(ZoneType.Stack)) {
// time stop can do something like this:

View File

@@ -244,7 +244,7 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
//if Iona does prevent from casting, allow it to draw
for (final Card io : player.getCardsIn(ZoneType.Battlefield, "Iona, Shield of Emeria")) {
if (CardUtil.getColors(imprinted).hasAnyColor(MagicColor.fromName(io.getChosenColor()))) {
if (imprinted.determineColor().hasAnyColor(MagicColor.fromName(io.getChosenColor()))) {
return allow;
}
}

View File

@@ -303,6 +303,8 @@ public class DestroyAi extends SpellAbilityAi {
|| ai.getLife() <= 5)) {
// Basic ai logic for Lethal Vapors
return false;
} else if ("Always".equals(logic)) {
return true;
}
if (list.isEmpty()

View File

@@ -51,8 +51,8 @@ public class DigUntilAi extends SpellAbilityAi {
// until opponent's end of turn phase!
// But we still want more (and want to fill grave) if nothing better to do then
// This is important for Replenish/Living Death type decks
if (!((ai.getGame().getPhaseHandler().is(PhaseType.END_OF_TURN))
&& (!ai.getGame().getPhaseHandler().isPlayerTurn(ai)))) {
if (!ai.getGame().getPhaseHandler().is(PhaseType.END_OF_TURN)
&& !ai.getGame().getPhaseHandler().isPlayerTurn(ai)) {
return false;
}
}
@@ -75,7 +75,7 @@ public class DigUntilAi extends SpellAbilityAi {
}
final String num = sa.getParam("Amount");
if ((num != null) && num.equals("X") && sa.getSVar(num).equals("Count$xPaid")) {
if (num != null && num.equals("X") && sa.getSVar(num).equals("Count$xPaid")) {
// Set PayX here to maximum value.
SpellAbility root = sa.getRootAbility();
if (root.getXManaCostPaid() == null) {

View File

@@ -0,0 +1,48 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
public class FlipOntoBattlefieldAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {
PhaseHandler ph = sa.getHostCard().getGame().getPhaseHandler();
String logic = sa.getParamOrDefault("AILogic", "");
if (!SpellAbilityAi.isSorcerySpeed(sa) && sa.getPayCosts().hasManaCost()) {
return ph.is(PhaseType.END_OF_TURN);
}
if ("DamageCreatures".equals(logic)) {
int maxToughness = Integer.valueOf(sa.getSubAbility().getParam("NumDmg"));
CardCollectionView rightToughness = CardLists.filter(aiPlayer.getOpponents().getCreaturesInPlay(), new Predicate<Card>() {
@Override
public boolean apply(Card card) {
return card.getNetToughness() <= maxToughness && card.canBeDestroyed();
}
});
return !rightToughness.isEmpty();
}
return !aiPlayer.getOpponents().getCardsIn(ZoneType.Battlefield).isEmpty();
}
@Override
protected boolean doTriggerAINoCost(Player aiPlayer, SpellAbility sa, boolean mandatory) {
return canPlayAI(aiPlayer, sa) || mandatory;
}
@Override
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
return true;
}
}

View File

@@ -165,11 +165,10 @@ public class StaticData {
return this.editions;
}
public final CardEdition.Collection getCustomEditions(){
public final CardEdition.Collection getCustomEditions() {
return this.customEditions;
}
private List<CardEdition> sortedEditions;
public final List<CardEdition> getSortedEditions() {
if (sortedEditions == null) {
@@ -189,13 +188,13 @@ public class StaticData {
}
private TreeMap<CardEdition.Type, List<CardEdition>> editionsTypeMap;
public final Map<CardEdition.Type, List<CardEdition>> getEditionsTypeMap(){
if (editionsTypeMap == null){
public final Map<CardEdition.Type, List<CardEdition>> getEditionsTypeMap() {
if (editionsTypeMap == null) {
editionsTypeMap = new TreeMap<>();
for (CardEdition.Type editionType : CardEdition.Type.values()){
for (CardEdition.Type editionType : CardEdition.Type.values()) {
editionsTypeMap.put(editionType, new ArrayList<>());
}
for (CardEdition edition : this.getSortedEditions()){
for (CardEdition edition : this.getSortedEditions()) {
CardEdition.Type key = edition.getType();
List<CardEdition> editionsOfType = editionsTypeMap.get(key);
editionsOfType.add(edition);
@@ -204,9 +203,9 @@ public class StaticData {
return editionsTypeMap;
}
public CardEdition getCardEdition(String setCode){
public CardEdition getCardEdition(String setCode) {
CardEdition edition = this.editions.get(setCode);
if (edition == null) // try custom editions
if (edition == null) // try custom editions
edition = this.customEditions.get(setCode);
return edition;
}
@@ -231,8 +230,7 @@ public class StaticData {
public void attemptToLoadCard(String cardName){
this.attemptToLoadCard(cardName, null);
}
public void attemptToLoadCard(String cardName, String setCode){
public void attemptToLoadCard(String cardName, String setCode) {
CardRules rules = cardReader.attemptToLoadCard(cardName);
CardRules customRules = null;
if (customCardReader != null) {
@@ -257,7 +255,7 @@ public class StaticData {
* @param collectorNumber Card's collector Number
* @return PaperCard instance found in one of the available CardDb databases, or <code>null</code> if not found.
*/
public PaperCard fetchCard(final String cardName, final String setCode, final String collectorNumber){
public PaperCard fetchCard(final String cardName, final String setCode, final String collectorNumber) {
PaperCard card = null;
for (CardDb db : this.getAvailableDatabases().values()) {
card = db.getCard(cardName, setCode, collectorNumber);
@@ -345,7 +343,7 @@ public class StaticData {
return result;
}
private CardDb matchTargetCardDb(final String cardName){
private CardDb matchTargetCardDb(final String cardName) {
// NOTE: any foil request in cardName is NOT taken into account here.
// It's a private method, so it's a fair assumption.
for (CardDb targetDb : this.getAvailableDatabases().values()){
@@ -360,7 +358,7 @@ public class StaticData {
* @param cardName Name of the Card to verify (CASE SENSITIVE)
* @return True if a card with the given input string can be found. False otherwise.
*/
public boolean isMTGCard(final String cardName){
public boolean isMTGCard(final String cardName) {
if (cardName == null || cardName.trim().length() == 0)
return false;
CardDb.CardRequest cr = CardDb.CardRequest.fromString(cardName); // accounts for any foil request ending with +
@@ -450,10 +448,6 @@ public class StaticData {
public Predicate<PaperCard> getBrawlPredicate() { return brawlPredicate; }
public void setFilteredHandsEnabled(boolean filteredHandsEnabled){
this.filteredHandsEnabled = filteredHandsEnabled;
}
/**
* Get an alternative card print for the given card wrt. the input setReleaseDate.
* The reference release date will be used to retrieve the alternative art, according
@@ -501,7 +495,7 @@ public class StaticData {
*/
public PaperCard getAlternativeCardPrint(PaperCard card, Date setReleaseDate,
boolean isCardArtPreferenceLatestArt,
boolean cardArtPreferenceHasFilter){
boolean cardArtPreferenceHasFilter) {
Date searchReferenceDate = getReferenceDate(setReleaseDate, isCardArtPreferenceLatestArt);
CardDb.CardArtPreference searchCardArtStrategy = getSearchStrategyForAlternativeCardArt(isCardArtPreferenceLatestArt,
cardArtPreferenceHasFilter);
@@ -537,7 +531,6 @@ public class StaticData {
public PaperCard getAlternativeCardPrint(PaperCard card, Date setReleaseDate, boolean isCardArtPreferenceLatestArt,
boolean cardArtPreferenceHasFilter,
boolean preferCandidatesFromExpansionSets, boolean preferModernFrame) {
PaperCard altCard = this.getAlternativeCardPrint(card, setReleaseDate, isCardArtPreferenceLatestArt,
cardArtPreferenceHasFilter);
if (altCard == null)
@@ -618,7 +611,7 @@ public class StaticData {
private PaperCard tryToGetCardPrintFromExpansionSet(PaperCard altCard,
boolean isCardArtPreferenceLatestArt,
boolean preferModernFrame){
boolean preferModernFrame) {
CardEdition altCardEdition = editions.get(altCard.getEdition());
if (altCardEdition.getType() == CardEdition.Type.EXPANSION)
return null; // Nothing to do here!
@@ -628,7 +621,7 @@ public class StaticData {
CardDb.CardArtPreference searchStrategy = getSearchStrategyForAlternativeCardArt(searchStrategyFlag,
true);
PaperCard altCandidate = altCard;
while (altCandidate != null){
while (altCandidate != null) {
Date referenceDate = editions.get(altCandidate.getEdition()).getDate();
altCandidate = this.searchAlternativeCardCandidate(altCandidate, preferModernFrame,
referenceDate, searchStrategy);
@@ -645,7 +638,7 @@ public class StaticData {
private PaperCard tryToGetCardPrintWithMatchingFrame(PaperCard altCard,
boolean isCardArtPreferenceLatestArt,
boolean cardArtHasFilter,
boolean preferModernFrame){
boolean preferModernFrame) {
CardEdition altCardEdition = editions.get(altCard.getEdition());
boolean frameIsCompliantAlready = (altCardEdition.isModern() == preferModernFrame);
if (frameIsCompliantAlready)
@@ -654,7 +647,7 @@ public class StaticData {
CardDb.CardArtPreference searchStrategy = getSearchStrategyForAlternativeCardArt(searchStrategyFlag,
cardArtHasFilter);
PaperCard altCandidate = altCard;
while (altCandidate != null){
while (altCandidate != null) {
Date referenceDate = editions.get(altCandidate.getEdition()).getDate();
altCandidate = this.searchAlternativeCardCandidate(altCandidate, preferModernFrame,
referenceDate, searchStrategy);
@@ -677,7 +670,7 @@ public class StaticData {
* @param card Instance of target <code>PaperCard</code>
* @return The number of available arts for the given card in the corresponding set, or 0 if not found.
*/
public int getCardArtCount(PaperCard card){
public int getCardArtCount(PaperCard card) {
Collection<CardDb> databases = this.getAvailableDatabases().values();
for (CardDb db: databases){
int artCount = db.getArtCount(card.getName(), card.getEdition());
@@ -687,9 +680,12 @@ public class StaticData {
return 0;
}
public boolean getFilteredHandsEnabled(){
public boolean getFilteredHandsEnabled() {
return filteredHandsEnabled;
}
public void setFilteredHandsEnabled(boolean filteredHandsEnabled) {
this.filteredHandsEnabled = filteredHandsEnabled;
}
public void setMulliganRule(MulliganDefs.MulliganRule rule) {
mulliganRule = rule;
@@ -699,21 +695,21 @@ public class StaticData {
return mulliganRule;
}
public void setCardArtPreference(boolean latestArt, boolean coreExpansionOnly){
public void setCardArtPreference(boolean latestArt, boolean coreExpansionOnly) {
this.commonCards.setCardArtPreference(latestArt, coreExpansionOnly);
this.variantCards.setCardArtPreference(latestArt, coreExpansionOnly);
this.customCards.setCardArtPreference(latestArt, coreExpansionOnly);
}
public String getCardArtPreferenceName(){
public String getCardArtPreferenceName() {
return this.commonCards.getCardArtPreference().toString();
}
public CardDb.CardArtPreference getCardArtPreference(){
public CardDb.CardArtPreference getCardArtPreference() {
return this.commonCards.getCardArtPreference();
}
public CardDb.CardArtPreference getCardArtPreference(boolean latestArt, boolean coreExpansionOnly){
public CardDb.CardArtPreference getCardArtPreference(boolean latestArt, boolean coreExpansionOnly) {
if (latestArt){
return coreExpansionOnly ? CardDb.CardArtPreference.LATEST_ART_CORE_EXPANSIONS_REPRINT_ONLY : CardDb.CardArtPreference.LATEST_ART_ALL_EDITIONS;
}
@@ -721,15 +717,15 @@ public class StaticData {
}
public boolean isCoreExpansionOnlyFilterSet(){ return this.commonCards.getCardArtPreference().filterSets; }
public boolean isCoreExpansionOnlyFilterSet() { return this.commonCards.getCardArtPreference().filterSets; }
public boolean cardArtPreferenceIsLatest(){
public boolean cardArtPreferenceIsLatest() {
return this.commonCards.getCardArtPreference().latestFirst;
}
// === MOBILE APP Alternative Methods (using String Labels, not yet localised!!) ===
// Note: only used in mobile
public String[] getCardArtAvailablePreferences(){
public String[] getCardArtAvailablePreferences() {
CardDb.CardArtPreference[] preferences = CardDb.CardArtPreference.values();
String[] preferences_avails = new String[preferences.length];
for (int i = 0; i < preferences.length; i++)
@@ -745,17 +741,16 @@ public class StaticData {
return label.toString().trim();
}
public void setCardArtPreference(String artPreference){
public void setCardArtPreference(String artPreference) {
this.commonCards.setCardArtPreference(artPreference);
this.variantCards.setCardArtPreference(artPreference);
this.customCards.setCardArtPreference(artPreference);
}
//
public boolean isEnabledCardArtSmartSelection(){
public boolean isEnabledCardArtSmartSelection() {
return this.enableSmartCardArtSelection;
}
public void setEnableSmartCardArtSelection(boolean isEnabled){
public void setEnableSmartCardArtSelection(boolean isEnabled) {
this.enableSmartCardArtSelection = isEnabled;
}

View File

@@ -53,7 +53,7 @@ public class CardPool extends ItemPool<PaperCard> {
public void add(final String cardRequest, final int amount) {
CardDb.CardRequest request = CardDb.CardRequest.fromString(cardRequest);
this.add(request.cardName, request.edition, request.artIndex, amount);
this.add(CardDb.CardRequest.compose(request.cardName, request.isFoil), request.edition, request.artIndex, amount);
}
public void add(final String cardName, final String setCode) {
@@ -100,7 +100,7 @@ public class CardPool extends ItemPool<PaperCard> {
paperCard = StaticData.instance().getCommonCards().getCard(cardName);
selectedDbName = "Common";
}
if (paperCard == null){
if (paperCard == null) {
// after all still null
System.err.println("An unsupported card was requested: \"" + cardName + "\" from \"" + setCode + "\". \n");
paperCard = StaticData.instance().getCommonCards().createUnsupportedCard(cardName);
@@ -130,7 +130,6 @@ public class CardPool extends ItemPool<PaperCard> {
}
}
/**
* Add all from a List of CardPrinted.
*
@@ -222,10 +221,10 @@ public class CardPool extends ItemPool<PaperCard> {
*
* @see CardPool#getCardEditionStatistics(boolean)
*/
public Map<CardEdition.Type, Integer> getCardEditionTypeStatistics(boolean includeBasicLands){
public Map<CardEdition.Type, Integer> getCardEditionTypeStatistics(boolean includeBasicLands) {
Map<CardEdition.Type, Integer> editionTypeStats = new HashMap<>();
Map<CardEdition, Integer> editionStatistics = this.getCardEditionStatistics(includeBasicLands);
for(Entry<CardEdition, Integer> entry : editionStatistics.entrySet()) {
for (Entry<CardEdition, Integer> entry : editionStatistics.entrySet()) {
CardEdition edition = entry.getKey();
int count = entry.getValue();
CardEdition.Type key = edition.getType();
@@ -242,11 +241,11 @@ public class CardPool extends ItemPool<PaperCard> {
*
* @return The most frequent CardEdition.Type in the pool, or null if the Pool is empty
*/
public CardEdition.Type getTheMostFrequentEditionType(){
public CardEdition.Type getTheMostFrequentEditionType() {
Map<CardEdition.Type, Integer> editionTypeStats = this.getCardEditionTypeStatistics(false);
Integer mostFrequentType = 0;
List<CardEdition.Type> mostFrequentEditionTypes = new ArrayList<>();
for (Map.Entry<CardEdition.Type, Integer> entry : editionTypeStats.entrySet()){
for (Map.Entry<CardEdition.Type, Integer> entry : editionTypeStats.entrySet()) {
if (entry.getValue() > mostFrequentType) {
mostFrequentType = entry.getValue();
mostFrequentEditionTypes.add(entry.getKey());
@@ -271,11 +270,11 @@ public class CardPool extends ItemPool<PaperCard> {
* If the count of Modern and PreModern cards is tied, the return value is determined
* by the preferred Card Art Preference settings, namely True if Latest Art, False otherwise.
*/
public boolean isModern(){
public boolean isModern() {
int modernEditionsCount = 0;
int preModernEditionsCount = 0;
Map<CardEdition, Integer> editionStats = this.getCardEditionStatistics(false);
for (Map.Entry<CardEdition, Integer> entry: editionStats.entrySet()){
for (Map.Entry<CardEdition, Integer> entry: editionStats.entrySet()) {
CardEdition edition = entry.getKey();
if (edition.isModern())
modernEditionsCount += entry.getValue();
@@ -364,7 +363,7 @@ public class CardPool extends ItemPool<PaperCard> {
private static int getMedianFrequency(List<Integer> frequencyValues, float meanFrequency) {
int medianFrequency = frequencyValues.get(0);
float refDelta = Math.abs(meanFrequency - medianFrequency);
for (int i = 1; i < frequencyValues.size(); i++){
for (int i = 1; i < frequencyValues.size(); i++) {
int currentFrequency = frequencyValues.get(i);
float delta = Math.abs(meanFrequency - currentFrequency);
if (delta < refDelta) {
@@ -411,7 +410,7 @@ public class CardPool extends ItemPool<PaperCard> {
return pool;
}
public static List<Pair<String, Integer>> processCardList(final Iterable<String> lines){
public static List<Pair<String, Integer>> processCardList(final Iterable<String> lines) {
List<Pair<String, Integer>> cardRequests = new ArrayList<>();
if (lines == null)
return cardRequests; // empty list
@@ -466,7 +465,7 @@ public class CardPool extends ItemPool<PaperCard> {
public CardPool getFilteredPool(Predicate<PaperCard> predicate) {
CardPool filteredPool = new CardPool();
Iterator<PaperCard> cardsInPool = this.items.keySet().iterator();
while (cardsInPool.hasNext()){
while (cardsInPool.hasNext()) {
PaperCard c = cardsInPool.next();
if (predicate.apply(c))
filteredPool.add(c, this.items.get(c));
@@ -479,12 +478,12 @@ public class CardPool extends ItemPool<PaperCard> {
* @param predicate the Predicate to apply to this CardPool
* @return a new CardPool made from this CardPool with only the cards that agree with the provided Predicate
*/
public CardPool getFilteredPoolWithCardsCount(Predicate<PaperCard> predicate){
public CardPool getFilteredPoolWithCardsCount(Predicate<PaperCard> predicate) {
CardPool filteredPool = new CardPool();
for(Entry<PaperCard, Integer> entry : this.items.entrySet()){
for (Entry<PaperCard, Integer> entry : this.items.entrySet()) {
PaperCard pc = entry.getKey();
int count = entry.getValue();
if(predicate.apply(pc))
if (predicate.apply(pc))
filteredPool.add(pc, count);
}
return filteredPool;

View File

@@ -25,6 +25,7 @@ import forge.card.CardDb;
import forge.card.CardEdition;
import forge.item.IPaperCard;
import forge.item.PaperCard;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import java.util.*;
@@ -216,7 +217,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
}
private void loadDeferredSections() {
if ((deferredSections == null) && (loadedSections == null))
if (deferredSections == null && loadedSections == null)
return;
if (loadedSections != null && !includeCardsFromUnspecifiedSet)
@@ -236,8 +237,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
if (deferredSections != null) {
this.validateDeferredSections();
referenceDeckLoadingMap = new HashMap<>(this.deferredSections);
}
else
} else
referenceDeckLoadingMap = new HashMap<>(loadedSections);
loadedSections = new HashMap<>();
@@ -255,7 +255,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
continue;
final List<String> cardsInSection = s.getValue();
ArrayList<String> cardNamesWithNoEdition = getAllCardNamesWithNoSpecifiedEdition(cardsInSection);
if (cardNamesWithNoEdition.size() > 0){
if (cardNamesWithNoEdition.size() > 0) {
includeCardsFromUnspecifiedSet = true;
if (smartCardArtSelection)
cardsWithNoEdition.put(sec, cardNamesWithNoEdition);
@@ -267,10 +267,9 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
deferredSections = null; // set to null, just in case!
if (includeCardsFromUnspecifiedSet && smartCardArtSelection)
optimiseCardArtSelectionInDeckSections(cardsWithNoEdition);
}
private void validateDeferredSections(){
private void validateDeferredSections() {
/*
Construct a temporary (DeckSection, CardPool) Maps, to be sanitised and finalised
before copying into `this.parts`. This sanitisation is applied because of the
@@ -285,6 +284,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
}
final List<String> cardsInSection = s.getValue();
List<Pair<String, Integer>> originalCardRequests = CardPool.processCardList(cardsInSection);
CardPool pool = CardPool.fromCardList(cardsInSection);
if (pool.countDistinct() == 0)
continue; // pool empty, no card has been found!
@@ -301,13 +301,12 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
if (whiteList == null)
whiteList = new ArrayList<>();
for (Entry<PaperCard, Integer> entry : filteredPool) {
String poolRequest = getPoolRequest(entry);
String poolRequest = getPoolRequest(entry, originalCardRequests);
whiteList.add(poolRequest);
}
validatedSections.put(s.getKey(), whiteList);
if (filteredPool.countDistinct() != pool.countDistinct()){
if (filteredPool.countDistinct() != pool.countDistinct()) {
CardPool blackList = pool.getFilteredPoolWithCardsCount(new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard input) {
@@ -317,7 +316,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
for (Entry<PaperCard, Integer> entry : blackList) {
DeckSection cardSection = DeckSection.matchingSection(entry.getKey());
String poolRequest = getPoolRequest(entry);
String poolRequest = getPoolRequest(entry, originalCardRequests);
List<String> sectionCardList = validatedSections.getOrDefault(cardSection.name(), null);
if (sectionCardList == null)
sectionCardList = new ArrayList<>();
@@ -331,11 +330,26 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
this.deferredSections = validatedSections;
}
private String getPoolRequest(Entry<PaperCard, Integer> entry) {
private String getPoolRequest(Entry<PaperCard, Integer> entry, List<Pair<String, Integer>> originalCardRequests) {
PaperCard card = entry.getKey();
int amount = entry.getValue();
String cardRequest = CardDb.CardRequest.compose(card.getName(), card.getEdition(), card.getArtIndex());
return String.format("%d %s", amount, cardRequest);
String poolCardRequest = CardDb.CardRequest.compose(
card.isFoil() ? CardDb.CardRequest.compose(card.getName(), true) : card.getName(),
card.getEdition(), card.getArtIndex());
String originalRequestCandidate = null;
for (Pair<String, Integer> originalRequest : originalCardRequests){
String cardRequest = originalRequest.getLeft();
if (!StringUtils.startsWithIgnoreCase(poolCardRequest, cardRequest))
continue;
originalRequestCandidate = cardRequest;
int cardAmount = originalRequest.getRight();
if (amount == cardAmount)
return String.format("%d %s", cardAmount, cardRequest);
}
// This is just in case, it should never happen as we're
if (originalRequestCandidate != null)
return String.format("%d %s", amount, originalRequestCandidate);
return String.format("%d %s", amount, poolCardRequest);
}
private ArrayList<String> getAllCardNamesWithNoSpecifiedEdition(List<String> cardsInSection) {
@@ -356,9 +370,9 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
boolean isCardArtPreferenceLatestArt = data.cardArtPreferenceIsLatest();
boolean cardArtPreferenceHasFilter = data.isCoreExpansionOnlyFilterSet();
for(Entry<DeckSection, CardPool> part : parts.entrySet()) {
for (Entry<DeckSection, CardPool> part : parts.entrySet()) {
DeckSection deckSection = part.getKey();
if(deckSection == DeckSection.Planes || deckSection == DeckSection.Schemes || deckSection == DeckSection.Avatar)
if (deckSection != DeckSection.Main && deckSection != DeckSection.Sideboard && deckSection != DeckSection.Commander)
continue;
// == 0. First Off, check if there is anything at all to do for the current section
@@ -432,7 +446,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
cardsPerArtIndex = Math.max(1, cardsPerArtIndex); // make sure is never zero
int cardsAdded = 0;
PaperCard alternativeCardArt = null;
for (int artIndex = 1; artIndex <= nrOfAvailableArts; artIndex++){
for (int artIndex = 1; artIndex <= nrOfAvailableArts; artIndex++) {
alternativeCardArt = data.getOrLoadCommonCard(cardName, setCode, artIndex, isFoil);
cardsAdded += cardsPerArtIndex;
pool.add(alternativeCardArt, cardsPerArtIndex);
@@ -461,7 +475,7 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
if (card.getRules().isVariant())
return false; // skip variant cards
if (StaticData.instance().getCommonCards().hasPreferredArt(card.getName())){
if (StaticData.instance().getCommonCards().hasPreferredArt(card.getName())) {
// if there is any preferred art, never update it!
CardDb.CardRequest request = CardDb.CardRequest.fromString(card.getName());
if (request.edition.equals(card.getEdition()) && request.artIndex == card.getArtIndex())
@@ -478,8 +492,6 @@ public class Deck extends DeckBase implements Iterable<Entry<DeckSection, CardPo
return releaseDate.compareTo(referenceReleaseDate) < 0;
}
public static final Function<Deck, String> FN_NAME_SELECTOR = new Function<Deck, String>() {
@Override
public String apply(Deck arg1) {

View File

@@ -123,6 +123,14 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
}
return this.foiledVersion;
}
public PaperCard getUnFoiled() {
if (!this.foil)
return this;
PaperCard unFoiledVersion = new PaperCard(this.rules, this.edition, this.rarity,
this.artIndex, false, String.valueOf(collectorNumber), this.artist);
return unFoiledVersion;
}
// @Override
// public String getImageKey() {
@@ -260,7 +268,6 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
return sortableCNKey;
}
@Override
public int compareTo(final IPaperCard o) {
final int nameCmp = name.compareToIgnoreCase(o.getName());

View File

@@ -830,7 +830,7 @@ public class Game {
c.removeTempController(p);
// return stolen spells
if (c.isInZone(ZoneType.Stack)) {
SpellAbilityStackInstance si = getStack().getInstanceFromSpellAbility(c.getCastSA());
SpellAbilityStackInstance si = getStack().getInstanceMatchingSpellAbilityID(c.getCastSA());
si.setActivatingPlayer(c.getController());
}
if (c.getController().equals(p)) {
@@ -854,7 +854,7 @@ public class Game {
if (p != null && p.isMonarch()) {
// if the player who lost was the Monarch, someone else will be the monarch
if(p.equals(getPhaseHandler().getPlayerTurn())) {
if (p.equals(getPhaseHandler().getPlayerTurn())) {
getAction().becomeMonarch(getNextPlayerAfter(p), null);
} else {
getAction().becomeMonarch(getPhaseHandler().getPlayerTurn(), null);

View File

@@ -997,6 +997,9 @@ public class GameAction {
}
public void ceaseToExist(Card c, boolean skipTrig) {
if (c.isInZone(ZoneType.Stack)) {
c.getGame().getStack().remove(c);
}
c.getZone().remove(c);
// CR 603.6c other players LTB triggers should work

View File

@@ -1,24 +1,7 @@
package forge.game;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multiset;
import com.google.common.collect.*;
import com.google.common.eventbus.EventBus;
import forge.LobbyPlayer;
import forge.deck.CardPool;
import forge.deck.Deck;
@@ -40,7 +23,11 @@ import forge.util.Localizer;
import forge.util.MyRandom;
import forge.util.collect.FCollectionView;
import java.util.*;
import java.util.Map.Entry;
public class Match {
private static List<PaperCard> removedCards = Lists.newArrayList();
private final List<RegisteredPlayer> players;
private final GameRules rules;
private final String title;
@@ -198,6 +185,12 @@ public class Match {
return myRemovedAnteCards;
}
public static List<PaperCard> getRemovedCards() { return removedCards; }
public void removeCard(PaperCard c) {
removedCards.add(c);
}
private static void preparePlayerZone(Player player, final ZoneType zoneType, CardPool section, boolean canRandomFoil) {
PlayerZone library = player.getZone(zoneType);
List<Card> newLibrary = new ArrayList<>();
@@ -257,6 +250,23 @@ public class Match {
}
Deck toChange = psc.getDeck();
if (!getRemovedCards().isEmpty()) {
CardPool main = new CardPool();
main.addAll(toChange.get(DeckSection.Main));
CardPool sideboard = new CardPool();
sideboard.addAll(toChange.getOrCreate(DeckSection.Sideboard));
for (PaperCard c : removedCards) {
if (main.contains(c)) {
main.remove(c, 1);
} else if (sideboard.contains(c)) {
sideboard.remove(c, 1);
}
}
toChange.getMain().clear();
toChange.getMain().addAll(main);
toChange.get(DeckSection.Sideboard).clear();
toChange.get(DeckSection.Sideboard).addAll(sideboard);
}
List<PaperCard> newMain = person.sideboard(toChange, rules.getGameType(), player.getName());
if (null != newMain) {
CardPool allCards = new CardPool();

View File

@@ -1789,7 +1789,7 @@ public class AbilityUtils {
if (sq[0].contains("HasNumChosenColors")) {
int sum = 0;
for (Card card : getDefinedCards(c, sq[1], sa)) {
sum += CardUtil.getColors(card).getSharedColors(ColorSet.fromNames(c.getChosenColors())).countColors();
sum += card.determineColor().getSharedColors(ColorSet.fromNames(c.getChosenColors())).countColors();
}
return sum;
}
@@ -1990,7 +1990,7 @@ public class AbilityUtils {
// Count$CardMulticolor.<numMC>.<numNotMC>
if (sq[0].contains("CardMulticolor")) {
final boolean isMulti = CardUtil.getColors(c).isMulticolor();
final boolean isMulti = c.determineColor().isMulticolor();
return doXMath(Integer.parseInt(sq[isMulti ? 1 : 2]), expr, c, ctb);
}
// Count$Madness.<True>.<False>
@@ -2046,7 +2046,7 @@ public class AbilityUtils {
}
if (sq[0].contains("CardNumColors")) {
return doXMath(CardUtil.getColors(c).countColors(), expr, c, ctb);
return doXMath(c.determineColor().countColors(), expr, c, ctb);
}
if (sq[0].contains("CardNumAttacksThisTurn")) {
return doXMath(c.getDamageHistory().getCreatureAttacksThisTurn(), expr, c, ctb);
@@ -3766,7 +3766,7 @@ public class AbilityUtils {
someCards = CardLists.filter(someCards, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return CardUtil.getColors(c).isMulticolor();
return c.determineColor().isMulticolor();
}
});
}
@@ -3775,7 +3775,7 @@ public class AbilityUtils {
someCards = CardLists.filter(someCards, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return CardUtil.getColors(c).isMonoColor();
return c.determineColor().isMonoColor();
}
});
}

View File

@@ -85,6 +85,7 @@ public enum ApiType {
Explore (ExploreEffect.class),
Fight (FightEffect.class),
FlipACoin (FlipCoinEffect.class),
FlipOntoBattlefield (FlipOntoBattlefieldEffect.class),
Fog (FogEffect.class),
GainControl (ControlGainEffect.class),
GainControlVariant (ControlGainVariantEffect.class),
@@ -139,6 +140,7 @@ public enum ApiType {
RemoveCounterAll (CountersRemoveAllEffect.class),
RemoveFromCombat (RemoveFromCombatEffect.class),
RemoveFromGame (RemoveFromGameEffect.class),
RemoveFromMatch (RemoveFromMatchEffect.class),
ReorderZone (ReorderZoneEffect.class),
Repeat (RepeatEffect.class),
RepeatEach (RepeatEachEffect.class),

View File

@@ -8,6 +8,7 @@ import com.google.common.collect.Lists;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardUtil;
import forge.game.event.GameEventCardModeChosen;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -81,6 +82,19 @@ public class ChooseGenericEffect extends SpellAbilityEffect {
chosenSAs = p.getController().chooseSpellAbilitiesForEffect(abilities, sa, prompt, amount, ImmutableMap.of());
}
for (SpellAbility chosenSA : chosenSAs) {
if (sa.hasParam("AtRandom") && sa.getParam("AtRandom").equals("Urza") && chosenSA.usesTargeting()) {
List<Card> validTargets = CardUtil.getValidCardsToTarget(chosenSA.getTargetRestrictions(), sa);
if (validTargets.isEmpty()) {
List <SpellAbility> newChosenSAs = Lists.newArrayList();
Aggregates.random(abilities, amount, newChosenSAs);
chosenSAs = newChosenSAs;
} else {
p.getController().chooseTargetsFor(chosenSA);
}
}
}
if (!chosenSAs.isEmpty()) {
for (SpellAbility chosenSA : chosenSAs) {
String chosenValue = chosenSA.getDescription();

View File

@@ -42,8 +42,9 @@ public class DigEffect extends SpellAbilityEffect {
final int numToDig = AbilityUtils.calculateAmount(host, sa.getParam("DigNum"), sa);
final List<Player> tgtPlayers = getTargetPlayers(sa);
sb.append(host.getController()).append(" looks at the top ");
sb.append(Lang.nounWithAmount(numToDig, "card")).append(" of ");
sb.append(host.getController()).append(sa.hasParam("Reveal") && sa.getParam("Reveal").equals("True")
? " reveals " : " looks at ").append("the top ");
sb.append(numToDig == 1 ? "card" : (Lang.getNumeral(numToDig) + " cards")).append(" of ");
if (tgtPlayers.contains(host.getController())) {
sb.append("their ");

View File

@@ -179,12 +179,12 @@ public class DigUntilEffect extends SpellAbilityEffect {
Localizer.getInstance().getMessage("lblDoYouWantPutCardToZone", foundDest.getTranslatedName()))) {
continue;
}
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield);
moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard);
Card m = null;
if (sa.hasParam("GainControl") && foundDest.equals(ZoneType.Battlefield)) {
c.setController(sa.getActivatingPlayer(), game.getNextTimestamp());
Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
moveParams.put(AbilityKey.LastStateBattlefield, lastStateBattlefield);
moveParams.put(AbilityKey.LastStateGraveyard, lastStateGraveyard);
m = game.getAction().moveTo(c.getController().getZone(foundDest), c, sa, moveParams);
if (sa.hasParam("Tapped")) {
c.setTapped(true);
@@ -195,7 +195,7 @@ public class DigUntilEffect extends SpellAbilityEffect {
} else if (sa.hasParam("NoMoveFound") && foundDest.equals(ZoneType.Library)) {
//Don't do anything
} else {
m = game.getAction().moveTo(foundDest, c, foundLibPos, sa);
m = game.getAction().moveTo(foundDest, c, foundLibPos, sa, moveParams);
}
revealed.remove(c);
if (m != null && !origin.equals(m.getZone().getZoneType())) {

View File

@@ -0,0 +1,130 @@
package forge.game.ability.effects;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import forge.game.Game;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.Localizer;
import forge.util.MyRandom;
import java.util.ArrayList;
public class FlipOntoBattlefieldEffect extends SpellAbilityEffect {
@Override
public void resolve(SpellAbility sa) {
// Basic parameters defining the chances
final float chanceToFlip = 0.85f;
final int maxFlipTimes = 2;
final float chanceToHit = 0.70f;
final float chanceToHitTwoCards = 0.20f;
final Card host = sa.getHostCard();
final Player p = sa.getActivatingPlayer();
final Game game = host.getGame();
boolean flippedOnce = false;
// TODO: allow to make a bounding box of sorts somehow, ideally - upgrade to a full system allowing to actually target by location
CardCollectionView tgtBox = p.getController().chooseCardsForEffect(game.getCardsIn(ZoneType.Battlefield), sa, Localizer.getInstance().getMessage("lblChooseDesiredLocation"), 1, 1, sa.hasParam("AllowRandom"), null);
Card tgtLoc = tgtBox.getFirst();
Card lhsNeighbor = getNeighboringCard(tgtLoc, -1);
Card rhsNeighbor = getNeighboringCard(tgtLoc, 1);
CardCollection randChoices = new CardCollection();
randChoices.add(tgtLoc);
if (lhsNeighbor != null) {
randChoices.add(lhsNeighbor);
} else if (rhsNeighbor != null) {
randChoices.add(rhsNeighbor);
}
// TODO: would be fun to add a small chance (e.g. 3-5%) to land unpredictably on some random target?
flippedOnce = MyRandom.getRandom().nextFloat() <= chanceToFlip; // 20% chance that the card won't flip even once
if (!flippedOnce) {
sa.setSVar("TimesFlipped", "0");
game.getAction().notifyOfValue(sa, host, Localizer.getInstance().getMessage("lblDidNotFlipOver"), null);
return;
} else {
int flippedTimes = MyRandom.getRandom().nextInt(maxFlipTimes) + 1;
sa.setSVar("TimesFlipped", String.valueOf(flippedTimes)); // Currently the exact # of times is unused
game.getAction().notifyOfValue(sa, host, Localizer.getInstance().getMessage("lblFlippedOver", flippedTimes), null);
}
// Choose what was hit
CardCollection hit = new CardCollection();
float outcome = MyRandom.getRandom().nextFloat();
if (outcome <= chanceToHitTwoCards) {
hit.addAll(Aggregates.random(randChoices, randChoices.size() > 1 ? 2 : 1));
if (hit.size() == 2) {
game.getAction().notifyOfValue(sa, host, Localizer.getInstance().getMessage("lblLandedOnTwoCards", hit.getFirst(), hit.getLast()), null);
} else {
game.getAction().notifyOfValue(sa, host, Localizer.getInstance().getMessage("lblLandedOnOneCard", hit.getFirst()), null);
}
}
else if (outcome <= chanceToHit) {
hit.add(Aggregates.random(randChoices));
game.getAction().notifyOfValue(sa, host, Localizer.getInstance().getMessage("lblLandedOnOneCard", hit.getFirst()), null);
} else {
game.getAction().notifyOfValue(sa, host, Localizer.getInstance().getMessage("lblDidNotLandOnCards"), null);
}
// Remember whatever was hit
for (Card c : hit) {
host.addRemembered(c);
}
}
@Override
protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder();
final Card host = sa.getHostCard();
final Player p = sa.getActivatingPlayer();
sb.append("Flip ");
sb.append(host.toString());
sb.append(" onto the battlefield from a height of at least one foot.");
return sb.toString();
}
private Card getNeighboringCard(Card c, int direction) {
// Currently gets the nearest (in zone order) card to the left or to the right of the designated one by type
Player controller = c.getController();
ArrayList<Card> cardsOTB = Lists.newArrayList(CardLists.filter(
controller.getCardsIn(ZoneType.Battlefield), new Predicate<Card>() {
@Override
public boolean apply(Card card) {
if (c.isCreature()) {
return card.isCreature();
} else if (c.isPlaneswalker() || c.isArtifact() || (c.isEnchantment() && !c.isAura())) {
return card.isPlaneswalker() || card.isArtifact() || (c.isEnchantment() && !c.isAura());
} else if (c.isLand()) {
return card.isLand();
} else if (c.isAttachedToEntity()) {
return card.isAttachedToEntity(c.getEntityAttachedTo()) || c.equals(card.getAttachedTo());
}
return card.sharesCardTypeWith(c);
}
}
));
int loc = cardsOTB.indexOf(c);
if (direction < 0 && loc > 0) {
return cardsOTB.get(loc - 1);
} else if (loc < cardsOTB.size() - 1) {
return cardsOTB.get(loc + 1);
}
return c;
}
}

View File

@@ -99,12 +99,8 @@ public class MillEffect extends SpellAbilityEffect {
} else if (dest.equals(ZoneType.Ante)) {
sb.append("antes ");
}
sb.append(numCards);
sb.append(" card");
if (numCards != 1) {
sb.append("s");
}
sb.append(".");
sb.append(numCards == 1 ? "a card" : (Lang.getNumeral(numCards) + " cards")).append(".");
return sb.toString();
}

View File

@@ -15,7 +15,6 @@ import forge.game.Game;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardFactory;
import forge.game.card.CardUtil;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.item.PaperCard;
@@ -35,7 +34,7 @@ public class PlayLandVariantEffect extends SpellAbilityEffect {
cards = Lists.newArrayList(Iterables.filter(cards, cpp));
}
// current color of source card
final ColorSet color = CardUtil.getColors(source);
final ColorSet color = source.determineColor();
if (color.isColorless()) {
return;
}

View File

@@ -15,7 +15,6 @@ import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardUtil;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
@@ -65,7 +64,7 @@ public class ProtectAllEffect extends SpellAbilityEffect {
}
} else if (sa.getParam("Gains").equals("TargetedCardColor")) {
for (final Card c : sa.getSATargetingCard().getTargets().getTargetCards()) {
ColorSet cs = CardUtil.getColors(c);
ColorSet cs = c.determineColor();
for (byte col : MagicColor.WUBRG) {
if (cs.hasAnyColor(col))
gains.add(MagicColor.toLongString(col).toLowerCase());

View File

@@ -0,0 +1,37 @@
package forge.game.ability.effects;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.event.GameEventRandomLog;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.item.PaperCard;
public class RemoveFromMatchEffect extends SpellAbilityEffect {
@Override
public void resolve(SpellAbility sa) {
final Card host = sa.getHostCard();
CardCollection toRemove;
if (sa.hasParam("RemoveType")) {
CardCollection cards = (CardCollection) host.getOwner().getGame().getCardsInGame();
if (sa.hasParam("IncludeSideboard")) {
CardCollection sideboard = (CardCollection) host.getGame().getCardsIn(ZoneType.Sideboard);
cards.addAll(sideboard);
}
toRemove = (CardCollection) AbilityUtils.filterListByType(cards, sa.getParam("RemoveType"), sa);
} else {
toRemove = getTargetCards(sa);
}
String logMessage = sa.getParamOrDefault("LogMessage", "Removed from match");
String remove = toRemove.toString().replace("[","").replace("]","");
host.getController().getGame().fireEvent(new GameEventRandomLog(logMessage + ": " + remove));
for (final Card tgtC : toRemove) {
tgtC.getGame().getAction().ceaseToExist(tgtC, true);
PaperCard rem = (PaperCard) tgtC.getPaperCard();
host.getGame().getMatch().removeCard(rem);
}
}
}

View File

@@ -51,7 +51,7 @@ public class TwoPilesEffect extends SpellAbilityEffect {
zone = ZoneType.smartValueOf(sa.getParam("Zone"));
}
final String valid = sa.getParamOrDefault("ValidCards", "");
final String valid = sa.getParamOrDefault("ValidCards", "Card");
final TargetRestrictions tgt = sa.getTargetRestrictions();
final List<Player> tgtPlayers = getTargetPlayers(sa);

View File

@@ -4937,17 +4937,13 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
view.updateEmblem(this);
}
/*
* there are easy checkers for Color. The CardUtil functions should be made
* part of the Card class, so calling out is not necessary
*/
public final boolean isOfColor(final String col) { return CardUtil.getColors(this).hasAnyColor(MagicColor.fromName(col)); }
public final boolean isBlack() { return CardUtil.getColors(this).hasBlack(); }
public final boolean isBlue() { return CardUtil.getColors(this).hasBlue(); }
public final boolean isRed() { return CardUtil.getColors(this).hasRed(); }
public final boolean isGreen() { return CardUtil.getColors(this).hasGreen(); }
public final boolean isWhite() { return CardUtil.getColors(this).hasWhite(); }
public final boolean isColorless() { return CardUtil.getColors(this).isColorless(); }
public final boolean isOfColor(final String col) { return determineColor().hasAnyColor(MagicColor.fromName(col)); }
public final boolean isBlack() { return determineColor().hasBlack(); }
public final boolean isBlue() { return determineColor().hasBlue(); }
public final boolean isRed() { return determineColor().hasRed(); }
public final boolean isGreen() { return determineColor().hasGreen(); }
public final boolean isWhite() { return determineColor().hasWhite(); }
public final boolean isColorless() { return determineColor().isColorless(); }
public final boolean sharesNameWith(final Card c1) {
// in a corner case where c1 is null, there is no name to share with.
@@ -5891,6 +5887,10 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
@Override
public final boolean canBeTargetedBy(final SpellAbility sa) {
if (getOwner().hasLost()) {
return false;
}
if (sa == null) {
return true;
}

View File

@@ -104,6 +104,11 @@ public class CardFactory {
out.setCommander(in.isRealCommander());
//out.setFaceDown(in.isFaceDown());
int foil = in.getCurrentState().getFoil();
if (foil > 0) {
out.setFoil(foil);
}
return out;
}

View File

@@ -338,7 +338,7 @@ public class CardFactoryUtil {
}
for (final Card crd : list) {
ColorSet color = CardUtil.getColors(crd);
ColorSet color = crd.determineColor();
for (int i = 0; i < cntColors; i++) {
if (color.hasAnyColor(MagicColor.WUBRG[i]))
map[i]++;
@@ -376,7 +376,7 @@ public class CardFactoryUtil {
}
for (final Card crd : list) {
ColorSet color = CardUtil.getColors(crd);
ColorSet color = crd.determineColor();
for (int i = 0; i < cntColors; i++) {
if (color.hasAnyColor(MagicColor.WUBRG[i]))
map[i]++;
@@ -407,7 +407,7 @@ public class CardFactoryUtil {
}
for (final Card crd : list) {
ColorSet color = CardUtil.getColors(crd);
ColorSet color = crd.determineColor();
for (int i = 0; i < cntColors; i++) {
if (color.hasAnyColor(colorRestrictions.get(i))) {
map[i]++;

View File

@@ -264,7 +264,7 @@ public final class CardPredicates {
return new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return CardUtil.getColors(c).hasAnyColor(color);
return c.determineColor().hasAnyColor(color);
}
};
} // getColor()
@@ -273,7 +273,7 @@ public final class CardPredicates {
return new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return CardUtil.getColors(c).hasExactlyColor(color);
return c.determineColor().hasExactlyColor(color);
}
};
}
@@ -282,7 +282,7 @@ public final class CardPredicates {
return new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return CardUtil.getColors(c).isColorless();
return c.determineColor().isColorless();
}
};
}

View File

@@ -689,7 +689,7 @@ public class CardProperty {
break;
case "MostProminentColor":
byte mask = CardFactoryUtil.getMostProminentColors(game.getCardsIn(ZoneType.Battlefield));
if (!CardUtil.getColors(card).hasAnyColor(mask))
if (!card.determineColor().hasAnyColor(mask))
return false;
break;
case "LastCastThisTurn":
@@ -703,7 +703,7 @@ public class CardProperty {
if (castSA == null) {
return false;
}
if (!CardUtil.getColors(card).hasAnyColor(castSA.getPayingColors().getColor())) {
if (!card.determineColor().hasAnyColor(castSA.getPayingColors().getColor())) {
return false;
}
break;

View File

@@ -85,10 +85,6 @@ public final class CardUtil {
return false;
}
public static ColorSet getColors(final Card c) {
return c.determineColor();
}
public static boolean isStackingKeyword(final String keyword) {
String kw = keyword;
if (kw.startsWith("HIDDEN")) {
@@ -158,7 +154,6 @@ public final class CardUtil {
public static List<Card> getLastTurnCast(final String valid, final Card src, final CardTraitBase ctb) {
return CardLists.getValidCardsAsList(src.getGame().getStack().getSpellsCastLastTurn(), valid, src.getController(), src, ctb);
}
public static List<Card> getLKICopyList(final Iterable<Card> in, Map<Integer, Card> cachedMap) {
@@ -343,7 +338,7 @@ public final class CardUtil {
byte combinedColor = 0;
for (Card tgt : tgts) {
ColorSet cs = CardUtil.getColors(tgt);
ColorSet cs = tgt.determineColor();
for (byte color : MagicColor.WUBRG) {
if(!cs.hasAnyColor(color))
continue;

View File

@@ -158,7 +158,7 @@ public class TokenInfo {
if (!colorMap.isEmpty()) {
if (!result.isColorless()) {
// change Token Colors
byte color = CardUtil.getColors(result).getColor();
byte color = result.determineColor().getColor();
for (final Map.Entry<String, String> e : colorMap.entrySet()) {
byte v = MagicColor.fromName(e.getValue());

View File

@@ -34,7 +34,6 @@ import forge.game.GameObjectPredicates;
import forge.game.GameType;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardUtil;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
@@ -300,9 +299,9 @@ public class SpellAbilityCondition extends SpellAbilityVariables {
if (first == null) {
return false;
}
byte firstColor = CardUtil.getColors(first).getColor();
byte firstColor = first.determineColor().getColor();
for (Card c : tgts) {
if (CardUtil.getColors(c).getColor() != firstColor) {
if (c.determineColor().getColor() != firstColor) {
return false;
}
}

View File

@@ -1,3 +1,52 @@
#!/bin/sh
#!/bin/bash
# returns the JDK version.
# 8 for 1.8.0_nn, 9 for 9-ea etc, and "no_java" for undetected
# Based on the code from this source: https://eed3si9n.com/detecting-java-version-bash
jdk_version() {
local result
local java_cmd
if [[ -n $(type -p java) ]]
then
java_cmd=java
elif [[ (-n "$JAVA_HOME") && (-x "$JAVA_HOME/bin/java") ]]
then
java_cmd="$JAVA_HOME/bin/java"
fi
local IFS=$'\n'
# remove \r for Cygwin
local lines=$("$java_cmd" -Xms32M -Xmx32M -version 2>&1 | tr '\r' '\n')
if [[ -z $java_cmd ]]
then
result=no_java
else
for line in $lines; do
if [[ (-z $result) && ($line = *"version \""*) ]]
then
local ver=$(echo $line | sed -e 's/.*version "\(.*\)"\(.*\)/\1/; 1q')
# on macOS, sed doesn't support '?'
if [[ $ver = "1."* ]]
then
result=$(echo $ver | sed -e 's/1\.\([0-9]*\)\(.*\)/\1/; 1q')
else
result=$(echo $ver | sed -e 's/\([0-9]*\)\(.*\)/\1/; 1q')
fi
fi
done
fi
echo "$result"
}
v="$(jdk_version)"
SHAREDPARAMS='-Xmx4096m -Dfile.encoding=UTF-8 -jar $project.build.finalName$'
cd $(dirname "${0}")
java -Xmx4096m -Dfile.encoding=UTF-8 -jar $project.build.finalName$
if [[ $v -ge 17 ]]
then
java --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED --add-opens java.base/java.text=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED $SHAREDPARAMS
elif [[ $v -ge 11 ]]
then
java --illegal-access=permit $SHAREDPARAMS
else
java $SHAREDPARAMS
fi

View File

@@ -371,7 +371,7 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
@Override
public void deckTypeSelected(final DecksComboBoxEvent ev) {
if (ev.getDeckType() == DeckType.NET_ARCHIVE_STANDARD_DECK && !refreshingDeckType) {
if(lstDecks.getGameType() != GameType.Constructed)
if (lstDecks.getGameType() != GameType.Constructed)
return;
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
@@ -398,7 +398,7 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
return;
} else if (ev.getDeckType() == DeckType.NET_ARCHIVE_PIONEER_DECK && !refreshingDeckType) {
if(lstDecks.getGameType() != GameType.Constructed)
if (lstDecks.getGameType() != GameType.Constructed)
return;
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
@@ -424,7 +424,7 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
return;
} else if (ev.getDeckType() == DeckType.NET_ARCHIVE_MODERN_DECK && !refreshingDeckType) {
if(lstDecks.getGameType() != GameType.Constructed)
if (lstDecks.getGameType() != GameType.Constructed)
return;
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
@@ -450,7 +450,7 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
return;
} else if (ev.getDeckType() == DeckType.NET_ARCHIVE_PAUPER_DECK && !refreshingDeckType) {
if(lstDecks.getGameType() != GameType.Constructed)
if (lstDecks.getGameType() != GameType.Constructed)
return;
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
@@ -476,7 +476,7 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
return;
} else if (ev.getDeckType() == DeckType.NET_ARCHIVE_LEGACY_DECK && !refreshingDeckType) {
if(lstDecks.getGameType() != GameType.Constructed)
if (lstDecks.getGameType() != GameType.Constructed)
return;
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
@@ -502,7 +502,7 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
return;
} else if (ev.getDeckType() == DeckType.NET_ARCHIVE_VINTAGE_DECK && !refreshingDeckType) {
if(lstDecks.getGameType() != GameType.Constructed)
if (lstDecks.getGameType() != GameType.Constructed)
return;
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
@@ -528,7 +528,7 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
return;
} else if (ev.getDeckType() == DeckType.NET_ARCHIVE_BLOCK_DECK && !refreshingDeckType) {
if(lstDecks.getGameType() != GameType.Constructed)
if (lstDecks.getGameType() != GameType.Constructed)
return;
FThreads.invokeInBackgroundThread(new Runnable() { //needed for loading net decks
@Override
@@ -712,7 +712,6 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
prefs.save();
}
private String getState() {
final StringBuilder state = new StringBuilder();
DeckType selectedDeckType = this.selectedDeckType; // decksComboBox.getDeckType()
@@ -827,7 +826,6 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener {
}
}
private List<String> getSelectedDecksFromSavedState(final String savedState) {
try {
if (StringUtils.isBlank(savedState)) {

View File

@@ -216,7 +216,6 @@ public abstract class ACEditorBase<TItem extends InventoryItem, TModel extends D
}
for (final Entry<TItem, Integer> itemEntry : itemsToAdd) {
final TItem item = itemEntry.getKey();
final PaperCard card = item instanceof PaperCard ? (PaperCard)item : null;
int qty = itemEntry.getValue();
@@ -224,8 +223,7 @@ public abstract class ACEditorBase<TItem extends InventoryItem, TModel extends D
int max;
if (deck == null || card == null || limit == CardLimit.None || DeckFormat.canHaveAnyNumberOf(card)) {
max = Integer.MAX_VALUE;
}
else {
} else {
max = (limit == CardLimit.Singleton ? 1 : FModel.getPreferences().getPrefInt(FPref.DECK_DEFAULT_CARD_LIMIT));
Integer cardCopies = DeckFormat.canHaveSpecificNumberInDeck(card);
@@ -538,16 +536,16 @@ public abstract class ACEditorBase<TItem extends InventoryItem, TModel extends D
CardManager cardManager = (CardManager) CDeckEditorUI.SINGLETON_INSTANCE.getCurrentEditorController().getDeckManager();
PaperCard existingCard = cardManager.getSelectedItem();
// make a foiled version based on the original
PaperCard foiledCard = existingCard.getFoiled();
PaperCard foiledCard = existingCard.isFoil() ? existingCard.getUnFoiled() : existingCard.getFoiled();
// remove *quantity* instances of existing card
CDeckEditorUI.SINGLETON_INSTANCE.removeSelectedCards(false, quantity);
// add *quantity* into the deck and set them as selected
cardManager.addItem(foiledCard, quantity);
cardManager.setSelectedItem(foiledCard);
}
}, true, true);
}, true, true);
}
//TODO: need to translate getItemDisplayString
//TODO: need to translate getItemDisplayString
private void addItem(final String verb, final String dest, final boolean toAlternate, final int qty, final int shortcutModifiers) {
String label = verb + " " + SItemManagerUtil.getItemDisplayString(getItemManager().getSelectedItems(), qty, false);
if (dest != null && !dest.isEmpty()) {
@@ -563,8 +561,7 @@ public abstract class ACEditorBase<TItem extends InventoryItem, TModel extends D
}
if (isAddContextMenu) {
CDeckEditorUI.SINGLETON_INSTANCE.addSelectedCards(toAlternate, quantity);
}
else {
} else {
CDeckEditorUI.SINGLETON_INSTANCE.removeSelectedCards(toAlternate, quantity);
}
}

View File

@@ -27,7 +27,6 @@ import forge.gui.framework.FScreen;
import forge.item.PaperCard;
import forge.itemmanager.CardManager;
import forge.itemmanager.ItemManagerConfig;
import forge.itemmanager.filters.DeckSetFilter;
import forge.localinstance.properties.ForgePreferences.FPref;
import forge.model.FModel;
import forge.screens.deckeditor.AddBasicLandsDialog;

View File

@@ -86,10 +86,9 @@ public class DeckController<T extends DeckBase> {
/**
* Load deck from file or clipboard
*/
public void loadDeck(Deck deck){
public void loadDeck(Deck deck) {
this.loadDeck(deck, true);
}
public void loadDeck(Deck deck, boolean substituteCurrentDeck) {
boolean isStored;
if (view.getCatalogManager().isInfinite()) {
@@ -159,7 +158,6 @@ public class DeckController<T extends DeckBase> {
}
private void pickFromCatalog(Map<String, Integer> countByName, CardPool catalog, CardPool targetSection) {
CardPool catalogClone = new CardPool(catalog); // clone to iterate modified collection
for (Map.Entry<PaperCard, Integer> entry : catalogClone) {
PaperCard availableCard = entry.getKey();
@@ -218,7 +216,6 @@ public class DeckController<T extends DeckBase> {
public void setModel(final T document) {
setModel(document, false);
}
private void setModel(final T document, final boolean isStored) {
model = document;
onModelChanged(isStored);
@@ -234,8 +231,7 @@ public class DeckController<T extends DeckBase> {
if (isStored) {
if (isModelInSyncWithFolder()) {
setSaved(true);
}
else {
} else {
notifyModelChanged();
}
} else { //TODO: Make this smarter
@@ -317,8 +313,7 @@ public class DeckController<T extends DeckBase> {
final T newModel = currentFolder.get(name);
if (newModel != null) {
setModel((T) newModel.copyTo(name), true);
}
else {
} else {
setSaved(true);
}
}

View File

@@ -8,7 +8,6 @@ import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
@@ -96,7 +95,6 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
pnlContent.setOpaque(false);
if (javaRecentEnough()) {
// With Blacksmith we would upload the releases and the /latest would redirect to the right URL
// That currently doesn't happen so lets comment out this button for now
// pnlContent.add(btnCheckForUpdates, constraintsBTN);
@@ -122,9 +120,7 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
pnlContent.add(btnDownloadSkins, constraintsBTN);
pnlContent.add(_makeLabel(localizer.getMessage("lblDownloadSkins")), constraintsLBL);
} else {
String text = localizer.getMessage("lblYourVersionOfJavaIsTooOld");
FLabel label = new FLabel.Builder().fontAlign(SwingConstants.CENTER).text(text).fontStyle(Font.BOLD).fontSize(18).build();
pnlContent.add(label, "w 90%!, h 25px!, center, gap 0 0 30px 3px");
@@ -137,7 +133,6 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
text = text + " . " + localizer.getMessage("lblYouNeedAtLeastJavaVersion") ;
label = new FLabel.Builder().fontAlign(SwingConstants.CENTER).text(text).fontStyle(Font.BOLD).fontSize(18).build();
pnlContent.add(label, "w 90%!, h 25px!, center, gap 0 0 0 36px");
}
pnlContent.add(btnListImageData, constraintsBTN);
@@ -154,15 +149,12 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
pnlContent.add(btnLicensing, constraintsBTN);
pnlContent.add(_makeLabel(localizer.getMessage("lblLicensing")), constraintsLBL);
}
private boolean javaRecentEnough() {
RuntimeVersion javaVersion = RuntimeVersion.of(System.getProperty("java.version"));
return javaVersion.getMajor() >= 9 || (javaVersion.getMajor() >= 1 && (javaVersion.getMinor() > 8 || (javaVersion.getMinor() == 8 && javaVersion.getUpdate() >= 101)));
}
/* (non-Javadoc)
@@ -199,7 +191,7 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
public void setHowToPlayCommand(UiCommand command) { btnHowToPlay.setCommand(command); }
public void setDownloadPricesCommand(UiCommand command) { btnDownloadPrices.setCommand(command); }
public void setLicensingCommand(UiCommand command) { btnLicensing.setCommand(command); }
public void setDownloadSkinsCommand(UiCommand command) { btnDownloadSkins.setCommand(command); }
public void setDownloadSkinsCommand(UiCommand command) { btnDownloadSkins.setCommand(command); }
public void focusTopButton() {
btnDownloadPics.requestFocusInWindow();
@@ -269,7 +261,6 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
String imagePath;
int artIndex = 1;
ArrayList<String> cis = new ArrayList<>();
HashMap<String, Pair<Boolean, Integer>> cardCount = new HashMap<>();
for (CardInSet c : e.getAllCardsInSet()) {
@@ -302,10 +293,7 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
continue;
}
//
// check the front image
//
imagePath = ImageUtil.getImageRelativePath(cp, false, true, false);
if (imagePath != null) {
File file = ImageKeys.getImageFile(imagePath);
@@ -319,9 +307,7 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
}
}
//
// check the back face
//
if (cp.hasBackFace()) {
imagePath = ImageUtil.getImageRelativePath(cp, true, true, false);
if (imagePath != null) {
@@ -372,7 +358,6 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
nifSB.append("\n");
}
String totalStats = "Missing images: " + missingCount + "\nUnimplemented cards: " + notImplementedCount + "\n";
cniSB.append("\n-----------\n");
cniSB.append(totalStats);
@@ -425,7 +410,6 @@ public enum VSubmenuDownloaders implements IVSubmenu<CSubmenuDownloaders> {
});
}
public void showLicensing() {
String license = "<html>Forge License Information<br><br>"
+ "This program is free software : you can redistribute it and/or modify "

View File

@@ -23,7 +23,7 @@ public class IntegerConstraint {
@Override
public String toString() {
if( min == max ) {
if (min == max) {
return String.valueOf( min );
}
return "between " + min + " and " + max;

View File

@@ -339,17 +339,14 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
//hide deck header on while drafting
setDeck(new Deck());
deckHeader.setVisible(false);
}
else {
} else {
if (newDeck == null) {
editorType.getController().newModel();
}
else {
} else {
editorType.getController().setDeck(newDeck);
}
}
}
else {
} else {
if (editorType == EditorType.Draft || editorType == EditorType.QuestDraft) {
tabPages[0].hideTab(); //hide Draft Pack page if editing existing draft deck
}
@@ -897,8 +894,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
public void handleEvent(FEvent e) {
if (max == 1) {
callback.run(max);
}
else {
} else {
final Localizer localizer = Localizer.getInstance();
GuiChoose.getInteger(cardManager.getSelectedItem() + " - " + verb + " " + localizer.getMessage("lblHowMany"), 1, max, 20, callback);
}
@@ -1150,8 +1146,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
default:
// Do nothing
}
}
else {
} else {
//if a commander has been set, only show cards that match its color identity
switch (editorType) {
case Commander:
@@ -1176,8 +1171,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
default:
if (cardManager.getWantUnique()) {
cardManager.setPool(editorType.applyCardFilter(FModel.getUniqueCardsNoAlt(), additionalFilter), true);
}
else {
} else {
cardManager.setPool(editorType.applyCardFilter(FModel.getAllCardsNoAlt(), additionalFilter), true);
}
break;
@@ -1250,8 +1244,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
CardPreferences.save();
}
}));
}
else {
} else {
menu.addItem(new FMenuItem(localizer.getMessage("lblRemoveFavorites"), Forge.hdbuttons ? FSkinImage.HDSTAR_OUTLINE : FSkinImage.STAR_OUTLINE, new FEventHandler() {
@Override
public void handleEvent(FEvent e) {
@@ -1376,8 +1369,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
protected void updateCaption() {
if (deckSection == DeckSection.Commander) {
caption = captionPrefix; //don't display count for commander section since it won't be more than 1
}
else {
} else {
caption = captionPrefix + " (" + parentScreen.getDeck().get(deckSection).countAll() + ")";
}
}
@@ -1767,8 +1759,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
if (isStored) {
if (isModelInSyncWithFolder()) {
setSaved(true);
}
else {
} else {
notifyModelChanged();
}
}
@@ -1779,8 +1770,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
}
if (model != null) {
editor.setDeck(model.getHumanDeck());
}
else {
} else {
editor.setDeck(null);
}

View File

@@ -525,6 +525,9 @@ public abstract class ItemManager<T extends InventoryItem> extends FContainer im
}
public void addItem(final T item, int qty) {
if (pool == null) {
return;
}
pool.add(item, qty);
if (isUnfiltered()) {
model.addItem(item, qty);

View File

@@ -6,6 +6,6 @@ SVar:TrigExile:DB$ ChangeZone | Defined$ TriggeredCard | Origin$ Graveyard | Des
A:AB$ Draw | Cost$ 2 T | NumCards$ 1 | SpellDescription$ Draw a card, then discard a card. | SubAbility$ DBDiscard
SVar:DBDiscard:DB$ Discard | Defined$ You | NumCards$ 1 | Mode$ TgtChoose
AI:RemoveDeck:All
A:AB$ ChangeZoneAll | Cost$ 4 T Sac<1/CARDNAME> | ChangeType$ Card.ExiledWithSource | Origin$ Exile | Destination$ Hand | AILogic$ DiscardAllAndRetExiled.minAdv2 | SpellDescription$ Return all cards exiled with CARDNAME to their owner's hand.
A:AB$ ChangeZoneAll | Cost$ 4 T Sac<1/CARDNAME> | ChangeType$ Card.ExiledWithSource | Origin$ Exile | Destination$ Hand | AILogic$ DiscardAllAndRetExiled.noDiscard.minAdv2 | SpellDescription$ Return all cards exiled with CARDNAME to their owner's hand.
AI:RemoveDeck:Random
Oracle:Whenever you discard a card, exile that card from your graveyard.\n{2}, {T}: Draw a card, then discard a card.\n{4}, {T}, Sacrifice Bag of Holding: Return all cards exiled with Bag of Holding to their owner's hand.

View File

@@ -0,0 +1,6 @@
Name:Blacker Lotus
ManaCost:0
Types:Artifact
A:AB$ Mana | Cost$ T | Produced$ Any | Amount$ 4 | AILogic$ BlackLotus | SubAbility$ DBTearUpAndRemove | SpellDescription$ Tear CARDNAME into pieces. Add four mana of any one color. Remove the pieces from the game.
SVar:DBTearUpAndRemove:DB$ RemoveFromMatch | Defined$ Self | LogMessage$ Torn to pieces and removed
Oracle:{T}: Tear Blacker Lotus into pieces. Add four mana of any one color. Remove the pieces from the game.

View File

@@ -0,0 +1,8 @@
Name:Chaos Orb
ManaCost:2
Types:Artifact
A:AB$ FlipOntoBattlefield | Cost$ 1 T | SubAbility$ DBDestroyTouched | ActivationZone$ Battlefield | SpellDescription$ If CARDNAME is on the battlefield, flip CARDNAME onto the battlefield from a height of at least one foot. If CARDNAME turns over completely at least once during the flip, destroy all nontoken permanents it touches. Then destroy CARDNAME. | StackDescription$ SpellDescription
SVar:DBDestroyTouched:DB$ DestroyAll | ValidCards$ Card.IsRemembered+nonToken | SubAbility$ DBDestroyChaosOrb | AILogic$ Always | StackDescription$ None
SVar:DBDestroyChaosOrb:DB$ Destroy | Defined$ Self | SubAbility$ DBCleanup | AILogic$ Always | StackDescription$ None
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
Oracle:{1}, {T}: If Chaos Orb is on the battlefield, flip Chaos Orb onto the battlefield from a height of at least one foot. If Chaos Orb turns over completely at least once during the flip, destroy all nontoken permanents it touches. Then destroy Chaos Orb.

View File

@@ -1,10 +1,9 @@
Name:Fact or Fiction
ManaCost:3 U
Types:Instant
A:SP$ Dig | Cost$ 3 U | DigNum$ 5 | Reveal$ True | RememberRevealed$ True | NoMove$ True | SubAbility$ DBTwoPiles | SpellDescription$ Reveal the top five cards of your library. An opponent separates those cards into two piles. Put one pile into your hand and the other into your graveyard.
SVar:DBTwoPiles:DB$ TwoPiles | Defined$ You | DefinedCards$ Remembered | Separator$ Opponent | ChosenPile$ DBHand | UnchosenPile$ DBGrave
A:SP$ Dig | DigNum$ 5 | Reveal$ True | RememberRevealed$ True | NoMove$ True | SubAbility$ DBTwoPiles | SpellDescription$ Reveal the top five cards of your library. An opponent separates those cards into two piles. Put one pile into your hand and the other into your graveyard.
SVar:DBTwoPiles:DB$ TwoPiles | Defined$ You | DefinedCards$ Remembered | Separator$ Opponent | ChosenPile$ DBHand | UnchosenPile$ DBGrave | StackDescription$ An opponent separates those cards into two piles. {p:You} puts one pile into their hand and the other into their graveyard.
SVar:DBHand:DB$ ChangeZone | Defined$ Remembered | Origin$ Library | Destination$ Hand | SubAbility$ DBCleanup
SVar:DBGrave:DB$ ChangeZone | Defined$ Remembered | Origin$ Library | Destination$ Graveyard | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:Picture:http://www.wizards.com/global/images/magic/general/fact_or_fiction.jpg
Oracle:Reveal the top five cards of your library. An opponent separates those cards into two piles. Put one pile into your hand and the other into your graveyard.

View File

@@ -0,0 +1,7 @@
Name:Falling Star
ManaCost:2 R
Types:Sorcery
A:SP$ FlipOntoBattlefield | SubAbility$ DBDamageTouched | AILogic$ DamageCreatures | SpellDescription$ Flip CARDNAME onto the playing area from a height of at least one foot. CARDNAME deals 3 damage to each creature it lands on. Tap all creatures dealt damage by CARDNAME. If CARDNAME doesn't turn completely over at least once during the flip, it has no effect. | StackDescription$ SpellDescription
SVar:DBDamageTouched:DB$ DamageAll | ValidCards$ Creature.IsRemembered | ValidDescription$ each creature touched. | NumDmg$ 3 | SubAbility$ DBCleanup | StackDescription$ None
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
Oracle:Flip Falling Star onto the playing area from a height of at least one foot. Falling Star deals 3 damage to each creature it lands on. Tap all creatures dealt damage by Falling Star. If Falling Star doesn't turn completely over at least once during the flip, it has no effect.

View File

@@ -5,5 +5,5 @@ PT:3/3
K:Double Strike
K:Evoke:ExileFromHand<1/Card.Red+Other/red card>
T:Mode$ ChangesZone | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDamage | TriggerDescription$ When CARDNAME enters the battlefield, it deals 4 damage divided as you choose among any number of target creatures and/or planeswalkers.
SVar:TrigDamage:DB$ DealDamage | ValidTgts$ Creature,Planeswalker | TgtPrompt$ Select target creature or planeswalker to distribute damage to | NumDmg$ 4 | TargetMin$ 1 | TargetMax$ 4 | DividedAsYouChoose$ 4
SVar:TrigDamage:DB$ DealDamage | ValidTgts$ Creature,Planeswalker | TgtPrompt$ Select target creature or planeswalker to distribute damage to | NumDmg$ 4 | TargetMin$ 0 | TargetMax$ 4 | DividedAsYouChoose$ 4
Oracle:Double strike\nWhen Fury enters the battlefield, it deals 4 damage divided as you choose among any number of target creatures and/or planeswalkers.\nEvoke—Exile a red card from your hand.

View File

@@ -7,4 +7,5 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.S
SVar:TrigEffect:DB$ Effect | Triggers$ TrigDamageDone
SVar:TrigDamageDone:Mode$ DamageDone | ValidTarget$ Creature.OppCtrl | Execute$ TrigDestroy | TriggerDescription$ Poison Breath — Until end of turn, whenever a creature an opponent controls is dealt damage, destroy it.
SVar:TrigDestroy:DB$ Destroy | Defined$ TriggeredTarget
SVar:PlayMain1:TRUE
Oracle:Flying\nPoison Breath — When Green Dragon enters the battlefield, until end of turn, whenever a creature an opponent controls is dealt damage, destroy it.

View File

@@ -14,5 +14,5 @@ ManaCost:1 G
Types:Legendary Artifact
K:ETBReplacement:Other:ChooseCT
SVar:ChooseCT:DB$ ChooseType | Defined$ You | Type$ Creature | AILogic$ MostProminentInComputerDeck | SpellDescription$ As CARDNAME enters the battlefield, choose a creature type.
A:AB$ Mana | Cost$ T | Produced$ G | RestrictValid$ Creature.ChosenType,Creature.Legendary | SpellDescription$ {T}: Add {G}. Spend this mana only to cast a creature spell of the chosen type or a legendary creature spell.
A:AB$ Mana | Cost$ T | Produced$ G | RestrictValid$ Creature.ChosenType,Creature.Legendary | SpellDescription$ Add {G}. Spend this mana only to cast a creature spell of the chosen type or a legendary creature spell.
Oracle:As The Ringhart Crest enters the battlefield, choose a creature type.\n{T}: Add {G}. Spend this mana only to cast a creature spell of the chosen type or a legendary creature spell.

View File

@@ -0,0 +1,6 @@
Name:Look at Me, I'm the DCI
ManaCost:5 W W
Types:Sorcery
A:SP$ NameCard | Defined$ You | ValidCards$ Card.nonBasic | SelectPrompt$ Choose a card other than a basic land card to ban | SubAbility$ DBRemove | AILogic$ MostProminentInHumanDeck | StackDescription$ None | SpellDescription$ Ban a card other than a basic land card for the rest of the match. (All cards with that name in any zone or sideboard are removed from the match.)
SVar:DBRemove:DB$ RemoveFromMatch | RemoveType$ Card.NamedCard | IncludeSideboard$ True | StackDescription$ Ban a card other than a basic land card for the rest of the match. (All cards with that name in any zone or sideboard are removed from the match.)
Oracle:Ban a card other than a basic land card for the rest of the match. (All cards with that name in any zone or sideboard are removed from the match.)

View File

@@ -3,6 +3,6 @@ ManaCost:1 U R
Types:Legendary Creature Human Wizard
PT:1/4
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ Player | Execute$ DrawDamageOther | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of each player's end step, that player may draw a card if a player other than you lost life this turn.
SVar:DrawDamageOther:DB$ Draw | Defined$ TriggeredPlayer | NumCards$ 1 | ConditionPlayerDefined$ Player.Other | ConditionPlayerContains$ Player.wasDealtDamageThisTurn | OptionalDecider$ True
SVar:DrawDamageOther:DB$ Draw | Defined$ TriggeredPlayer | NumCards$ 1 | ConditionPlayerDefined$ Player.Other | ConditionPlayerContains$ Player.LostLifeThisTurn | OptionalDecider$ True
K:Partner
Oracle:At the beginning of each player's end step, that player may draw a card if a player other than you lost life this turn.\nPartner (You can have two commanders if both have partner.)

View File

@@ -2,10 +2,10 @@ Name:Sorin, Lord of Innistrad
ManaCost:2 W B
Types:Legendary Planeswalker Sorin
Loyalty:3
A:AB$ Token | Cost$ AddCounter<1/LOYALTY> | TokenAmount$ 1 | TokenScript$ b_1_1_vampire_lifelink | TokenOwner$ You | LegacyImage$ b 1 1 vampire lifelink dka | Planeswalker$ True | SpellDescription$ Create a 1/1 black Vampire creature token with lifelink.
A:AB$ Token | Cost$ AddCounter<1/LOYALTY> | TokenAmount$ 1 | TokenScript$ b_1_1_vampire_lifelink | Planeswalker$ True | SpellDescription$ Create a 1/1 black Vampire creature token with lifelink.
A:AB$ Effect | Cost$ SubCounter<2/LOYALTY> | Name$ Emblem - Sorin, Lord of Innistrad | Image$ emblem_sorin_lord_of_innistrad | StaticAbilities$ STPump | Planeswalker$ True | Duration$ Permanent | AILogic$ Always | SpellDescription$ You get an emblem with "Creatures you control get +1/+0."
SVar:STPump:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Creature.YouCtrl | AddPower$ 1
A:AB$ Destroy | Cost$ SubCounter<6/LOYALTY> | Planeswalker$ True | Ultimate$ True | ValidTgts$ Creature,Planeswalker.Other | TargetMin$ 0 | TargetMax$ 3 | TgtPrompt$ Select target creatures or other planeswalkers | RememberTargets$ True | ForgetOtherTargets$ True | SubAbility$ DBChangeZoneAll | SpellDescription$ Destroy up to 3 target creatures and/or other planeswalkers. Return each card put into a graveyard this way to the battlefield under your control.
A:AB$ Destroy | Cost$ SubCounter<6/LOYALTY> | Planeswalker$ True | Ultimate$ True | ValidTgts$ Creature,Planeswalker.Other | TargetMin$ 0 | TargetMax$ 3 | TgtPrompt$ Select target creatures or other planeswalkers | RememberTargets$ True | ForgetOtherTargets$ True | SubAbility$ DBChangeZoneAll | SpellDescription$ Destroy up to three target creatures and/or other planeswalkers. Return each card put into a graveyard this way to the battlefield under your control.
SVar:DBChangeZoneAll:DB$ ChangeZoneAll | ChangeType$ Card.IsRemembered | Origin$ Graveyard | Destination$ Battlefield | GainControl$ True | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:Picture:http://www.wizards.com/global/images/magic/general/sorin_lord_of_innistrad.jpg

View File

@@ -0,0 +1,113 @@
Name:Urza, Academy Headmaster
ManaCost:W U B R G
Types:Legendary Planeswalker Urza
Loyalty:4
A:AB$ GenericChoice | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | AtRandom$ Urza | ShowChoice$ Description | Choices$ Pump1,PutCounter2,Destroy3,Token4,Token5,Token6,Dig7,MustAttack8,PutCounter9,Effect10,Exile11,Dig12,Animate13,Draw14,Animate15,PumpAll16,Dig17,DealDamage18,Animate19,Mana20 | ShowChoice$ Description | StackDescription$ SpellDescription | SpellDescription$ Head to AskUrza.com and click +1.
SVar:Pump1:DB$ Pump | TargetMin$ 0 | TargetMax$ 1 | KW$ First Strike & Vigilance & Lifelink | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ +1 | NumDef$ +1 | KW$ First Strike & Vigilance & Lifelink | SpellDescription$ Until end of turn, up to one target creature gets +1/+1 and gains first strike, vigilance, and lifelink.
SVar:PutCounter2:DB$ PutCounter | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control to distribute counters to | CounterType$ P1P1 | CounterNum$ 3 | TargetMin$ 1 | TargetMax$ 3 | DividedAsYouChoose$ 3 | SpellDescription$ Distribute three +1/+1 counters among one, two, or three target creatures you control.
SVar:Destroy3:DB$ Destroy | ValidTgts$ Permanent.nonCreature | TgtPrompt$ Select a noncreature permanent | SpellDescription$ Destroy target noncreature permanent.
SVar:Token4:DB$ Token | TokenAmount$ 2 | TokenScript$ r_3_1_elemental_haste | AtEOT$ Exile | SpellDescription$ Create two 3/1 red Elemental creature tokens with haste. Exile them at the beginning of the next end step.
SVar:Token5:DB$ Token | TokenAmount$ 3 | TokenScript$ w_1_1_soldier | SpellDescription$ Create three 1/1 white Soldier creature tokens.
SVar:Token6:DB$ Token | TokenScript$ b_3_3_beast_deathtouch | SpellDescription$ Create a 3/3 black Beast creature token with deathtouch.
SVar:Dig7:DB$ Dig | DigNum$ 5 | Reveal$ True | ChangeNum$ All | ChangeValid$ Creature | SpellDescription$ Reveal the top five cards of your library. Put all creature cards revealed this way into your hand and the rest on the bottom of your library in any order.
SVar:MustAttack8:DB$ MustAttack | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | Defender$ Self | SpellDescription$ During target opponent's next turn, creatures that player controls attack NICKNAME if able.
SVar:PutCounter9:DB$ PutCounter | Defined$ Self | CounterType$ LOYALTY | CounterNum$ X9 | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | StackDescription$ SpellDescription | SpellDescription$ Put a loyalty counter on NICKNAME for each creature target opponent controls.
SVar:X9:TargetedPlayer$CreaturesInPlay
SVar:Effect10:DB$ Effect | Triggers$ TrigAttack10 | Duration$ UntilYourNextTurn | SpellDescription$ Until your next turn, whenever a creature an opponent controls attacks, it gets -1/-0 until end of turn.
SVar:TrigAttack10:Mode$ Attacks | ValidCard$ Creature.OppCtrl | TriggerZones$ Command | Execute$ DebuffAttacker10 | TriggerDescription$ Whenever a creature an opponent controls attacks, it gets -1/-0 until end of turn.
SVar:DebuffAttacker10:DB$ Pump | Defined$ TriggeredAttacker | NumAtt$ -1
SVar:Exile11:DB$ ChangeZone | ValidTgts$ Player | TgtPrompt$ Select target player | Origin$ Hand | Destination$ Exile | ChangeType$ Card | ChangeNum$ 1 | Chooser$ Targeted | Hidden$ True | IsCurse$ True | Mandatory$ True | SpellDescription$ Target player exiles a card from their hand.
SVar:Dig12:DB$ Dig | DigNum$ 1 | Reveal$ True | ChangeNum$ All | ChangeValid$ Land | DestinationZone$ Battlefield | DestinationZone2$ Hand | SpellDescription$ Reveal the top card of your library. If it's a land card, put it onto the battlefield. Otherwise, put it into your hand.
SVar:Animate13:DB$ Animate | ValidTgts$ Land.YouCtrl | TgtPrompt$ Select target land you control | Power$ 4 | Toughness$ 4 | Types$ Creature,Elemental | Duration$ Permanent | Keywords$ Trample | SpellDescription$ Target land you control becomes a 4/4 Elemental creature with trample. It's still a land.
SVar:Draw14:DB$ Draw | Defined$ You | SubAbility$ DBMana14 | SpellDescription$ Draw a card, then add one mana of any color.
SVar:DBMana14:DB$ Mana | Produced$ Any | AILogic$ MostProminentInComputerHand
SVar:Animate15:DB$ Animate | Power$ 4 | Toughness$ 4 | Types$ Creature,Legendary,Dragon | Colors$ Red | OverwriteColors$ True | RemoveCardTypes$ True | Keywords$ Flying & Indestructible & Haste | SpellDescription$ Until end of turn, NICKNAME becomes a legendary 4/4 red Dragon creature with flying, indestructible, and haste. (He doesn't lose loyalty while he's not a planeswalker.)
SVar:PumpAll16:DB$ PumpAll | ValidCards$ Creature.YouCtrl | NumAtt$ +1 | KW$ Lifelink | Duration$ UntilYourNextTurn | SpellDescription$ Until your next turn, creatures you control get +1/+0 and gain lifelink.
SVar:Dig17:DB$ Dig | DigNum$ 5 | ChangeNum$ 1 | Optional$ True | ChangeValid$ Artifact | SpellDescription$ Look at the top five cards of your library. You may reveal an artifact card from among them and put it into your hand. Put the rest on the bottom of your library in any order.
SVar:DealDamage18:DB$ DealDamage | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 3 | SpellDescription$ NICKNAME deals 3 damage to any target.
SVar:Animate19:DB$ Animate | Defined$ Self | Triggers$ DamageTrig19 | Duration$ UntilYourNextTurn | SpellDescription$ Until your next turn, whenever a creature deals combat damage to NICKNAME, destroy that creature. | StackDescription$ SpellDescription
SVar:DamageTrig19:Mode$ DamageDone | ValidSource$ Creature | ValidTarget$ Card.Self | TriggerZones$ Battlefield | CombatDamage$ True | Execute$ TrigDestroy19 | TriggerDescription$ Whenever a creature deals combat damage to NICKNAME, destroy that creature.
SVar:TrigDestroy19:DB$ Destroy | Defined$ TriggeredSourceLKICopy
SVar:Mana20:DB$ Mana | Produced$ Combo Any | Amount$ X20 | SpellDescription$ Add X mana in any combination of colors, where X is the number of creatures you control.
SVar:X20:Count$Valid Creature.YouCtrl
A:AB$ GenericChoice | Cost$ SubCounter<1/LOYALTY> | Planeswalker$ True | AtRandom$ Urza | ShowChoice$ Description | Choices$ DamageAll1M,GainControl2M,DealDamage3M,Destroy4M,Effect5M,ChangeZone6M,Draw7M,Mill8M,Dig9M,Exile10M,Reveal11M,Tutor12M,Sacrifice13M,Token14M,Token15M,SetLife16M,Destroy17M,Return18M,Token19M,Draw20M | ShowChoice$ Description | StackDescription$ SpellDescription | SpellDescription$ Head to AskUrza.com and click -1.
SVar:DamageAll1M:DB$ DamageAll | NumDmg$ 3 | ValidCards$ Creature | SpellDescription$ NICKNAME deals 3 damage to each creature.
SVar:GainControl2M:DB$ GainControl | ValidTgts$ Creature | TgtPrompt$ Select target creature | SpellDescription$ Gain control of target creature.
SVar:DealDamage3M:DB$ DealDamage | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ 4 | SubAbility$ DBGainLife3M | SpellDescription$ NICKNAME deals 4 damage to any target and you gain 4 life.
SVar:DBGainLife3M:DB$ GainLife | Defined$ You | LifeAmount$ 4
SVar:Destroy4M:DB$ Destroy | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBGainLife4M | SpellDescription$ Destroy target creature. You gain life equal to its toughness.
SVar:DBGainLife4M:DB$ GainLife | Defined$ You | LifeAmount$ X4M
SVar:X4M:TargetedLKI$CardToughness
SVar:Effect5M:DB$ Effect | Name$ Emblem - Urza, Academy Headmaster (5M) | StaticAbilities$ STPump5M | Duration$ Permanent | SpellDescription$ You get an emblem with "Creatures you control get +1/+1."
SVar:STPump5M:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Creature.YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Creatures you control get +1/+1.
SVar:ChangeZone6M:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | ChangeType$ Creature | ChangeNum$ 1 | SpellDescription$ You may put a creature card from your hand onto the battlefield.
SVar:Draw7M:DB$ Draw | NumCards$ 3 | SubAbility$ DBChangeZone7M | SpellDescription$ Draw three cards, then put a card from your hand on top of your library.
SVar:DBChangeZone7M:DB$ ChangeZone | Origin$ Hand | Destination$ Library | ChangeType$ Card | ChangeNum$ 1 | Mandatory$ True | SelectPrompt$ Select a card from your hand to put on top of your library
SVar:Mill8M:DB$ Mill | ValidTgts$ Player | TgtPrompt$ Select target player | NumCards$ 10 | SpellDescription$ Target player puts the top ten cards of their library into their graveyard.
SVar:Dig9M:DB$ Dig | DigNum$ 5 | Reveal$ True | RememberRevealed$ True | NoMove$ True | SubAbility$ DBTwoPiles9M | SpellDescription$ Reveal the top five cards of your library. An opponent separates them into two piles. Put one pile into your hand and the other on the bottom of your library in any order.
SVar:DBTwoPiles9M:DB$ TwoPiles | Defined$ You | DefinedCards$ Remembered | Separator$ Opponent | ChosenPile$ DBHand9M | UnchosenPile$ DBLibraryBottom9M
SVar:DBHand9M:DB$ ChangeZone | Defined$ Remembered | Origin$ Library | Destination$ Hand
SVar:DBLibraryBottom9M:DB$ ChangeZoneAll | ChangeType$ Card.IsRemembered | Origin$ Library | Destination$ Library | LibraryPosition$ -1 | SubAbility$ DBCleanup
SVar:Exile10M:DB$ ChangeZone | ValidTgts$ Permanent | TgtPrompt$ Select target permanent | Origin$ Battlefield | Destination$ Exile | SpellDescription$ Exile target permanent.
SVar:Reveal11M:DB$ Dig | DigNum$ 5 | Reveal$ True | RememberRevealed$ True | NoMove$ True | SubAbility$ DBChangeCreatures11M | SpellDescription$ Reveal the top five cards of your library. You may put all creature cards and/or land cards from among them into your hand. Put the rest into your graveyard.
SVar:DBChangeCreatures11M:DB$ ChangeZoneAll | ChangeType$ Card.Creature+IsRemembered | Origin$ Library | Destination$ Hand | Optional$ True | OptionQuestion$ Put all creature cards into your hand? | ForgetChanged$ True | SubAbility$ DBChangeLands11M
SVar:DBChangeLands11M:DB$ ChangeZoneAll | ChangeType$ Card.Land+IsRemembered | Origin$ Library | Destination$ Hand | Optional$ True | OptionQuestion$ Put all land cards into your hand? | ForgetChanged$ True | SubAbility$ DBChangeRest11M
SVar:DBChangeRest11M:DB$ ChangeZoneAll | ChangeType$ Card.IsRemembered | Origin$ Library | Destination$ Graveyard | ForgetChanged$ True
SVar:Tutor12M:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Card | ChangeNum$ 1 | Mandatory$ True | SpellDescription$ Search your library for a card and put that card into your hand. Then shuffle your library.
SVar:Sacrifice13M:DB$ Sacrifice | ValidTgts$ Player | Amount$ 2 | SacValid$ Creature | SpellDescription$ Target player sacrifices two creatures.
SVar:Token14M:DB$ Token | TokenScript$ b_5_5_demon_flying | SubAbility$ DBLoselife14M | SpellDescription$ Create a 5/5 black Demon creature token with flying. You lose 2 life.
SVar:DBLoselife14M:DB$ LoseLife | LifeAmount$ 2
SVar:Token15M:DB$ Token | TokenScript$ c_4_4_dragon_flying | SpellDescription$ Create a 4/4 gold Dragon creature token with flying.
SVar:SetLife16M:DB$ SetLife | ValidTgts$ Player | TgtPrompt$ Select target player | LifeAmount$ 10 | SpellDescription$ Target player's life total becomes 10.
SVar:Destroy17M:DB$ Destroy | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select a nonland permanent | SpellDescription$ Destroy target nonland permanent.
SVar:Return18M:DB$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | GainControl$ True | TgtPrompt$ Select target permanent in a graveyard | ValidTgts$ Permanent | SpellDescription$ Return target permanent from a graveyard to the battlefield under your control.
SVar:Token19M:DB$ Token | TokenAmount$ 2 | TokenScript$ g_3_3_beast | SpellDescription$ Create two 3/3 green Beast creature tokens.
SVar:Draw20M:DB$ Draw | NumCards$ 4 | SubAbility$ DBDiscard20M | SpellDescription$ Draw four cards, then discard two cards.
SVar:DBDiscard20M:DB$ Discard | Defined$ You | NumCards$ 2 | Mode$ TgtChoose
A:AB$ GenericChoice | Cost$ SubCounter<6/LOYALTY> | AtRandom$ Urza | ShowChoice$ Description | Choices$ DealDamage1U,Effect2U,DestroyAll3U,Token4U,LifeGain5U,Damage6U,Effect7U,Effect8U,Token9U,Shuffle10U,Destroy11U,Effect12U,Effect13U,ControlPlayer14U,ExileLibrary15U,Token16U,Raise17U,LifeDraw18U,FlipTurns19U | Planeswalker$ True | Ultimate$ True | ShowChoice$ Description | StackDescription$ SpellDescription | SpellDescription$ Head to AskUrza.com and click -6.
SVar:DealDamage1U:DB$ DealDamage | ValidTgts$ Player,Planeswalker | SubAbility$ DBDiscard1U | SpellDescription$ NICKNAME deals 7 damage to target player or planeswalker. That player or that planeswalker's controller discards seven cards, then sacrifices seven permanents.
SVar:DBDiscard1U:DB$ Discard | Defined$ TargetedOrController | NumCards$ 7 | Mode$ TgtChoose | SubAbility$ DBSac1U
SVar:DBSac1U:DB$Sacrifice | Defined$ TargetedOrController | SacValid$ Permanent | Amount$ 7
SVar:Effect2U:DB$ Effect | Name$ Emblem - Urza, Academy Headmaster (2U) | ReplacementEffects$ RPreventDamage | Stackable$ False | Duration$ Permanent | AILogic$ Always | SpellDescription$ You get an emblem with "If a source would deal damage to you or a planeswalker you control, prevent all but 1 of that damage."
SVar:RPreventDamage:Event$ DamageDone | ValidTarget$ You,Planeswalker.YouCtrl | ReplaceWith$ PreventDmg | PreventionEffect$ True | Description$ If a source would deal damage to you or a planeswalker you control, prevent all but 1 of that damage.
SVar:PreventDmg:DB$ ReplaceDamage | Amount$ ShieldAmount
SVar:ShieldAmount:ReplaceCount$DamageAmount/Minus.1
SVar:DestroyAll3U:DB$ DestroyAll | ValidTgts$ Player | TgtPrompt$ Select target player | ValidCards$ Land | SpellDescription$ Destroy all lands target player controls.
SVar:Token4U:DB$ Token | TokenAmount$ X4U | TokenScript$ w_2_2_cat | SpellDescription$ Create X 2/2 white Cat creature tokens, where X is your life total.
SVar:X4U:Count$YourLifeTotal
SVar:LifeGain5U:DB$ GainLife | LifeAmount$ 100 | SpellDescription$ You gain 100 life.
SVar:Damage6U:DB$ DealDamage | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select a player or planeswalker | NumDmg$ 10 | SubAbility$ DmgAll6U | DamageMap$ True | SpellDescription$ NICKNAME deals 10 damage to target player or planeswalker and each creature that player or that planeswalker's controller controls.
SVar:DmgAll6U:DB$ DamageAll | NumDmg$ 10 | ValidCards$ Creature.ControlledBy TargetedOrController | SubAbility$ DBDamageResolve6U
SVar:DBDamageResolve6U:DB$ DamageResolve
SVar:Effect7U:DB$ Effect | Name$ Emblem - Urza, Academy Headmaster (7U) | StaticAbilities$ ST7U | Stackable$ False | Duration$ Permanent | AILogic$ Always | SpellDescription$ You get an emblem with "Creatures you control have double strike, trample, hexproof and haste."
SVar:ST7U:Mode$ Continuous | EffectZone$ Command | Affected$ Creature.YouCtrl | AffectedZone$ Battlefield | AddKeyword$ Double Strike & Trample & Hexproof & Haste | Description$ Creatures you control have double strike, trample, hexproof and haste.
SVar:Effect8U:DB$ Effect | Name$ Emblem - Urza, Academy Headmaster (8U) | StaticAbilities$ STIndestructible8U | Stackable$ False | Duration$ Permanent | AILogic$ Always | SpellDescription$ You get an emblem with "Artifacts, creatures, enchantments, and lands you control have indestructible."
SVar:STIndestructible8U:Mode$ Continuous | EffectZone$ Command | Affected$ Artifact.YouCtrl,Creature.YouCtrl,Enchantment.YouCtrl,Land.YouCtrl | AffectedZone$ Battlefield | AddKeyword$ Indestructible | Description$ Artifacts, creatures, enchantments, and lands you control are indestructible.
SVar:Token9U:DB$ Token | TokenAmount$ Lands | TokenScript$ g_6_6_wurm | SpellDescription$ Create a 6/6 green Wurm creature token for each land you control.
SVar:Lands:Count$Valid Land.YouCtrl
SVar:Shuffle10U:DB$ ChangeZoneAll | ChangeType$ Card | Origin$ Hand,Graveyard | Destination$ Library | Shuffle$ True | SubAbility$ DBDraw10U | UseAllOriginZones$ True | SpellDescription$ Each player shuffles their hand and graveyard into their library. You draw seven cards.
SVar:DBDraw10U:DB$ Draw | Defined$ You | NumCards$ 7
SVar:Destroy11U:DB$ Destroy | ValidTgts$ Creature,Planeswalker.Other | TargetMin$ 0 | TargetMax$ 3 | TgtPrompt$ Select up to three target creatures and/or other planeswalkers | RememberTargets$ True | SubAbility$ DBChangeZoneAll11U | SpellDescription$ Destroy up to three target creatures and/or other planeswalkers. Return each card put into a graveyard this way to the battlefield under your control.
SVar:DBChangeZoneAll11U:DB$ ChangeZoneAll | ChangeType$ Card.IsRemembered | Origin$ Graveyard | Destination$ Battlefield | GainControl$ True | SubAbility$ DBCleanup
SVar:Effect12U:DB$ Effect | Name$ Emblem - Urza, Academy Headmaster (12U) | Triggers$ TrigSpellCast12U | Duration$ Permanent | AILogic$ Always | SpellDescription$ You get an emblem with "Whenever you cast a spell, exile target permanent."
SVar:TrigSpellCast12U:Mode$ SpellCast | ValidActivatingPlayer$ You | Execute$ EffSpellCast12U | TriggerDescription$ Whenever you cast a spell, exile target permanent.
SVar:EffSpellCast12U:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Permanent
SVar:Effect13U:DB$ Effect | Name$ Emblem - Urza, Academy Headmaster (13U) | Triggers$ TrigFight13U | Duration$ Permanent | AILogic$ Always | SubAbility$ DBToken13U | SpellDescription$ You get an emblem with "Whenever a creature enters the battlefield under your control, you may have it fight target creature." Then create three 8/8 blue Octopus creature tokens.
SVar:TrigFight13U:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Creature.YouCtrl | Execute$ DBFight13U | OptionalDecider$ You | TriggerZones$ Command | TriggerDescription$ Whenever a creature enters the battlefield under your control, you may have it fight target creature.
SVar:DBFight13U:DB$ Fight | Defined$ TriggeredCardLKICopy | ValidTgts$ Creature | TgtPrompt$ Choose target creature
SVar:DBToken13U:DB$ Token | TokenAmount$ 3 | TokenScript$ u_8_8_octopus
SVar:ControlPlayer14U:DB$ ControlPlayer | ValidTgts$ Player | TgtPrompt$ Select target player | SpellDescription$ You control target player during that player's next turn.
SVar:ExileLibrary15U:DB$ ChangeZoneAll | Origin$ Library | Destination$ Exile | ValidTgts$ Player | TgtPrompt$ Select target player | SubAbility$ DBChangeZone15U | Planeswalker$ True | Ultimate$ True | SpellDescription$ Exile all cards from target player's library, then that player shuffles their hand into their library.
SVar:DBChangeZone15U:DB$ ChangeZoneAll | Origin$ Hand | Destination$ Library | Defined$ Targeted | ChangeType$ Card | Shuffle$ True
SVar:Token16U:DB$ Token | TokenAmount$ 3 | TokenScript$ b_1_1_assassin_lose_con | SpellDescription$ Create three 1/1 black Assassin creature tokens with "Whenever this creature deals combat damage to a player, that player loses the game."
SVar:Raise17U:DB$ ChangeZoneAll | ChangeType$ Creature | Origin$ Graveyard | Destination$ Battlefield | GainControl$ True | SpellDescription$ Put all creature cards in all graveyards onto the battlefield under your control.
SVar:LifeDraw18U:DB$ GainLife | LifeAmount$ Lands | SubAbility$ DBDraw18U | SpellDescription$ You gain X life and draw X cards, where X is the number of lands you control.
SVar:DBDraw18U:DB$ Draw | NumCards$ Lands
SVar:FlipTurns19U:DB$ FlipACoin | Amount$ 5 | NoCall$ True | HeadsSubAbility$ DBAddTurn19U | StackDescription$ SpellDescription | SpellDescription$ Flip 5 coins. Take an extra turn after this one for each coin that comes up heads.
SVar:DBAddTurn19U:DB$ AddTurn | Defined$ You | NumTurns$ 1
SVar:LifeDrawPut20U:DB$ GainLife | LifeAmount$ 7 | SubAbility$ DBDraw20U | SpellDescription$ You gain 7 life, draw seven cards, then put up to seven permanent cards from your hand onto the battlefield.
SVar:DBDraw20U:DB$ Draw | NumCards$ 7 | SubAbility$ DBChangeZone20U
SVar:DBChangeZone20U:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | ChangeType$ Permanent | ChangeNum$ 7
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True
DeckHas:Ability$Counters & Ability$Token & Ability$LifeGain & Ability$Discard
Oracle:[+1]: Head to AskUrza.com and click +1.\n[-1]: Head to AskUrza.com and click -1.\n[-6]: Head to AskUrza.com and click -6.

View File

@@ -244,7 +244,7 @@ Eternal Warrior|LEG
Eureka|LEG
Evil Eye of Orms-by-Gore|LEG
Fallen Angel|LEG
#Falling Star|LEG
Falling Star|LEG
Feint|LEG
Field of Dreams|LEG
Fire Sprites|LEG
@@ -504,7 +504,7 @@ Camouflage|LEB
Castle|LEB
Celestial Prism|LEB
Channel|LEB
#Chaos Orb|LEB
Chaos Orb|LEB
Chaoslace|LEB
Circle of Protection: Black|LEB
Circle of Protection: Blue|LEB

View File

@@ -0,0 +1,14 @@
[metadata]
Code=VOC
Date=2021-11-19
Name=Innistrad: Crimson Vow Commander
Type=Commander
ScryfallCode=VOC
[cards]
1 M Millicent, Restless Revenant @
2 M Strefan, Maurer Progenitor @
32 M Wedding Ring @
39 M Millicent, Restless Revenant @
40 M Strefan, Maurer Progenitor @
70 M Wedding Ring @

View File

@@ -0,0 +1,90 @@
[metadata]
Code=VOW
Date=2021-11-19
Name=Innistrad: Crimson Vow
Code2=VOW
MciCode=vow
Type=Expansion
ScryfallCode=VOW
[cards]
5 R By Invitation Only @
10 C Drogskol Infantry @
15 C Gryff Rider @
34 M Savior of Ollenbock @
36 R Sigarda's Summons @
38 R Thalia, Guardian of Thraben @
45 R Wedding Announcement @
60 U Geistlight Snare @
71 R Overcharged Amalgam @
103 R Demonic Bargain @
112 U Fell Stinger @
114 C Gluttonous Guest @
129 C Rot-Tide Gargantua @
131 M Sorin the Mirthless @
137 R Voldaren Bloodcaster @
154 R Dominating Vampire @
184 C Weary Prisoner @
185 C Apprentice Sharpshooter @
197 R Dig Up @
208 C Massive Might @
235 R Dorothea, Vengeful Victim @
238 R Grolnok, the Omnivore @
245 M Olivia, Crimson Bride @
260 C Wedding Invitation @
261 R Deathcap Glade @
262 R Dreamroot Cascade @
264 R Shattered Sanctum @
265 R Stormcarved Coast @
266 R Sundown Pass @
267 R Voldaren Estate @
268 L Plains @
269 L Plains @
270 L Island @
271 L Island @
272 L Swamp @
273 L Swamp @
274 L Mountain @
275 L Mountain @
276 L Forest @
277 L Forest @
278 M Sorin the Mirthless @
281 R Deathcap Glade @
282 R Dreamroot Cascade @
283 R Shattered Sanctum @
284 R Stormcarved Coast @
285 R Sundown Pass @
292 C Gluttonous Guest @
297 M Sorin the Mirthless @
298 R Voldaren Bloodcaster @
305 R Dominating Vampire @
315 M Olivia, Crimson Bride @
318 R Thalia, Guardian of Thraben @
322 R Dorothea, Vengeful Victim @
324 R Grolnok, the Omnivore @
330 M Savior of Ollenbock @
331 R Thalia, Guardian of Thraben @
337 M Sorin the Mirthless @
338 R Voldaren Bloodcaster @
343 M Olivia, Crimson Bride @
346 R By Invitation Only @
352 M Savior of Ollenbock @
353 R Sigarda's Summons @
355 R Wedding Announcement @
363 R Overcharged Amalgam @
368 R Demonic Bargain @
387 R Dig Up @
397 R Voldaren Estate @
398 L Plains @
399 L Island @
400 L Swamp @
401 L Mountain @
402 L Forest @
403 R Voldaren Estate @
404 R Sigarda's Summons @
405 U Geistlight Snare @
406 U Fell Stinger @
407 R Dominating Vampire @
[tokens]
c_a_blood_draw

View File

@@ -1938,6 +1938,13 @@ lblTails=Zahl
lblCallCoinFlip=Kopf oder Zahl
lblWin=Gewonnen
lblLose=Verloren
#FlipOntoBattlefieldEffect.java
lblChooseDesiredLocation=Wähle eine Karte als Mittelpunkt der gewünschten Landezone.
lblDidNotFlipOver=Die Karte hat sich NICHT überschlagen.
lblFlippedOver=Die Karte überschlug sich {0} mal.
lblDidNotLandOnCards=Die Karte landete auf keiner Karte.
lblLandedOnOneCard=Die Karte landete auf {0}.
lblLandedOnTwoCards=Die Karte landete auf {0} und {1}.
#InvestigateEffect.java
lblWouldYouLikeInvestigate=Möchtest du Nachforschungen anstellen?
#LifeSetEffect.java

View File

@@ -1939,6 +1939,13 @@ lblTails=tails
lblCallCoinFlip=Call coin flip
lblWin=win
lblLose=lose
#FlipOntoBattlefieldEffect.java
lblChooseDesiredLocation=Choose a card to represent the center of the desired card landing location.
lblDidNotFlipOver=The card did not flip over.
lblFlippedOver=The card flipped over {0} time(s).
lblDidNotLandOnCards=The card did not land on any cards.
lblLandedOnOneCard=The card landed on {0}.
lblLandedOnTwoCards=The card landed on {0} and {1}.
#InvestigateEffect.java
lblWouldYouLikeInvestigate=Do you want to investigate?
#LifeSetEffect.java

View File

@@ -1937,6 +1937,13 @@ lblTails=cruz
lblCallCoinFlip=Llamar al lanzamiento de la moneda
lblWin=gana
lblLose=pierde
#FlipOntoBattlefieldEffect.java
lblChooseDesiredLocation=Choose a card to represent the center of the desired card landing location.
lblDidNotFlipOver=The card did not flip over.
lblFlippedOver=The card flipped over {0} time(s).
lblDidNotLandOnCards=The card did not land on any cards.
lblLandedOnOneCard=The card landed on {0}.
lblLandedOnTwoCards=The card landed on {0} and {1}.
#InvestigateEffect.java
lblWouldYouLikeInvestigate=¿Quieres investigar?
#LifeSetEffect.java

View File

@@ -1936,6 +1936,13 @@ lblTails=croce
lblCallCoinFlip=Scegli testa o croce
lblWin=hai vinto
lblLose=hai perso
#FlipOntoBattlefieldEffect.java
lblChooseDesiredLocation=Choose a card to represent the center of the desired card landing location.
lblDidNotFlipOver=The card did not flip over.
lblFlippedOver=The card flipped over {0} time(s).
lblDidNotLandOnCards=The card did not land on any cards.
lblLandedOnOneCard=The card landed on {0}.
lblLandedOnTwoCards=The card landed on {0} and {1}.
#InvestigateEffect.java
lblWouldYouLikeInvestigate=Do you want to investigate?
#LifeSetEffect.java

View File

@@ -1936,6 +1936,13 @@ lblTails=裏
lblCallCoinFlip=コイン投げを予想
lblWin=勝ち
lblLose=負け
#FlipOntoBattlefieldEffect.java
lblChooseDesiredLocation=Choose a card to represent the center of the desired card landing location.
lblDidNotFlipOver=The card did not flip over.
lblFlippedOver=The card flipped over {0} time(s).
lblDidNotLandOnCards=The card did not land on any cards.
lblLandedOnOneCard=The card landed on {0}.
lblLandedOnTwoCards=The card landed on {0} and {1}.
#InvestigateEffect.java
lblWouldYouLikeInvestigate=Do you want to investigate?
#LifeSetEffect.java

View File

@@ -1940,6 +1940,13 @@ lblTails=背面
lblCallCoinFlip=掷骰子
lblWin=
lblLose=
#FlipOntoBattlefieldEffect.java
lblChooseDesiredLocation=Choose a card to represent the center of the desired card landing location.
lblDidNotFlipOver=The card did not flip over.
lblFlippedOver=The card flipped over {0} time(s).
lblDidNotLandOnCards=The card did not land on any cards.
lblLandedOnOneCard=The card landed on {0}.
lblLandedOnTwoCards=The card landed on {0} and {1}.
#InvestigateEffect.java
lblWouldYouLikeInvestigate=你想要探查吗?
#LifeSetEffect.java

View File

@@ -374,6 +374,7 @@ Tezzeret
Tibalt
Tyvar
Ugin
Urza
Venser
Vivien
Vraska

View File

@@ -2130,3 +2130,11 @@
2021-10-11 Legacy Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/legacy/2021-10-11-legacy-challenge.zip
2021-10-12 Legacy Preliminary (4 decks) | https://downloads.cardforge.org/decks/archive/legacy/2021-10-12-legacy-preliminary.zip
2021-10-16 Legacy League (49 decks) | https://downloads.cardforge.org/decks/archive/legacy/2021-10-16-legacy-league.zip
2021-10-18 Legacy Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/legacy/2021-10-18-legacy-challenge.zip
2021-10-20 Legacy Preliminary (4 decks) | https://downloads.cardforge.org/decks/archive/legacy/2021-10-20-legacy-preliminary.zip
2021-10-22 Legacy Preliminary (5 decks) | https://downloads.cardforge.org/decks/archive/legacy/2021-10-22-legacy-preliminary.zip
2021-10-23 Legacy League (49 decks) | https://downloads.cardforge.org/decks/archive/legacy/2021-10-23-legacy-league.zip
2021-10-23 Legacy Preliminary (3 decks) | https://downloads.cardforge.org/decks/archive/legacy/2021-10-23-legacy-preliminary.zip
2021-10-24 Legacy Premier (16 decks) | https://downloads.cardforge.org/decks/archive/legacy/2021-10-24-legacy-premier.zip
2021-10-25 Legacy Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/legacy/2021-10-25-legacy-challenge.zip
2021-10-26 Legacy Preliminary (3 decks) | https://downloads.cardforge.org/decks/archive/legacy/2021-10-26-legacy-preliminary.zip

View File

@@ -2798,3 +2798,17 @@
2021-10-16 Modern Preliminary (6 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-16-modern-preliminary.zip
2021-10-16 Modern Premier (16 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-16-modern-premier.zip
2021-10-17 Modern Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-17-modern-challenge.zip
2021-10-18 Modern Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-18-modern-challenge.zip
2021-10-18 Modern Premier (16 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-18-modern-premier.zip
2021-10-19 Modern League (56 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-19-modern-league.zip
2021-10-19 Modern Preliminary (7 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-19-modern-preliminary.zip
2021-10-20 Modern Preliminary (5 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-20-modern-preliminary.zip
2021-10-21 Modern Preliminary (10 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-21-modern-preliminary.zip
2021-10-22 Modern League (56 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-22-modern-league.zip
2021-10-22 Modern Preliminary (5 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-22-modern-preliminary.zip
2021-10-23 Modern Preliminary (7 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-23-modern-preliminary.zip
2021-10-24 Modern Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-24-modern-challenge.zip
2021-10-25 Modern Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-25-modern-challenge.zip
2021-10-25 Modern Premier (16 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-25-modern-premier.zip
2021-10-26 Modern League (65 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-26-modern-league.zip
2021-10-26 Modern Preliminary (7 decks) | https://downloads.cardforge.org/decks/archive/modern/2021-10-26-modern-preliminary.zip

View File

@@ -1815,3 +1815,8 @@
2021-10-11 Pauper Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/pauper/2021-10-11-pauper-challenge.zip
2021-10-13 Pauper League (30 decks) | https://downloads.cardforge.org/decks/archive/pauper/2021-10-13-pauper-league.zip
2021-10-17 Pauper Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/pauper/2021-10-17-pauper-challenge.zip
2021-10-18 Pauper Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/pauper/2021-10-18-pauper-challenge.zip
2021-10-20 Pauper League (25 decks) | https://downloads.cardforge.org/decks/archive/pauper/2021-10-20-pauper-league.zip
2021-10-24 Pauper Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/pauper/2021-10-24-pauper-challenge.zip
2021-10-25 Pauper Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/pauper/2021-10-25-pauper-challenge.zip
Pauper League (20 decks) | https://downloads.cardforge.org/decks/archive/pauper/pauper-league.zip

View File

@@ -755,3 +755,10 @@
2021-10-11 Pioneer League (18 decks) | https://downloads.cardforge.org/decks/archive/pioneer/2021-10-11-pioneer-league.zip
2021-10-14 Pioneer League (15 decks) | https://downloads.cardforge.org/decks/archive/pioneer/2021-10-14-pioneer-league.zip
2021-10-17 Pioneer Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/pioneer/2021-10-17-pioneer-challenge.zip
2021-10-18 Pioneer Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/pioneer/2021-10-18-pioneer-challenge.zip
2021-10-18 Pioneer League (14 decks) | https://downloads.cardforge.org/decks/archive/pioneer/2021-10-18-pioneer-league.zip
2021-10-21 Pioneer League (17 decks) | https://downloads.cardforge.org/decks/archive/pioneer/2021-10-21-pioneer-league.zip
2021-10-23 Pioneer Preliminary (6 decks) | https://downloads.cardforge.org/decks/archive/pioneer/2021-10-23-pioneer-preliminary.zip
2021-10-24 Pioneer Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/pioneer/2021-10-24-pioneer-challenge.zip
2021-10-25 Pioneer Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/pioneer/2021-10-25-pioneer-challenge.zip
2021-10-25 Pioneer League (19 decks) | https://downloads.cardforge.org/decks/archive/pioneer/2021-10-25-pioneer-league.zip

View File

@@ -2515,3 +2515,10 @@
2021-10-14 Standard League (12 decks) | https://downloads.cardforge.org/decks/archive/standard/2021-10-14-standard-league.zip
2021-10-15 Standard Preliminary (4 decks) | https://downloads.cardforge.org/decks/archive/standard/2021-10-15-standard-preliminary.zip
2021-10-17 Standard Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/standard/2021-10-17-standard-challenge.zip
2021-10-18 Standard Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/standard/2021-10-18-standard-challenge.zip
2021-10-18 Standard League (15 decks) | https://downloads.cardforge.org/decks/archive/standard/2021-10-18-standard-league.zip
2021-10-20 Standard Preliminary (3 decks) | https://downloads.cardforge.org/decks/archive/standard/2021-10-20-standard-preliminary.zip
2021-10-21 Standard League (5 decks) | https://downloads.cardforge.org/decks/archive/standard/2021-10-21-standard-league.zip
2021-10-24 Standard Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/standard/2021-10-24-standard-challenge.zip
2021-10-25 Standard Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/standard/2021-10-25-standard-challenge.zip
2021-10-25 Standard League (8 decks) | https://downloads.cardforge.org/decks/archive/standard/2021-10-25-standard-league.zip

View File

@@ -1535,3 +1535,8 @@
2021-10-11 Vintage Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/vintage/2021-10-11-vintage-challenge.zip
2021-10-17 Vintage Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/vintage/2021-10-17-vintage-challenge.zip
2021-10-17 Vintage League (12 decks) | https://downloads.cardforge.org/decks/archive/vintage/2021-10-17-vintage-league.zip
2021-10-18 Vintage Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/vintage/2021-10-18-vintage-challenge.zip
2021-10-23 Vintage Preliminary (4 decks) | https://downloads.cardforge.org/decks/archive/vintage/2021-10-23-vintage-preliminary.zip
2021-10-24 Vintage Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/vintage/2021-10-24-vintage-challenge.zip
2021-10-24 Vintage League (9 decks) | https://downloads.cardforge.org/decks/archive/vintage/2021-10-24-vintage-league.zip
2021-10-25 Vintage Challenge (32 decks) | https://downloads.cardforge.org/decks/archive/vintage/2021-10-25-vintage-challenge.zip

View File

@@ -13,7 +13,6 @@ import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostShard;
import forge.game.card.Card;
import forge.game.card.CardCollectionView;
import forge.game.card.CardUtil;
import forge.game.mana.ManaCostBeingPaid;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -74,7 +73,7 @@ public final class InputSelectCardsForConvokeOrImprovise extends InputSelectMany
if (improvise) {
chosenColor = ManaCostShard.COLORLESS.getColorMask();
} else {
ColorSet colors = CardUtil.getColors(card);
ColorSet colors = card.determineColor();
if (colors.isMulticolor()) {
//if card is multicolor, strip out any colors which can't be paid towards remaining cost
colors = ColorSet.fromMask(colors.getColor() & remainingCost.getUnpaidColors());

View File

@@ -30,8 +30,7 @@ public class FThreads {
public static void invokeInEdtNowOrLater(final Runnable proc) {
if (isGuiThread()) {
GuiBase.getInterface().invokeInEdtNow(proc);
}
else {
} else {
GuiBase.getInterface().invokeInEdtLater(proc);
}
}

View File

@@ -80,8 +80,7 @@ public final class ItemManagerModel<T extends InventoryItem> {
if (data.count(item0) > 0) {
if (isInfinite()) {
data.removeAll(item0);
}
else {
} else {
data.remove(item0, qty);
}
isListInSync = false;