mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 19:28:01 +00:00
Merge branch 'master' into questMode_wildOpponents
# Conflicts: # forge-gui/res/languages/en-US.properties
This commit is contained in:
@@ -300,4 +300,10 @@ public class TextUtil {
|
|||||||
sb.append( str, idx1, str.length() );
|
sb.append( str, idx1, str.length() );
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
//Convert to Mana String
|
||||||
|
public static String toManaString(String ManaProduced){
|
||||||
|
if (ManaProduced == "mana"|| ManaProduced.contains("Combo")|| ManaProduced.contains("Any"))
|
||||||
|
return "mana";//fix manamorphose stack description and probably others..
|
||||||
|
return "{"+TextUtil.fastReplace(ManaProduced," ","}{")+"}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,7 +121,14 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
}
|
}
|
||||||
final String destination = sa.getParam("Destination");
|
final String destination = sa.getParam("Destination");
|
||||||
|
|
||||||
final String type = sa.hasParam("ChangeType") ? sa.getParam("ChangeType") : "Card";
|
String type = "card";
|
||||||
|
if (sa.hasParam("ChangeTypeDesc")) {
|
||||||
|
type = sa.getParam("ChangeTypeDesc");
|
||||||
|
}
|
||||||
|
else if (sa.hasParam("ChangeType")) {
|
||||||
|
type = sa.getParam("ChangeType");
|
||||||
|
}
|
||||||
|
|
||||||
final int num = sa.hasParam("ChangeNum") ? AbilityUtils.calculateAmount(host,
|
final int num = sa.hasParam("ChangeNum") ? AbilityUtils.calculateAmount(host,
|
||||||
sa.getParam("ChangeNum"), sa) : 1;
|
sa.getParam("ChangeNum"), sa) : 1;
|
||||||
|
|
||||||
@@ -140,8 +147,17 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
} else if (origin.equals("Library")) {
|
} else if (origin.equals("Library")) {
|
||||||
sb.append(chooserNames);
|
sb.append(chooserNames);
|
||||||
sb.append(" search").append(choosers.size() > 1 ? " " : "es ");
|
sb.append(" search").append(choosers.size() > 1 ? " " : "es ");
|
||||||
sb.append(fetchPlayer);
|
sb.append(fetchPlayer).append(fetchPlayer.equals(chooserNames) ? "'s " : " ");
|
||||||
sb.append("'s library for ").append(num).append(" ").append(type).append(" and ");
|
sb.append("library for ").append(num).append(" ");
|
||||||
|
sb.append(type).append(num > 1 ? "s" : "");
|
||||||
|
if (!sa.hasParam("NoReveal")) {
|
||||||
|
if (choosers.size() == 1) {
|
||||||
|
sb.append(num > 1 ? ", reveals those cards," : ", reveals that card,");
|
||||||
|
} else {
|
||||||
|
sb.append(num > 1 ? ", reveal those cards," : ", reveal that card,");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.append(" and ");
|
||||||
|
|
||||||
if (destination.equals("Exile")) {
|
if (destination.equals("Exile")) {
|
||||||
if (num == 1) {
|
if (num == 1) {
|
||||||
@@ -169,10 +185,19 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
|
|
||||||
}
|
}
|
||||||
if (destination.equals("Hand")) {
|
if (destination.equals("Hand")) {
|
||||||
|
if (num == 1) {
|
||||||
sb.append("into its owner's hand.");
|
sb.append("into its owner's hand.");
|
||||||
|
} else {
|
||||||
|
sb.append("into their owner's hand.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (destination.equals("Graveyard")) {
|
if (destination.equals("Graveyard")) {
|
||||||
sb.append("into its owners's graveyard.");
|
if (num == 1) {
|
||||||
|
sb.append("into its owner's graveyard.");
|
||||||
|
} else {
|
||||||
|
sb.append("into their owner's graveyard.");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.append(" Then shuffle that library.");
|
sb.append(" Then shuffle that library.");
|
||||||
@@ -297,7 +322,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
|
|||||||
if (ZoneType.Graveyard.equals(origin)) {
|
if (ZoneType.Graveyard.equals(origin)) {
|
||||||
sb.append(fromGraveyard);
|
sb.append(fromGraveyard);
|
||||||
}
|
}
|
||||||
sb.append(" to").append(pronoun).append("owners hand.");
|
sb.append(" to").append(pronoun).append("owner's hand.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (destination.equals(ZoneType.Library)) {
|
if (destination.equals(ZoneType.Library)) {
|
||||||
|
|||||||
@@ -49,6 +49,13 @@ public class CountersPutEffect extends SpellAbilityEffect {
|
|||||||
final boolean dividedAsYouChoose = spellAbility.hasParam("DividedAsYouChoose");
|
final boolean dividedAsYouChoose = spellAbility.hasParam("DividedAsYouChoose");
|
||||||
|
|
||||||
final int amount = AbilityUtils.calculateAmount(card, spellAbility.getParamOrDefault("CounterNum", "1"), spellAbility);
|
final int amount = AbilityUtils.calculateAmount(card, spellAbility.getParamOrDefault("CounterNum", "1"), spellAbility);
|
||||||
|
//skip the StringBuilder if no targets are chosen ("up to" scenario)
|
||||||
|
if (spellAbility.usesTargeting()) {
|
||||||
|
final List<Card> targetCards = SpellAbilityEffect.getTargetCards(spellAbility);
|
||||||
|
if (targetCards.size() == 0) {
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (spellAbility.hasParam("Bolster")) {
|
if (spellAbility.hasParam("Bolster")) {
|
||||||
stringBuilder.append("Bolster ").append(amount);
|
stringBuilder.append("Bolster ").append(amount);
|
||||||
return stringBuilder.toString();
|
return stringBuilder.toString();
|
||||||
|
|||||||
@@ -6,26 +6,24 @@ import forge.game.ability.SpellAbilityEffect;
|
|||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
import forge.game.spellability.TargetRestrictions;
|
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
|
|
||||||
public class GoadEffect extends SpellAbilityEffect {
|
public class GoadEffect extends SpellAbilityEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resolve(SpellAbility sa) {
|
public void resolve(SpellAbility sa) {
|
||||||
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
|
||||||
final Player player = sa.getActivatingPlayer();
|
final Player player = sa.getActivatingPlayer();
|
||||||
final Game game = player.getGame();
|
final Game game = player.getGame();
|
||||||
final long timestamp = game.getNextTimestamp();
|
final long timestamp = game.getNextTimestamp();
|
||||||
|
|
||||||
for (final Card tgtC : getTargetCards(sa)) {
|
for (final Card tgtC : getDefinedCardsOrTargeted(sa)) {
|
||||||
// only pump things in PumpZone
|
// only pump things in PumpZone
|
||||||
if (!game.getCardsIn(ZoneType.Battlefield).contains(tgtC)) {
|
if (!game.getCardsIn(ZoneType.Battlefield).contains(tgtC)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if pump is a target, make sure we can still target now
|
// if pump is a target, make sure we can still target now
|
||||||
if ((tgt != null) && !tgtC.canBeTargetedBy(sa)) {
|
if (sa.usesTargeting() && !sa.getTargetRestrictions().canTgtPlayer() && !tgtC.canBeTargetedBy(sa)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static forge.util.TextUtil.toManaString;
|
||||||
|
|
||||||
public class ManaEffect extends SpellAbilityEffect {
|
public class ManaEffect extends SpellAbilityEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -252,7 +254,7 @@ public class ManaEffect extends SpellAbilityEffect {
|
|||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
String mana = !sa.hasParam("Amount") || StringUtils.isNumeric(sa.getParam("Amount"))
|
String mana = !sa.hasParam("Amount") || StringUtils.isNumeric(sa.getParam("Amount"))
|
||||||
? GameActionUtil.generatedMana(sa) : "mana";
|
? GameActionUtil.generatedMana(sa) : "mana";
|
||||||
sb.append("Add ").append(mana).append(".");
|
sb.append("Add ").append(toManaString(mana)).append(".");
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,9 +105,7 @@ public class MillEffect extends SpellAbilityEffect {
|
|||||||
if (numCards != 1) {
|
if (numCards != 1) {
|
||||||
sb.append("s");
|
sb.append("s");
|
||||||
}
|
}
|
||||||
final String millPosition = sa.hasParam("FromBottom") ? "bottom" : "top";
|
sb.append(".");
|
||||||
sb.append(" from the ").append(millPosition).append(" of their library.");
|
|
||||||
|
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6174,6 +6174,12 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
source.forceTurnFaceUp();
|
source.forceTurnFaceUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the modal state is not copied with lki, need to copy it extra
|
||||||
|
if (!source.hasState(CardStateName.Modal)) {
|
||||||
|
source.addAlternateState(CardStateName.Modal, false);
|
||||||
|
source.getState(CardStateName.Modal).copyFrom(this.getState(CardStateName.Modal), true);
|
||||||
|
}
|
||||||
|
|
||||||
source.setSplitStateToPlayAbility(la);
|
source.setSplitStateToPlayAbility(la);
|
||||||
|
|
||||||
if (la.canPlay(source)) {
|
if (la.canPlay(source)) {
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import forge.game.keyword.Keyword;
|
|||||||
import forge.game.keyword.KeywordInterface;
|
import forge.game.keyword.KeywordInterface;
|
||||||
import forge.game.phase.PhaseHandler;
|
import forge.game.phase.PhaseHandler;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
|
import forge.game.player.PlayerCollection;
|
||||||
import forge.game.replacement.ReplacementEffect;
|
import forge.game.replacement.ReplacementEffect;
|
||||||
import forge.game.replacement.ReplacementHandler;
|
import forge.game.replacement.ReplacementHandler;
|
||||||
import forge.game.replacement.ReplacementLayer;
|
import forge.game.replacement.ReplacementLayer;
|
||||||
@@ -80,10 +81,9 @@ public class CardFactoryUtil {
|
|||||||
public static SpellAbility buildBasicLandAbility(final CardState state, byte color) {
|
public static SpellAbility buildBasicLandAbility(final CardState state, byte color) {
|
||||||
String strcolor = MagicColor.toShortString(color);
|
String strcolor = MagicColor.toShortString(color);
|
||||||
String abString = "AB$ Mana | Cost$ T | Produced$ " + strcolor +
|
String abString = "AB$ Mana | Cost$ T | Produced$ " + strcolor +
|
||||||
" | SpellDescription$ Add {" + strcolor + "}.";
|
" | Secondary$ True | SpellDescription$ Add {" + strcolor + "}.";
|
||||||
SpellAbility sa = AbilityFactory.getAbility(abString, state);
|
SpellAbility sa = AbilityFactory.getAbility(abString, state);
|
||||||
sa.setIntrinsic(true); // always intristic
|
sa.setIntrinsic(true); // always intristic
|
||||||
sa.setBasicLandAbility(true); // to exclude it from other suspress effects
|
|
||||||
return sa;
|
return sa;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1294,6 +1294,9 @@ public class CardFactoryUtil {
|
|||||||
if (sq[0].contains("CardNumColors")) {
|
if (sq[0].contains("CardNumColors")) {
|
||||||
return doXMath(CardUtil.getColors(c).countColors(), m, c);
|
return doXMath(CardUtil.getColors(c).countColors(), m, c);
|
||||||
}
|
}
|
||||||
|
if (sq[0].contains("CardNumAttacksThisTurn")) {
|
||||||
|
return doXMath(c.getDamageHistory().getCreatureAttacksThisTurn(), m, c);
|
||||||
|
}
|
||||||
if (sq[0].contains("ChosenNumber")) {
|
if (sq[0].contains("ChosenNumber")) {
|
||||||
Integer i = c.getChosenNumber();
|
Integer i = c.getChosenNumber();
|
||||||
return doXMath(i == null ? 0 : i, m, c);
|
return doXMath(i == null ? 0 : i, m, c);
|
||||||
@@ -1336,6 +1339,13 @@ public class CardFactoryUtil {
|
|||||||
return doXMath(getCardTypesFromList(game.getCardsIn(ZoneType.smartValueOf(sq[1]))), m, c);
|
return doXMath(getCardTypesFromList(game.getCardsIn(ZoneType.smartValueOf(sq[1]))), m, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sq[0].contains("OppTypesInGrave")) {
|
||||||
|
final PlayerCollection opponents = cc.getOpponents();
|
||||||
|
CardCollection oppCards = new CardCollection();
|
||||||
|
oppCards.addAll(opponents.getCardsIn(ZoneType.Graveyard));
|
||||||
|
return doXMath(getCardTypesFromList(oppCards), m, c);
|
||||||
|
}
|
||||||
|
|
||||||
if (sq[0].contains("BushidoPoint")) {
|
if (sq[0].contains("BushidoPoint")) {
|
||||||
return doXMath(c.getKeywordMagnitude(Keyword.BUSHIDO), m, c);
|
return doXMath(c.getKeywordMagnitude(Keyword.BUSHIDO), m, c);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -456,6 +456,19 @@ public final class CardPredicates {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final Predicate<Card> castSA(final Predicate<SpellAbility> predSA) {
|
||||||
|
return new Predicate<Card>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(final Card c)
|
||||||
|
{
|
||||||
|
if (c.getCastSA() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return predSA.apply(c.getCastSA());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public static class Presets {
|
public static class Presets {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -173,23 +173,12 @@ public final class CardUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static List<Card> getThisTurnCast(final String valid, final Card src) {
|
public static List<Card> getThisTurnCast(final String valid, final Card src) {
|
||||||
List<Card> res = Lists.newArrayList();
|
return CardLists.getValidCardsAsList(src.getGame().getStack().getSpellsCastThisTurn(), valid, src.getController(), src);
|
||||||
final Game game = src.getGame();
|
|
||||||
res.addAll(game.getStack().getSpellsCastThisTurn());
|
|
||||||
|
|
||||||
res = CardLists.getValidCardsAsList(res, valid, src.getController(), src);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Card> getLastTurnCast(final String valid, final Card src) {
|
public static List<Card> getLastTurnCast(final String valid, final Card src) {
|
||||||
List<Card> res = Lists.newArrayList();
|
return CardLists.getValidCardsAsList(src.getGame().getStack().getSpellsCastLastTurn(), valid, src.getController(), src);
|
||||||
final Game game = src.getGame();
|
|
||||||
res.addAll(game.getStack().getSpellsCastLastTurn());
|
|
||||||
|
|
||||||
res = CardLists.getValidCardsAsList(res, valid, src.getController(), src);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import forge.game.mana.ManaCostBeingPaid;
|
|||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.spellability.AbilityActivated;
|
import forge.game.spellability.AbilityActivated;
|
||||||
import forge.game.spellability.SpellAbility;
|
import forge.game.spellability.SpellAbility;
|
||||||
|
import forge.game.spellability.SpellAbilityPredicates;
|
||||||
import forge.game.spellability.TargetChoices;
|
import forge.game.spellability.TargetChoices;
|
||||||
import forge.game.staticability.StaticAbility;
|
import forge.game.staticability.StaticAbility;
|
||||||
import forge.game.zone.Zone;
|
import forge.game.zone.Zone;
|
||||||
@@ -423,6 +424,7 @@ public class CostAdjustment {
|
|||||||
final Player controller = hostCard.getController();
|
final Player controller = hostCard.getController();
|
||||||
final Player activator = sa.getActivatingPlayer();
|
final Player activator = sa.getActivatingPlayer();
|
||||||
final Card card = sa.getHostCard();
|
final Card card = sa.getHostCard();
|
||||||
|
final Game game = hostCard.getGame();
|
||||||
|
|
||||||
if (st.hasParam("ValidCard")
|
if (st.hasParam("ValidCard")
|
||||||
&& !card.isValid(st.getParam("ValidCard").split(","), controller, hostCard, sa)) {
|
&& !card.isValid(st.getParam("ValidCard").split(","), controller, hostCard, sa)) {
|
||||||
@@ -452,7 +454,19 @@ public class CostAdjustment {
|
|||||||
if (activator == null ) {
|
if (activator == null ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
List<Card> list = CardUtil.getThisTurnCast(st.getParam("ValidCard"), hostCard);
|
List<Card> list;
|
||||||
|
if (st.hasParam("ValidCard")) {
|
||||||
|
list = CardUtil.getThisTurnCast(st.getParam("ValidCard"), hostCard);
|
||||||
|
} else {
|
||||||
|
list = game.getStack().getSpellsCastThisTurn();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st.hasParam("ValidSpell")) {
|
||||||
|
list = CardLists.filterAsList(list, CardPredicates.castSA(
|
||||||
|
SpellAbilityPredicates.isValid(st.getParam("ValidSpell").split(","), controller, hostCard, sa))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (CardLists.filterControlledBy(list, activator).size() > 0) {
|
if (CardLists.filterControlledBy(list, activator).size() > 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
package forge.game.player;
|
package forge.game.player;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.tuple.ImmutablePair;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.ListMultimap;
|
import com.google.common.collect.ListMultimap;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
import forge.LobbyPlayer;
|
import forge.LobbyPlayer;
|
||||||
import forge.card.ColorSet;
|
import forge.card.ColorSet;
|
||||||
import forge.card.ICardFace;
|
import forge.card.ICardFace;
|
||||||
@@ -14,7 +22,11 @@ import forge.game.GameEntity;
|
|||||||
import forge.game.GameObject;
|
import forge.game.GameObject;
|
||||||
import forge.game.GameOutcome.AnteResult;
|
import forge.game.GameOutcome.AnteResult;
|
||||||
import forge.game.GameType;
|
import forge.game.GameType;
|
||||||
import forge.game.card.*;
|
import forge.game.card.Card;
|
||||||
|
import forge.game.card.CardCollection;
|
||||||
|
import forge.game.card.CardCollectionView;
|
||||||
|
import forge.game.card.CardView;
|
||||||
|
import forge.game.card.CounterType;
|
||||||
import forge.game.combat.Combat;
|
import forge.game.combat.Combat;
|
||||||
import forge.game.cost.Cost;
|
import forge.game.cost.Cost;
|
||||||
import forge.game.cost.CostPart;
|
import forge.game.cost.CostPart;
|
||||||
@@ -23,18 +35,17 @@ import forge.game.keyword.KeywordInterface;
|
|||||||
import forge.game.mana.Mana;
|
import forge.game.mana.Mana;
|
||||||
import forge.game.mana.ManaConversionMatrix;
|
import forge.game.mana.ManaConversionMatrix;
|
||||||
import forge.game.replacement.ReplacementEffect;
|
import forge.game.replacement.ReplacementEffect;
|
||||||
import forge.game.spellability.*;
|
import forge.game.spellability.AbilitySub;
|
||||||
|
import forge.game.spellability.OptionalCostValue;
|
||||||
|
import forge.game.spellability.SpellAbility;
|
||||||
|
import forge.game.spellability.SpellAbilityStackInstance;
|
||||||
|
import forge.game.spellability.TargetChoices;
|
||||||
import forge.game.trigger.WrappedAbility;
|
import forge.game.trigger.WrappedAbility;
|
||||||
|
import forge.game.zone.Zone;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.item.PaperCard;
|
import forge.item.PaperCard;
|
||||||
import forge.util.ITriggerEvent;
|
import forge.util.ITriggerEvent;
|
||||||
import forge.util.collect.FCollectionView;
|
import forge.util.collect.FCollectionView;
|
||||||
import org.apache.commons.lang3.tuple.ImmutablePair;
|
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A prototype for player controller class
|
* A prototype for player controller class
|
||||||
@@ -278,4 +289,7 @@ public abstract class PlayerController {
|
|||||||
|
|
||||||
public abstract CardCollection chooseCardsForEffectMultiple(Map<String, CardCollection> validMap,
|
public abstract CardCollection chooseCardsForEffectMultiple(Map<String, CardCollection> validMap,
|
||||||
SpellAbility sa, String title, boolean isOptional);
|
SpellAbility sa, String title, boolean isOptional);
|
||||||
|
|
||||||
|
public void handleLandPlayed(Card land, Zone zone) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,8 +113,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
private boolean blessing = false;
|
private boolean blessing = false;
|
||||||
private Integer chapter = null;
|
private Integer chapter = null;
|
||||||
|
|
||||||
private boolean basicLandAbility = false;
|
|
||||||
|
|
||||||
private CardStateName stateName = null;
|
private CardStateName stateName = null;
|
||||||
|
|
||||||
private int totalManaSpent = 0;
|
private int totalManaSpent = 0;
|
||||||
@@ -789,13 +787,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
return this.isAlternativeCost(AlternativeCost.Flashback);
|
return this.isAlternativeCost(AlternativeCost.Flashback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBasicLandAbility(final boolean basicLandAbility0) {
|
|
||||||
basicLandAbility = basicLandAbility0;
|
|
||||||
}
|
|
||||||
public boolean isBasicLandAbility() {
|
|
||||||
return basicLandAbility && isIntrinsic();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the aftermath
|
* @return the aftermath
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import com.google.common.base.Predicate;
|
|||||||
|
|
||||||
import forge.game.CardTraitPredicates;
|
import forge.game.CardTraitPredicates;
|
||||||
import forge.game.ability.ApiType;
|
import forge.game.ability.ApiType;
|
||||||
|
import forge.game.card.Card;
|
||||||
|
import forge.game.player.Player;
|
||||||
|
|
||||||
public final class SpellAbilityPredicates extends CardTraitPredicates {
|
public final class SpellAbilityPredicates extends CardTraitPredicates {
|
||||||
public static final Predicate<SpellAbility> isApi(final ApiType type) {
|
public static final Predicate<SpellAbility> isApi(final ApiType type) {
|
||||||
@@ -59,4 +61,13 @@ public final class SpellAbilityPredicates extends CardTraitPredicates {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final Predicate<SpellAbility> isValid(String[] restrictions, Player sourceController, Card source, SpellAbility spellAbility) {
|
||||||
|
return new Predicate<SpellAbility>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(final SpellAbility sa) {
|
||||||
|
return sa.isValid(restrictions, sourceController, source, spellAbility);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ import forge.util.Localizer;
|
|||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static forge.util.TextUtil.toManaString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* Trigger_TapsForMana class.
|
* Trigger_TapsForMana class.
|
||||||
@@ -99,6 +101,9 @@ public class TriggerTapsForMana extends Trigger {
|
|||||||
if (!this.getHostCard().hasChosenColor() || !produced.contains(MagicColor.toShortString(this.getHostCard().getChosenColor()))) {
|
if (!this.getHostCard().hasChosenColor() || !produced.contains(MagicColor.toShortString(this.getHostCard().getChosenColor()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!produced.contains(MagicColor.toShortString(this.getParam("Produced")))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +121,7 @@ public class TriggerTapsForMana extends Trigger {
|
|||||||
public String getImportantStackObjects(SpellAbility sa) {
|
public String getImportantStackObjects(SpellAbility sa) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(Localizer.getInstance().getMessage("lblTappedForMana")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card));
|
sb.append(Localizer.getInstance().getMessage("lblTappedForMana")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card));
|
||||||
sb.append(Localizer.getInstance().getMessage("lblProduced")).append(": ").append(sa.getTriggeringObject(AbilityKey.Produced));
|
sb.append(Localizer.getInstance().getMessage("lblProduced")).append(": ").append(toManaString(sa.getTriggeringObject(AbilityKey.Produced).toString()));
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ import forge.game.card.CardUtil;
|
|||||||
import forge.game.event.EventValueChangeType;
|
import forge.game.event.EventValueChangeType;
|
||||||
import forge.game.event.GameEventZone;
|
import forge.game.event.GameEventZone;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
|
import forge.game.player.PlayerCollection;
|
||||||
|
import forge.game.player.PlayerController;
|
||||||
import forge.util.CollectionSuppliers;
|
import forge.util.CollectionSuppliers;
|
||||||
import forge.util.MyRandom;
|
import forge.util.MyRandom;
|
||||||
import forge.util.maps.EnumMapOfLists;
|
import forge.util.maps.EnumMapOfLists;
|
||||||
@@ -123,7 +125,21 @@ public class Zone implements java.io.Serializable, Iterable<Card> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
onChanged();
|
onChanged();
|
||||||
|
|
||||||
|
if(zoneType == ZoneType.Battlefield && c.isLand()) {
|
||||||
|
PlayerCollection playerCollection = game.getPlayers();
|
||||||
|
int numPlayers = playerCollection.size();
|
||||||
|
for (int i = 0; i < numPlayers; i++) {
|
||||||
|
Player player = playerCollection.get(i);
|
||||||
|
if(!player.isAI()) {
|
||||||
|
PlayerController playerControllerHuman = player.getController();
|
||||||
|
playerControllerHuman.handleLandPlayed(c,this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
game.fireEvent(new GameEventZone(zoneType, getPlayer(), EventValueChangeType.Added, c));
|
game.fireEvent(new GameEventZone(zoneType, getPlayer(), EventValueChangeType.Added, c));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean contains(final Card c) {
|
public final boolean contains(final Card c) {
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ public enum CSubmenuPreferences implements ICDoc {
|
|||||||
initializeMulliganRuleComboBox();
|
initializeMulliganRuleComboBox();
|
||||||
initializeAiProfilesComboBox();
|
initializeAiProfilesComboBox();
|
||||||
initializeStackAdditionsComboBox();
|
initializeStackAdditionsComboBox();
|
||||||
|
initializeLandPlayedComboBox();
|
||||||
initializeColorIdentityCombobox();
|
initializeColorIdentityCombobox();
|
||||||
initializeAutoYieldModeComboBox();
|
initializeAutoYieldModeComboBox();
|
||||||
initializeCounterDisplayTypeComboBox();
|
initializeCounterDisplayTypeComboBox();
|
||||||
@@ -448,6 +449,17 @@ public enum CSubmenuPreferences implements ICDoc {
|
|||||||
panel.setComboBox(comboBox, selectedItem);
|
panel.setComboBox(comboBox, selectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void initializeLandPlayedComboBox() {
|
||||||
|
final String[] elems = {ForgeConstants.LAND_PLAYED_NOTIFICATION_NEVER, ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS,
|
||||||
|
ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS_FOR_NONBASIC_LANDS, ForgeConstants.LAND_PLAYED_NOTIFICATION_AI,
|
||||||
|
ForgeConstants.LAND_PLAYED_NOTIFICATION_AI_FOR_NONBASIC_LANDS};
|
||||||
|
final FPref userSetting = FPref.UI_LAND_PLAYED_NOTIFICATION_POLICY;
|
||||||
|
final FComboBoxPanel<String> panel = this.view.getCbpLandPlayedComboBoxPanel();
|
||||||
|
final FComboBox<String> comboBox = createComboBox(elems, userSetting);
|
||||||
|
final String selectedItem = this.prefs.getPref(userSetting);
|
||||||
|
panel.setComboBox(comboBox, selectedItem);
|
||||||
|
}
|
||||||
|
|
||||||
private void initializeColorIdentityCombobox() {
|
private void initializeColorIdentityCombobox() {
|
||||||
final String[] elems = {ForgeConstants.DISP_CURRENT_COLORS_NEVER, ForgeConstants.DISP_CURRENT_COLORS_CHANGED,
|
final String[] elems = {ForgeConstants.DISP_CURRENT_COLORS_NEVER, ForgeConstants.DISP_CURRENT_COLORS_CHANGED,
|
||||||
ForgeConstants.DISP_CURRENT_COLORS_MULTICOLOR, ForgeConstants.DISP_CURRENT_COLORS_MULTI_OR_CHANGED,
|
ForgeConstants.DISP_CURRENT_COLORS_MULTICOLOR, ForgeConstants.DISP_CURRENT_COLORS_MULTI_OR_CHANGED,
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
|||||||
private final FComboBoxPanel<String> cbpMulliganRule = new FComboBoxPanel<>(localizer.getMessage("cbpMulliganRule")+":");
|
private final FComboBoxPanel<String> cbpMulliganRule = new FComboBoxPanel<>(localizer.getMessage("cbpMulliganRule")+":");
|
||||||
private final FComboBoxPanel<String> cbpAiProfiles = new FComboBoxPanel<>(localizer.getMessage("cbpAiProfiles")+":");
|
private final FComboBoxPanel<String> cbpAiProfiles = new FComboBoxPanel<>(localizer.getMessage("cbpAiProfiles")+":");
|
||||||
private final FComboBoxPanel<String> cbpStackAdditions = new FComboBoxPanel<>(localizer.getMessage("cbpStackAdditions")+":");
|
private final FComboBoxPanel<String> cbpStackAdditions = new FComboBoxPanel<>(localizer.getMessage("cbpStackAdditions")+":");
|
||||||
|
private final FComboBoxPanel<String> cbpLandPlayed = new FComboBoxPanel<>(localizer.getMessage("cbpLandPlayed")+":");
|
||||||
private final FComboBoxPanel<String> cbpDisplayCurrentCardColors = new FComboBoxPanel<>(localizer.getMessage("cbpDisplayCurrentCardColors")+":");
|
private final FComboBoxPanel<String> cbpDisplayCurrentCardColors = new FComboBoxPanel<>(localizer.getMessage("cbpDisplayCurrentCardColors")+":");
|
||||||
private final FComboBoxPanel<String> cbpAutoYieldMode = new FComboBoxPanel<>(localizer.getMessage("cbpAutoYieldMode")+":");
|
private final FComboBoxPanel<String> cbpAutoYieldMode = new FComboBoxPanel<>(localizer.getMessage("cbpAutoYieldMode")+":");
|
||||||
private final FComboBoxPanel<String> cbpCounterDisplayType = new FComboBoxPanel<>(localizer.getMessage("cbpCounterDisplayType")+":");
|
private final FComboBoxPanel<String> cbpCounterDisplayType = new FComboBoxPanel<>(localizer.getMessage("cbpCounterDisplayType")+":");
|
||||||
@@ -206,6 +207,9 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
|||||||
pnlPrefs.add(cbpStackAdditions, comboBoxConstraints);
|
pnlPrefs.add(cbpStackAdditions, comboBoxConstraints);
|
||||||
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlpStackAdditions")), descriptionConstraints);
|
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlpStackAdditions")), descriptionConstraints);
|
||||||
|
|
||||||
|
pnlPrefs.add(cbpLandPlayed, comboBoxConstraints);
|
||||||
|
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlpLandPlayed")), descriptionConstraints);
|
||||||
|
|
||||||
pnlPrefs.add(cbEnforceDeckLegality, titleConstraints);
|
pnlPrefs.add(cbEnforceDeckLegality, titleConstraints);
|
||||||
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlEnforceDeckLegality")), descriptionConstraints);
|
pnlPrefs.add(new NoteLabel(localizer.getMessage("nlEnforceDeckLegality")), descriptionConstraints);
|
||||||
|
|
||||||
@@ -685,6 +689,10 @@ public enum VSubmenuPreferences implements IVSubmenu<CSubmenuPreferences> {
|
|||||||
return cbpStackAdditions;
|
return cbpStackAdditions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FComboBoxPanel<String> getCbpLandPlayedComboBoxPanel() {
|
||||||
|
return cbpLandPlayed;
|
||||||
|
}
|
||||||
|
|
||||||
public FComboBoxPanel<GameLogEntryType> getGameLogVerbosityComboBoxPanel() {
|
public FComboBoxPanel<GameLogEntryType> getGameLogVerbosityComboBoxPanel() {
|
||||||
return cbpGameLogEntryType;
|
return cbpGameLogEntryType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,40 @@
|
|||||||
*/
|
*/
|
||||||
package forge.screens.match;
|
package forge.screens.match;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import javax.swing.JMenu;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
|
import javax.swing.KeyStroke;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.event.PopupMenuEvent;
|
||||||
|
import javax.swing.event.PopupMenuListener;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import forge.*;
|
|
||||||
|
import forge.FThreads;
|
||||||
|
import forge.GuiBase;
|
||||||
|
import forge.ImageCache;
|
||||||
|
import forge.LobbyPlayer;
|
||||||
|
import forge.Singletons;
|
||||||
|
import forge.StaticData;
|
||||||
import forge.assets.FSkinProp;
|
import forge.assets.FSkinProp;
|
||||||
import forge.card.CardStateName;
|
import forge.card.CardStateName;
|
||||||
import forge.control.KeyboardShortcuts;
|
import forge.control.KeyboardShortcuts;
|
||||||
@@ -42,11 +71,28 @@ import forge.game.keyword.Keyword;
|
|||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.player.DelayedReveal;
|
import forge.game.player.DelayedReveal;
|
||||||
import forge.game.player.IHasIcon;
|
import forge.game.player.IHasIcon;
|
||||||
|
import forge.game.player.Player;
|
||||||
import forge.game.player.PlayerView;
|
import forge.game.player.PlayerView;
|
||||||
import forge.game.spellability.*;
|
import forge.game.spellability.SpellAbility;
|
||||||
|
import forge.game.spellability.SpellAbilityStackInstance;
|
||||||
|
import forge.game.spellability.SpellAbilityView;
|
||||||
|
import forge.game.spellability.StackItemView;
|
||||||
|
import forge.game.spellability.TargetChoices;
|
||||||
|
import forge.game.zone.Zone;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.gui.*;
|
import forge.gui.FNetOverlay;
|
||||||
import forge.gui.framework.*;
|
import forge.gui.GuiChoose;
|
||||||
|
import forge.gui.GuiDialog;
|
||||||
|
import forge.gui.GuiUtils;
|
||||||
|
import forge.gui.SOverlayUtils;
|
||||||
|
import forge.gui.framework.DragCell;
|
||||||
|
import forge.gui.framework.EDocID;
|
||||||
|
import forge.gui.framework.FScreen;
|
||||||
|
import forge.gui.framework.ICDoc;
|
||||||
|
import forge.gui.framework.IVDoc;
|
||||||
|
import forge.gui.framework.SDisplayUtil;
|
||||||
|
import forge.gui.framework.SLayoutIO;
|
||||||
|
import forge.gui.framework.VEmptyDoc;
|
||||||
import forge.item.InventoryItem;
|
import forge.item.InventoryItem;
|
||||||
import forge.item.PaperCard;
|
import forge.item.PaperCard;
|
||||||
import forge.match.AbstractGuiGame;
|
import forge.match.AbstractGuiGame;
|
||||||
@@ -57,12 +103,23 @@ import forge.player.PlayerZoneUpdates;
|
|||||||
import forge.properties.ForgeConstants;
|
import forge.properties.ForgeConstants;
|
||||||
import forge.properties.ForgePreferences;
|
import forge.properties.ForgePreferences;
|
||||||
import forge.properties.ForgePreferences.FPref;
|
import forge.properties.ForgePreferences.FPref;
|
||||||
import forge.screens.match.controllers.*;
|
import forge.screens.match.controllers.CAntes;
|
||||||
|
import forge.screens.match.controllers.CCombat;
|
||||||
|
import forge.screens.match.controllers.CDetailPicture;
|
||||||
|
import forge.screens.match.controllers.CDev;
|
||||||
|
import forge.screens.match.controllers.CDock;
|
||||||
|
import forge.screens.match.controllers.CLog;
|
||||||
|
import forge.screens.match.controllers.CPrompt;
|
||||||
|
import forge.screens.match.controllers.CStack;
|
||||||
import forge.screens.match.menus.CMatchUIMenus;
|
import forge.screens.match.menus.CMatchUIMenus;
|
||||||
import forge.screens.match.views.VField;
|
import forge.screens.match.views.VField;
|
||||||
import forge.screens.match.views.VHand;
|
import forge.screens.match.views.VHand;
|
||||||
import forge.toolbox.*;
|
import forge.toolbox.FButton;
|
||||||
|
import forge.toolbox.FLabel;
|
||||||
|
import forge.toolbox.FOptionPane;
|
||||||
|
import forge.toolbox.FSkin;
|
||||||
import forge.toolbox.FSkin.SkinImage;
|
import forge.toolbox.FSkin.SkinImage;
|
||||||
|
import forge.toolbox.FTextArea;
|
||||||
import forge.toolbox.imaging.FImagePanel;
|
import forge.toolbox.imaging.FImagePanel;
|
||||||
import forge.toolbox.imaging.FImagePanel.AutoSizeImageMode;
|
import forge.toolbox.imaging.FImagePanel.AutoSizeImageMode;
|
||||||
import forge.toolbox.imaging.FImageUtil;
|
import forge.toolbox.imaging.FImageUtil;
|
||||||
@@ -79,17 +136,6 @@ import forge.view.arcane.CardPanel;
|
|||||||
import forge.view.arcane.FloatingZone;
|
import forge.view.arcane.FloatingZone;
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.PopupMenuEvent;
|
|
||||||
import javax.swing.event.PopupMenuListener;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.KeyEvent;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs instance of match UI controller, used as a single point of
|
* Constructs instance of match UI controller, used as a single point of
|
||||||
* top-level control for child UIs. Tasks targeting the view of individual
|
* top-level control for child UIs. Tasks targeting the view of individual
|
||||||
@@ -1392,4 +1438,57 @@ public final class CMatchUI
|
|||||||
nextNotifiableStackIndex--;
|
nextNotifiableStackIndex--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleLandPlayed(Card land, Zone zone) {
|
||||||
|
Runnable createPopupThread = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
createLandPopupPanel(land,zone);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
GuiBase.getInterface().invokeInEdtAndWait(createPopupThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createLandPopupPanel(Card land, Zone zone) {
|
||||||
|
|
||||||
|
String landPlayedNotificationPolicy = FModel.getPreferences().getPref(FPref.UI_LAND_PLAYED_NOTIFICATION_POLICY);
|
||||||
|
Player cardController = land.getController();
|
||||||
|
boolean isAi = cardController.isAI();
|
||||||
|
if(ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS.equals(landPlayedNotificationPolicy)
|
||||||
|
|| (ForgeConstants.LAND_PLAYED_NOTIFICATION_AI.equals(landPlayedNotificationPolicy) && (isAi))
|
||||||
|
|| (ForgeConstants.LAND_PLAYED_NOTIFICATION_ALWAYS_FOR_NONBASIC_LANDS.equals(landPlayedNotificationPolicy) && !land.isBasicLand())
|
||||||
|
|| (ForgeConstants.LAND_PLAYED_NOTIFICATION_AI_FOR_NONBASIC_LANDS.equals(landPlayedNotificationPolicy) && !land.isBasicLand()) && (isAi)) {
|
||||||
|
String title = "Forge";
|
||||||
|
List<String> options = ImmutableList.of(Localizer.getInstance().getMessage("lblOK"));
|
||||||
|
|
||||||
|
MigLayout migLayout = new MigLayout("insets 15, left, gap 30, fill");
|
||||||
|
JPanel mainPanel = new JPanel(migLayout);
|
||||||
|
final Dimension parentSize = JOptionPane.getRootFrame().getSize();
|
||||||
|
Dimension maxSize = new Dimension(1400, parentSize.height - 100);
|
||||||
|
mainPanel.setMaximumSize(maxSize);
|
||||||
|
mainPanel.setOpaque(false);
|
||||||
|
|
||||||
|
int rotation = getRotation(land.getView());
|
||||||
|
|
||||||
|
FImagePanel imagePanel = new FImagePanel();
|
||||||
|
BufferedImage bufferedImage = FImageUtil.getImage(land.getCurrentState().getView());
|
||||||
|
imagePanel.setImage(bufferedImage, rotation, AutoSizeImageMode.SOURCE);
|
||||||
|
int imageWidth = 433;
|
||||||
|
int imageHeight = 600;
|
||||||
|
Dimension imagePanelDimension = new Dimension(imageWidth,imageHeight);
|
||||||
|
imagePanel.setMinimumSize(imagePanelDimension);
|
||||||
|
|
||||||
|
mainPanel.add(imagePanel, "cell 0 0, spany 3");
|
||||||
|
|
||||||
|
String msg = cardController.toString() + " puts " + land.toString() + " into play into " + zone.toString() + ".";
|
||||||
|
|
||||||
|
final FTextArea prompt1 = new FTextArea(msg);
|
||||||
|
prompt1.setFont(FSkin.getFont(21));
|
||||||
|
prompt1.setAutoSize(true);
|
||||||
|
prompt1.setMinimumSize(new Dimension(475,200));
|
||||||
|
mainPanel.add(prompt1, "cell 1 0, aligny top");
|
||||||
|
|
||||||
|
FOptionPane.showOptionDialog(null, title, null, mainPanel, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class VCombat implements IVDoc<CCombat> {
|
|||||||
|
|
||||||
// Fields used with interface IVDoc
|
// Fields used with interface IVDoc
|
||||||
private DragCell parentCell;
|
private DragCell parentCell;
|
||||||
private final DragTab tab = new DragTab(Localizer.getInstance().getMessage("lblCombat"));
|
private final DragTab tab = new DragTab(Localizer.getInstance().getMessage("lblCombatTab"));
|
||||||
|
|
||||||
private final SkinnedTextArea tar = new SkinnedTextArea();
|
private final SkinnedTextArea tar = new SkinnedTextArea();
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ public class VCombat implements IVDoc<CCombat> {
|
|||||||
// No need to update this unless it's showing
|
// No need to update this unless it's showing
|
||||||
if (!this.equals(parentCell.getSelected())) { return; }
|
if (!this.equals(parentCell.getSelected())) { return; }
|
||||||
|
|
||||||
tab.setText(cntAttackers > 0 ? (Localizer.getInstance().getMessage("lblCombat") + " : " + cntAttackers) : Localizer.getInstance().getMessage("lblCombat"));
|
tab.setText(cntAttackers > 0 ? (Localizer.getInstance().getMessage("lblCombatTab") + " : " + cntAttackers) : Localizer.getInstance().getMessage("lblCombatTab"));
|
||||||
tar.setText(desc);
|
tar.setText(desc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ import forge.properties.ForgeConstants;
|
|||||||
import forge.util.ImageUtil;
|
import forge.util.ImageUtil;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -77,6 +79,7 @@ public class ImageCache {
|
|||||||
public static final Texture defaultImage;
|
public static final Texture defaultImage;
|
||||||
public static FImage BlackBorder = FSkinImage.IMG_BORDER_BLACK;
|
public static FImage BlackBorder = FSkinImage.IMG_BORDER_BLACK;
|
||||||
public static FImage WhiteBorder = FSkinImage.IMG_BORDER_WHITE;
|
public static FImage WhiteBorder = FSkinImage.IMG_BORDER_WHITE;
|
||||||
|
private static final Map<Texture, Boolean> Borders = new HashMap<>();
|
||||||
|
|
||||||
private static boolean imageLoaded, delayLoadRequested;
|
private static boolean imageLoaded, delayLoadRequested;
|
||||||
public static void allowSingleLoad() {
|
public static void allowSingleLoad() {
|
||||||
@@ -99,6 +102,7 @@ public class ImageCache {
|
|||||||
cache.invalidateAll();
|
cache.invalidateAll();
|
||||||
cache.cleanUp();
|
cache.cleanUp();
|
||||||
missingIconKeys.clear();
|
missingIconKeys.clear();
|
||||||
|
Borders.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void disposeTexture(){
|
public static void disposeTexture(){
|
||||||
@@ -181,6 +185,8 @@ public class ImageCache {
|
|||||||
if (useDefaultIfNotFound) {
|
if (useDefaultIfNotFound) {
|
||||||
image = defaultImage;
|
image = defaultImage;
|
||||||
cache.put(imageKey, defaultImage);
|
cache.put(imageKey, defaultImage);
|
||||||
|
if (Borders.get(image) == null)
|
||||||
|
Borders.put(image, false); //black border
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return image;
|
return image;
|
||||||
@@ -192,8 +198,8 @@ public class ImageCache {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static TextureRegion croppedBorderImage(Texture image, boolean fullborder) {
|
public static TextureRegion croppedBorderImage(Texture image) {
|
||||||
if (!fullborder)
|
if (!image.toString().contains(".fullborder."))
|
||||||
return new TextureRegion(image);
|
return new TextureRegion(image);
|
||||||
float rscale = 0.96f;
|
float rscale = 0.96f;
|
||||||
int rw = Math.round(image.getWidth()*rscale);
|
int rw = Math.round(image.getWidth()*rscale);
|
||||||
@@ -202,25 +208,6 @@ public class ImageCache {
|
|||||||
int ry = Math.round((image.getHeight() - rh)/2f)-2;
|
int ry = Math.round((image.getHeight() - rh)/2f)-2;
|
||||||
return new TextureRegion(image, rx, ry, rw, rh);
|
return new TextureRegion(image, rx, ry, rw, rh);
|
||||||
}
|
}
|
||||||
public static boolean isWhiteBordered(IPaperCard c) {
|
|
||||||
if (c == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
CardEdition ed = FModel.getMagicDb().getEditions().get(c.getEdition());
|
|
||||||
if (ed != null && ed.isWhiteBorder())
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public static boolean isWhiteBordered(CardView c) {
|
|
||||||
if (c == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
CardView.CardStateView state = c.getCurrentState();
|
|
||||||
CardEdition ed = FModel.getMagicDb().getEditions().get(state.getSetCode());
|
|
||||||
if (ed != null && ed.isWhiteBorder() && state.getFoilIndex() == 0)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public static Color borderColor(IPaperCard c) {
|
public static Color borderColor(IPaperCard c) {
|
||||||
if (c == null)
|
if (c == null)
|
||||||
return Color.valueOf("#171717");
|
return Color.valueOf("#171717");
|
||||||
@@ -250,38 +237,24 @@ public class ImageCache {
|
|||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
public static boolean isExtendedArt(CardView c) {
|
public static boolean isBorderlessCardArt(Texture t) {
|
||||||
if (c == null)
|
return ImageLoader.isBorderless(t);
|
||||||
return false;
|
|
||||||
|
|
||||||
CardView.CardStateView state = c.getCurrentState();
|
|
||||||
if (state.getSetCode().contains("MPS_"))
|
|
||||||
return true;
|
|
||||||
if (state.getSetCode().equalsIgnoreCase("UST"))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
public static boolean isExtendedArt(IPaperCard c) {
|
public static void updateBorders(Texture t, boolean val){
|
||||||
if (c == null)
|
Borders.put(t, val);
|
||||||
return false;
|
|
||||||
|
|
||||||
if (c.getEdition().contains("MPS_"))
|
|
||||||
return true;
|
|
||||||
if (c.getEdition().equalsIgnoreCase("UST"))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
public static FImage getBorderImage(CardView c, boolean canshow) {
|
public static FImage getBorder(Texture t) {
|
||||||
|
if (Borders.get(t) == null)
|
||||||
|
return BlackBorder;
|
||||||
|
return Borders.get(t) ? WhiteBorder : BlackBorder;
|
||||||
|
}
|
||||||
|
public static FImage getBorderImage(Texture t, boolean canshow) {
|
||||||
if (!canshow)
|
if (!canshow)
|
||||||
return BlackBorder;
|
return BlackBorder;
|
||||||
if (isWhiteBordered(c))
|
return getBorder(t);
|
||||||
return WhiteBorder;
|
|
||||||
return BlackBorder;
|
|
||||||
}
|
}
|
||||||
public static FImage getBorderImage(IPaperCard c) {
|
public static FImage getBorderImage(Texture t) {
|
||||||
if (isWhiteBordered(c))
|
return getBorder(t);
|
||||||
return WhiteBorder;
|
|
||||||
return BlackBorder;
|
|
||||||
}
|
}
|
||||||
public static Color getTint(CardView c) {
|
public static Color getTint(CardView c) {
|
||||||
if (c == null)
|
if (c == null)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package forge.assets;
|
package forge.assets;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import com.badlogic.gdx.files.FileHandle;
|
import com.badlogic.gdx.files.FileHandle;
|
||||||
import com.badlogic.gdx.graphics.Color;
|
import com.badlogic.gdx.graphics.Color;
|
||||||
@@ -13,24 +14,155 @@ import forge.FThreads;
|
|||||||
|
|
||||||
import forge.Forge;
|
import forge.Forge;
|
||||||
import forge.ImageKeys;
|
import forge.ImageKeys;
|
||||||
|
import forge.util.TextUtil;
|
||||||
|
|
||||||
|
import static forge.assets.ImageCache.croppedBorderImage;
|
||||||
|
|
||||||
final class ImageLoader extends CacheLoader<String, Texture> {
|
final class ImageLoader extends CacheLoader<String, Texture> {
|
||||||
|
private static ArrayList<String> borderlessCardlistKey = new ArrayList<String>() {
|
||||||
|
{//TODO: load the values from text list instead of hardcoded
|
||||||
|
add("2XM/Academy Ruins2.fullborder");
|
||||||
|
add("2XM/Atraxa, Praetors' Voice2.fullborder");
|
||||||
|
add("2XM/Avacyn, Angel of Hope2.fullborder");
|
||||||
|
add("2XM/Batterskull2.fullborder");
|
||||||
|
add("2XM/Blightsteel Colossus2.fullborder");
|
||||||
|
add("2XM/Blood Moon2.fullborder");
|
||||||
|
add("2XM/Brainstorm2.fullborder");
|
||||||
|
add("2XM/Chrome Mox2.fullborder");
|
||||||
|
add("2XM/Council's Judgment2.fullborder");
|
||||||
|
add("2XM/Crop Rotation2.fullborder");
|
||||||
|
add("2XM/Cyclonic Rift2.fullborder");
|
||||||
|
add("2XM/Dark Confidant2.fullborder");
|
||||||
|
add("2XM/Doubling Season2.fullborder");
|
||||||
|
add("2XM/Expedition Map2.fullborder");
|
||||||
|
add("2XM/Exploration2.fullborder");
|
||||||
|
add("2XM/Fatal Push2.fullborder");
|
||||||
|
add("2XM/Force of Will2.fullborder");
|
||||||
|
add("2XM/Goblin Guide2.fullborder");
|
||||||
|
add("2XM/Jace, the Mind Sculptor2.fullborder");
|
||||||
|
add("2XM/Kaalia of the Vast2.fullborder");
|
||||||
|
add("2XM/Karn Liberated2.fullborder");
|
||||||
|
add("2XM/Lightning Greaves2.fullborder");
|
||||||
|
add("2XM/Mana Crypt2.fullborder");
|
||||||
|
add("2XM/Meddling Mage2.fullborder");
|
||||||
|
add("2XM/Mox Opal2.fullborder");
|
||||||
|
add("2XM/Noble Hierarch2.fullborder");
|
||||||
|
add("2XM/Phyrexian Metamorph2.fullborder");
|
||||||
|
add("2XM/Sneak Attack2.fullborder");
|
||||||
|
add("2XM/Stoneforge Mystic2.fullborder");
|
||||||
|
add("2XM/Sword of Body and Mind2.fullborder");
|
||||||
|
add("2XM/Sword of Feast and Famine2.fullborder");
|
||||||
|
add("2XM/Sword of Fire and Ice2.fullborder");
|
||||||
|
add("2XM/Sword of Light and Shadow2.fullborder");
|
||||||
|
add("2XM/Sword of War and Peace2.fullborder");
|
||||||
|
add("2XM/Thoughtseize2.fullborder");
|
||||||
|
add("2XM/Toxic Deluge2.fullborder");
|
||||||
|
add("2XM/Urza's Mine2.fullborder");
|
||||||
|
add("2XM/Urza's Power Plant2.fullborder");
|
||||||
|
add("2XM/Urza's Tower2.fullborder");
|
||||||
|
add("2XM/Wurmcoil Engine2.fullborder");
|
||||||
|
add("ELD/Garruk, Cursed Huntsman2.fullborder");
|
||||||
|
add("ELD/Oko, Thief of Crowns2.fullborder");
|
||||||
|
add("ELD/The Royal Scions2.fullborder");
|
||||||
|
add("IKO/Brokkos, Apex of Forever2.fullborder");
|
||||||
|
add("IKO/Brokkos, Apex of Forever3.fullborder");
|
||||||
|
add("IKO/Crystalline Giant3.fullborder");
|
||||||
|
add("IKO/Cubwarden2.fullborder");
|
||||||
|
add("IKO/Dirge Bat2.fullborder");
|
||||||
|
add("IKO/Dirge Bat3.fullborder");
|
||||||
|
add("IKO/Everquill Phoenix2.fullborder");
|
||||||
|
add("IKO/Everquill Phoenix3.fullborder");
|
||||||
|
add("IKO/Gemrazer2.fullborder");
|
||||||
|
add("IKO/Gemrazer3.fullborder");
|
||||||
|
add("IKO/Gyruda, Doom of Depths3.fullborder");
|
||||||
|
add("IKO/Huntmaster Liger2.fullborder");
|
||||||
|
add("IKO/Huntmaster Liger3.fullborder");
|
||||||
|
add("IKO/Illuna, Apex of Wishes2.fullborder");
|
||||||
|
add("IKO/Illuna, Apex of Wishes3.fullborder");
|
||||||
|
add("IKO/Indatha Triome2.fullborder");
|
||||||
|
add("IKO/Ketria Triome2.fullborder");
|
||||||
|
add("IKO/Lukka, Coppercoat Outcast2.fullborder");
|
||||||
|
add("IKO/Luminous Broodmoth3.fullborder");
|
||||||
|
add("IKO/Mysterious Egg2.fullborder");
|
||||||
|
add("IKO/Narset of the Ancient Way2.fullborder");
|
||||||
|
add("IKO/Nethroi, Apex of Death2.fullborder");
|
||||||
|
add("IKO/Nethroi, Apex of Death3.fullborder");
|
||||||
|
add("IKO/Pollywog Symbiote2.fullborder");
|
||||||
|
add("IKO/Raugrin Triome2.fullborder");
|
||||||
|
add("IKO/Savai Triome2.fullborder");
|
||||||
|
add("IKO/Sea-Dasher Octopus2.fullborder");
|
||||||
|
add("IKO/Snapdax, Apex of the Hunt2.fullborder");
|
||||||
|
add("IKO/Snapdax, Apex of the Hunt3.fullborder");
|
||||||
|
add("IKO/Sprite Dragon3.fullborder");
|
||||||
|
add("IKO/Titanoth Rex2.fullborder");
|
||||||
|
add("IKO/Vadrok, Apex of Thunder2.fullborder");
|
||||||
|
add("IKO/Vadrok, Apex of Thunder3.fullborder");
|
||||||
|
add("IKO/Vivien, Monsters' Advocate2.fullborder");
|
||||||
|
add("IKO/Void Beckoner2.fullborder");
|
||||||
|
add("IKO/Yidaro, Wandering Monster3.fullborder");
|
||||||
|
add("IKO/Zagoth Triome2.fullborder");
|
||||||
|
add("IKO/Zilortha, Strength Incarnate.fullborder");
|
||||||
|
add("M21/Basri Ket2.fullborder");
|
||||||
|
add("M21/Chandra, Heart of Fire2.fullborder");
|
||||||
|
add("M21/Containment Priest2.fullborder");
|
||||||
|
add("M21/Cultivate2.fullborder");
|
||||||
|
add("M21/Garruk, Unleashed2.fullborder");
|
||||||
|
add("M21/Grim Tutor2.fullborder");
|
||||||
|
add("M21/Liliana, Waker of the Dead2.fullborder");
|
||||||
|
add("M21/Massacre Wurm2.fullborder");
|
||||||
|
add("M21/Scavenging Ooze2.fullborder");
|
||||||
|
add("M21/Solemn Simulacrum2.fullborder");
|
||||||
|
add("M21/Teferi, Master of Time2.fullborder");
|
||||||
|
add("M21/Ugin, the Spirit Dragon2.fullborder");
|
||||||
|
add("M21/Ugin, the Spirit Dragon3.fullborder");
|
||||||
|
add("PLGS/Hangarback Walker.fullborder");
|
||||||
|
add("SLD/Acidic Slime.fullborder");
|
||||||
|
add("SLD/Captain Sisay.fullborder");
|
||||||
|
add("SLD/Meren of Clan Nel Toth.fullborder");
|
||||||
|
add("SLD/Narset, Enlightened Master.fullborder");
|
||||||
|
add("SLD/Necrotic Ooze.fullborder");
|
||||||
|
add("SLD/Oona, Queen of the Fae.fullborder");
|
||||||
|
add("SLD/Saskia the Unyielding.fullborder");
|
||||||
|
add("SLD/The Mimeoplasm.fullborder");
|
||||||
|
add("SLD/Voidslime.fullborder");
|
||||||
|
add("THB/Ashiok, Nightmare Muse2.fullborder");
|
||||||
|
add("THB/Calix, Destiny's Hand2.fullborder");
|
||||||
|
add("THB/Elspeth, Sun's Nemesis2.fullborder");
|
||||||
|
add("UST/Forest.fullborder");
|
||||||
|
add("UST/Island.fullborder");
|
||||||
|
add("UST/Mountain.fullborder");
|
||||||
|
add("UST/Plains.fullborder");
|
||||||
|
add("UST/Swamp.fullborder");
|
||||||
|
add("ZNR/Boulderloft Pathway2.fullborder");
|
||||||
|
add("ZNR/Branchloft Pathway2.fullborder");
|
||||||
|
add("ZNR/Brightclimb Pathway2.fullborder");
|
||||||
|
add("ZNR/Clearwater Pathway2.fullborder");
|
||||||
|
add("ZNR/Cragcrown Pathway2.fullborder");
|
||||||
|
add("ZNR/Grimclimb Pathway2.fullborder");
|
||||||
|
add("ZNR/Jace, Mirror Mage2.fullborder");
|
||||||
|
add("ZNR/Lavaglide Pathway2.fullborder");
|
||||||
|
add("ZNR/Murkwater Pathway2.fullborder");
|
||||||
|
add("ZNR/Nahiri, Heir of the Ancients2.fullborder");
|
||||||
|
add("ZNR/Needleverge Pathway2.fullborder");
|
||||||
|
add("ZNR/Nissa of Shadowed Boughs2.fullborder");
|
||||||
|
add("ZNR/Pillarverge Pathway2.fullborder");
|
||||||
|
add("ZNR/Riverglide Pathway2.fullborder");
|
||||||
|
add("ZNR/Timbercrown Pathway2.fullborder");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Texture n;
|
Texture n;
|
||||||
@Override
|
@Override
|
||||||
public Texture load(String key) {
|
public Texture load(String key) {
|
||||||
boolean extendedArt = false;
|
boolean extendedArt = isBorderless(key);
|
||||||
boolean textureFilter = Forge.isTextureFilteringEnabled();
|
boolean textureFilter = Forge.isTextureFilteringEnabled();
|
||||||
if (key.length() > 4){
|
|
||||||
if ((key.substring(0,4).contains("MPS_"))) //MPS_ sets
|
|
||||||
extendedArt = true;
|
|
||||||
else if ((key.substring(0,3).contains("UST"))) //Unstable Set
|
|
||||||
extendedArt = true;
|
|
||||||
}
|
|
||||||
File file = ImageKeys.getImageFile(key);
|
File file = ImageKeys.getImageFile(key);
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
FileHandle fh = new FileHandle(file);
|
FileHandle fh = new FileHandle(file);
|
||||||
try {
|
try {
|
||||||
Texture t = new Texture(fh, textureFilter);
|
Texture t = new Texture(fh, textureFilter);
|
||||||
|
//update
|
||||||
|
ImageCache.updateBorders(t, extendedArt ? false: isCloserToWhite(getpixelColor(t)));
|
||||||
if (textureFilter)
|
if (textureFilter)
|
||||||
t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||||
if (extendedArt)
|
if (extendedArt)
|
||||||
@@ -106,4 +238,44 @@ final class ImageLoader extends CacheLoader<String, Texture> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isBorderless(String imagekey) {
|
||||||
|
if (imagekey.length() > 7) {
|
||||||
|
if ((!imagekey.substring(0, 7).contains("MPS_KLD"))&&(imagekey.substring(0, 4).contains("MPS_"))) //MPS_ sets except MPD_KLD
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return borderlessCardlistKey.contains(TextUtil.fastReplace(imagekey,".full",".fullborder"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isBorderless(Texture t) {
|
||||||
|
//generated texture/pixmap?
|
||||||
|
if (t.toString().contains("com.badlogic.gdx.graphics.Texture@"))
|
||||||
|
return true;
|
||||||
|
for (String key : borderlessCardlistKey) {
|
||||||
|
if (t.toString().contains(key))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getpixelColor(Texture i) {
|
||||||
|
if (!i.getTextureData().isPrepared()) {
|
||||||
|
i.getTextureData().prepare(); //prepare texture
|
||||||
|
}
|
||||||
|
//get pixmap from texture data
|
||||||
|
Pixmap pixmap = i.getTextureData().consumePixmap();
|
||||||
|
//get pixel color from x,y texture coordinate based on the image fullborder or not
|
||||||
|
Color color = new Color(pixmap.getPixel(croppedBorderImage(i).getRegionX()+1, croppedBorderImage(i).getRegionY()+1));
|
||||||
|
pixmap.dispose();
|
||||||
|
return color.toString();
|
||||||
|
}
|
||||||
|
public static boolean isCloserToWhite(String c){
|
||||||
|
if (c == null || c == "")
|
||||||
|
return false;
|
||||||
|
int c_r = Integer.parseInt(c.substring(0,2),16);
|
||||||
|
int c_g = Integer.parseInt(c.substring(2,4),16);
|
||||||
|
int c_b = Integer.parseInt(c.substring(4,6),16);
|
||||||
|
int brightness = ((c_r * 299) + (c_g * 587) + (c_b * 114)) / 1000;
|
||||||
|
return brightness > 155;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,13 +49,12 @@ public class CardImage implements FImage {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (Forge.enableUIMask) {
|
if (Forge.enableUIMask) {
|
||||||
boolean fullborder = image.toString().contains(".fullborder.");
|
if (ImageCache.isBorderlessCardArt(image))
|
||||||
if (ImageCache.isExtendedArt(card))
|
|
||||||
g.drawImage(image, x, y, w, h);
|
g.drawImage(image, x, y, w, h);
|
||||||
else {
|
else {
|
||||||
float radius = (h - w)/8;
|
float radius = (h - w)/8;
|
||||||
g.drawfillBorder(3, ImageCache.borderColor(card), x, y, w, h, radius);
|
g.drawfillBorder(3, ImageCache.borderColor(card), x, y, w, h, radius);
|
||||||
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x+radius/2.2f, y+radius/2, w*0.96f, h*0.96f);
|
g.drawImage(ImageCache.croppedBorderImage(image), x+radius/2.2f, y+radius/2, w*0.96f, h*0.96f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -348,7 +348,6 @@ public class CardImageRenderer {
|
|||||||
if (image == ImageCache.defaultImage) { //support drawing card image manually if card image not found
|
if (image == ImageCache.defaultImage) { //support drawing card image manually if card image not found
|
||||||
drawCardImage(g, card, altState, x, y, w, h, CardStackPosition.Top);
|
drawCardImage(g, card, altState, x, y, w, h, CardStackPosition.Top);
|
||||||
} else {
|
} else {
|
||||||
boolean fullborder = image.toString().contains(".fullborder.");
|
|
||||||
float radius = (h - w)/8;
|
float radius = (h - w)/8;
|
||||||
float wh_Adj = ForgeConstants.isGdxPortLandscape && isCurrentCard ? 1.38f:1.0f;
|
float wh_Adj = ForgeConstants.isGdxPortLandscape && isCurrentCard ? 1.38f:1.0f;
|
||||||
float new_w = w*wh_Adj;
|
float new_w = w*wh_Adj;
|
||||||
@@ -367,32 +366,32 @@ public class CardImageRenderer {
|
|||||||
}
|
}
|
||||||
if (rotatePlane && (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane())) {
|
if (rotatePlane && (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane())) {
|
||||||
if (Forge.enableUIMask){
|
if (Forge.enableUIMask){
|
||||||
if (ImageCache.isExtendedArt(card))
|
if (ImageCache.isBorderlessCardArt(image))
|
||||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
||||||
else {
|
else {
|
||||||
g.drawRotatedImage(FSkin.getBorders().get(0), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
g.drawRotatedImage(FSkin.getBorders().get(0), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
||||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), new_x+radius/2-minusxy, new_y+radius/2-minusxy, new_w*croppedArea, new_h*croppedArea, (new_x+radius/2-minusxy) + (new_w*croppedArea) / 2, (new_y+radius/2-minusxy) + (new_h*croppedArea) / 2, -90);
|
g.drawRotatedImage(ImageCache.croppedBorderImage(image), new_x+radius/2-minusxy, new_y+radius/2-minusxy, new_w*croppedArea, new_h*croppedArea, (new_x+radius/2-minusxy) + (new_w*croppedArea) / 2, (new_y+radius/2-minusxy) + (new_h*croppedArea) / 2, -90);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
||||||
} else if (rotateSplit && isCurrentCard && card.isSplitCard() && canshow) {
|
} else if (rotateSplit && isCurrentCard && card.isSplitCard() && canshow) {
|
||||||
boolean isAftermath = card.getText().contains("Aftermath") || card.getAlternateState().getOracleText().contains("Aftermath");
|
boolean isAftermath = card.getText().contains("Aftermath") || card.getAlternateState().getOracleText().contains("Aftermath");
|
||||||
if (Forge.enableUIMask) {
|
if (Forge.enableUIMask) {
|
||||||
if (ImageCache.isExtendedArt(card))
|
if (ImageCache.isBorderlessCardArt(image))
|
||||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||||
else {
|
else {
|
||||||
g.drawRotatedImage(FSkin.getBorders().get(ImageCache.getFSkinBorders(card)), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
g.drawRotatedImage(FSkin.getBorders().get(ImageCache.getFSkinBorders(card)), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), new_x + radius / 2-minusxy, new_y + radius / 2-minusxy, new_w * croppedArea, new_h * croppedArea, (new_x + radius / 2-minusxy) + (new_w * croppedArea) / 2, (new_y + radius / 2-minusxy) + (new_h * croppedArea) / 2, isAftermath ? 90 : -90);
|
g.drawRotatedImage(ImageCache.croppedBorderImage(image), new_x + radius / 2-minusxy, new_y + radius / 2-minusxy, new_w * croppedArea, new_h * croppedArea, (new_x + radius / 2-minusxy) + (new_w * croppedArea) / 2, (new_y + radius / 2-minusxy) + (new_h * croppedArea) / 2, isAftermath ? 90 : -90);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||||
} else {
|
} else {
|
||||||
if (Forge.enableUIMask && canshow) {
|
if (Forge.enableUIMask && canshow) {
|
||||||
if (ImageCache.isExtendedArt(card))
|
if (ImageCache.isBorderlessCardArt(image))
|
||||||
g.drawImage(image, x, y, w, h);
|
g.drawImage(image, x, y, w, h);
|
||||||
else {
|
else {
|
||||||
g.drawImage(ImageCache.getBorderImage(card, canshow), x, y, w, h);
|
g.drawImage(ImageCache.getBorderImage(image, canshow), x, y, w, h);
|
||||||
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
|
g.drawImage(ImageCache.croppedBorderImage(image), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (canshow)
|
if (canshow)
|
||||||
|
|||||||
@@ -459,13 +459,12 @@ public class CardRenderer {
|
|||||||
if (image == ImageCache.defaultImage) {
|
if (image == ImageCache.defaultImage) {
|
||||||
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(pc), false, x, y, w, h, pos);
|
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(pc), false, x, y, w, h, pos);
|
||||||
} else {
|
} else {
|
||||||
boolean fullborder = image.toString().contains(".fullborder.");
|
|
||||||
if (Forge.enableUIMask) {
|
if (Forge.enableUIMask) {
|
||||||
if (ImageCache.isExtendedArt(pc))
|
if (ImageCache.isBorderlessCardArt(image))
|
||||||
g.drawImage(image, x, y, w, h);
|
g.drawImage(image, x, y, w, h);
|
||||||
else {
|
else {
|
||||||
g.drawImage(ImageCache.getBorderImage(pc), x, y, w, h);
|
g.drawImage(ImageCache.getBorderImage(image), x, y, w, h);
|
||||||
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
|
g.drawImage(ImageCache.croppedBorderImage(image), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
g.drawImage(image, x, y, w, h);
|
g.drawImage(image, x, y, w, h);
|
||||||
@@ -499,26 +498,25 @@ public class CardRenderer {
|
|||||||
if (image == ImageCache.defaultImage) {
|
if (image == ImageCache.defaultImage) {
|
||||||
CardImageRenderer.drawCardImage(g, card, false, x, y, w, h, pos);
|
CardImageRenderer.drawCardImage(g, card, false, x, y, w, h, pos);
|
||||||
} else {
|
} else {
|
||||||
boolean fullborder = image.toString().contains(".fullborder.");
|
|
||||||
if(FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON)
|
if(FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON)
|
||||||
&& (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane()) && rotate){
|
&& (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane()) && rotate){
|
||||||
if (Forge.enableUIMask) {
|
if (Forge.enableUIMask) {
|
||||||
if (ImageCache.isExtendedArt(card))
|
if (ImageCache.isBorderlessCardArt(image))
|
||||||
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
|
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
|
||||||
else {
|
else {
|
||||||
g.drawRotatedImage(FSkin.getBorders().get(0), x, y, w, h, x + w / 2, y + h / 2, -90);
|
g.drawRotatedImage(FSkin.getBorders().get(0), x, y, w, h, x + w / 2, y + h / 2, -90);
|
||||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), x+radius/2.3f-minusxy, y+radius/2-minusxy, w*croppedArea, h*croppedArea, (x+radius/2.3f-minusxy) + (w*croppedArea) / 2, (y+radius/2-minusxy) + (h*croppedArea) / 2, -90);
|
g.drawRotatedImage(ImageCache.croppedBorderImage(image), x+radius/2.3f-minusxy, y+radius/2-minusxy, w*croppedArea, h*croppedArea, (x+radius/2.3f-minusxy) + (w*croppedArea) / 2, (y+radius/2-minusxy) + (h*croppedArea) / 2, -90);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
|
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
|
||||||
} else {
|
} else {
|
||||||
if (Forge.enableUIMask && canshow) {
|
if (Forge.enableUIMask && canshow) {
|
||||||
if (ImageCache.isExtendedArt(card))
|
if (ImageCache.isBorderlessCardArt(image))
|
||||||
g.drawImage(image, x, y, w, h);
|
g.drawImage(image, x, y, w, h);
|
||||||
else {
|
else {
|
||||||
boolean t = (card.getCurrentState().getOriginalColors() != card.getCurrentState().getColors()) || card.getCurrentState().hasChangeColors();
|
boolean t = (card.getCurrentState().getOriginalColors() != card.getCurrentState().getColors()) || card.getCurrentState().hasChangeColors();
|
||||||
g.drawBorderImage(ImageCache.getBorderImage(card, canshow), ImageCache.getTint(card), x, y, w, h, t); //tint check for changed colors
|
g.drawBorderImage(ImageCache.getBorderImage(image, canshow), ImageCache.getTint(card), x, y, w, h, t); //tint check for changed colors
|
||||||
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
|
g.drawImage(ImageCache.croppedBorderImage(image), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (canshow)
|
if (canshow)
|
||||||
|
|||||||
@@ -90,3 +90,4 @@ Core Set 2021, 3/6/M21, M21
|
|||||||
Jumpstart, -/2/JMP, Meta-Choose(S(JMP Above the Clouds 1)Above the Clouds 1;S(JMP Above the Clouds 2)Above the Clouds 2;S(JMP Above the Clouds 3)Above the Clouds 3;S(JMP Above the Clouds 4)Above the Clouds 4;S(JMP Angels 1)Angels 1;S(JMP Angels 2)Angels 2;S(JMP Archaeology 1)Archaeology 1;S(JMP Archaeology 2)Archaeology 2;S(JMP Archaeology 3)Archaeology 3;S(JMP Archaeology 4)Archaeology 4;;S(JMP Basri)Basri;S(JMP Cats 1)Cats 1;S(JMP Cats 2)Cats 2;S(JMP Chandra)Chandra;S(JMP Devilish 1)Devilish 1;S(JMP Devilish 2)Devilish 2;S(JMP Devilish 3)Devilish 3;S(JMP Devilish 4)Devilish 4;S(JMP Dinosaurs 1)Dinosaurs 1;S(JMP Dinosaurs 2)Dinosaurs 2;S(JMP Dinosaurs 3)Dinosaurs 3;S(JMP Dinosaurs 4)Dinosaurs 4;S(JMP Discarding 1)Discarding 1;S(JMP Discarding 2)Discarding 2;S(JMP Doctor 1)Doctor 1;S(JMP Doctor 2)Doctor 2;S(JMP Doctor 3)Doctor 3;S(JMP Doctor 4)Doctor 4;S(JMP Dogs 1)Dogs 1;S(JMP Dogs 2)Dogs 2;S(JMP Dragons 1)Dragons 1;S(JMP Dragons 2)Dragons 2;S(JMP Elves 1)Elves 1;S(JMP Elves 2)Elves 2;S(JMP Enchanted 1)Enchanted 1;S(JMP Enchanted 2)Enchanted 2;S(JMP Feathered Friends 1)Feathered Friends 1;S(JMP Feathered Friends 2)Feathered Friends 2;S(JMP Feathered Friends 3)Feathered Friends 3;S(JMP Feathered Friends 4)Feathered Friends 4;S(JMP Garruk)Garruk;S(JMP Goblins 1)Goblins 1;S(JMP Goblins 2)Goblins 2;S(JMP Goblins 3)Goblins 3;S(JMP Goblins 4)Goblins 4;S(JMP Heavily Armored 1)Heavily Armored 1;S(JMP Heavily Armored 2)Heavily Armored 2;S(JMP Heavily Armored 3)Heavily Armored 3;S(JMP Heavily Armored 4)Heavily Armored 4;S(JMP Lands 1)Lands 1;S(JMP Lands 2)Lands 2;S(JMP Legion 1)Legion 1;S(JMP Legion 2)Legion 2;S(JMP Legion 3)Legion 3;S(JMP Legion 4)Legion 4;S(JMP Lightning 1)Lightning 1;S(JMP Lightning 2)Lightning 2;S(JMP Liliana)Liliana;S(JMP Milling)Milling;S(JMP Minions 1)Minions 1;S(JMP Minions 2)Minions 2;S(JMP Minions 3)Minions 3;S(JMP Minions 4)Minions 4;S(JMP Minotaurs 1)Minotaurs 1;S(JMP Minotaurs 2)Minotaurs 2;S(JMP Phyrexian)Phyrexian;S(JMP Pirates 1)Pirates 1;S(JMP Pirates 2)Pirates 2;S(JMP Plus One 1)Plus One 1;S(JMP Plus One 2)Plus One 2;S(JMP Plus One 3)Plus One 3;S(JMP Plus One 4)Plus One 4;S(JMP Predatory 1)Predatory 1;S(JMP Predatory 2)Predatory 2;S(JMP Predatory 3)Predatory 3;S(JMP Predatory 4)Predatory 4;S(JMP Rainbow)Rainbow;S(JMP Reanimated 1)Reanimated 1;S(JMP Reanimated 2)Reanimated 2;S(JMP Reanimated 3)Reanimated 3;S(JMP Reanimated 4)Reanimated 4;S(JMP Rogues 1)Rogues 1;S(JMP Rogues 2)Rogues 2;S(JMP Seismic)Seismic;S(JMP Smashing 1)Smashing 1;S(JMP Smashing 2)Smashing 2;S(JMP Smashing 3)Smashing 3;S(JMP Smashing 4)Smashing 4;S(JMP Spellcasting 1)Spellcasting 1;S(JMP Spellcasting 2)Spellcasting 2;S(JMP Spellcasting 3)Spellcasting 3;S(JMP Spellcasting 4)Spellcasting 4;S(JMP Spirits 1)Spirits 1;S(JMP Spirits 2)Spirits 2;S(JMP Spooky 1)Spooky 1;S(JMP Spooky 2)Spooky 2;S(JMP Spooky 3)Spooky 3;S(JMP Spooky 4)Spooky 4;S(JMP Teferi)Teferi;S(JMP Tree Hugging 1)Tree Hugging 1;S(JMP Tree Hugging 2)Tree Hugging 2;S(JMP Tree Hugging 3)Tree Hugging 3;S(JMP Tree Hugging 4)Tree Hugging 4;S(JMP Under the Sea 1)Under the Sea 1;S(JMP Under the Sea 2)Under the Sea 2;S(JMP Unicorns)Unicorns;S(JMP Vampires 1)Vampires 1;S(JMP Vampires 2)Vampires 2;S(JMP Vampires 3)Vampires 3;S(JMP Vampires 4)Vampires 4;S(JMP Walls)Walls;S(JMP Well-Read 1)Well-Read 1;S(JMP Well-Read 2)Well-Read 2;S(JMP Well-Read 3)Well-Read 3;S(JMP Well-Read 4)Well-Read 4;S(JMP Witchcraft 1)Witchcraft 1;S(JMP Witchcraft 2)Witchcraft 2;S(JMP Wizards 1)Wizards 1;S(JMP Wizards 2)Wizards 2;S(JMP Wizards 3)Wizards 3;S(JMP Wizards 4)Wizards 4)Themes
|
Jumpstart, -/2/JMP, Meta-Choose(S(JMP Above the Clouds 1)Above the Clouds 1;S(JMP Above the Clouds 2)Above the Clouds 2;S(JMP Above the Clouds 3)Above the Clouds 3;S(JMP Above the Clouds 4)Above the Clouds 4;S(JMP Angels 1)Angels 1;S(JMP Angels 2)Angels 2;S(JMP Archaeology 1)Archaeology 1;S(JMP Archaeology 2)Archaeology 2;S(JMP Archaeology 3)Archaeology 3;S(JMP Archaeology 4)Archaeology 4;;S(JMP Basri)Basri;S(JMP Cats 1)Cats 1;S(JMP Cats 2)Cats 2;S(JMP Chandra)Chandra;S(JMP Devilish 1)Devilish 1;S(JMP Devilish 2)Devilish 2;S(JMP Devilish 3)Devilish 3;S(JMP Devilish 4)Devilish 4;S(JMP Dinosaurs 1)Dinosaurs 1;S(JMP Dinosaurs 2)Dinosaurs 2;S(JMP Dinosaurs 3)Dinosaurs 3;S(JMP Dinosaurs 4)Dinosaurs 4;S(JMP Discarding 1)Discarding 1;S(JMP Discarding 2)Discarding 2;S(JMP Doctor 1)Doctor 1;S(JMP Doctor 2)Doctor 2;S(JMP Doctor 3)Doctor 3;S(JMP Doctor 4)Doctor 4;S(JMP Dogs 1)Dogs 1;S(JMP Dogs 2)Dogs 2;S(JMP Dragons 1)Dragons 1;S(JMP Dragons 2)Dragons 2;S(JMP Elves 1)Elves 1;S(JMP Elves 2)Elves 2;S(JMP Enchanted 1)Enchanted 1;S(JMP Enchanted 2)Enchanted 2;S(JMP Feathered Friends 1)Feathered Friends 1;S(JMP Feathered Friends 2)Feathered Friends 2;S(JMP Feathered Friends 3)Feathered Friends 3;S(JMP Feathered Friends 4)Feathered Friends 4;S(JMP Garruk)Garruk;S(JMP Goblins 1)Goblins 1;S(JMP Goblins 2)Goblins 2;S(JMP Goblins 3)Goblins 3;S(JMP Goblins 4)Goblins 4;S(JMP Heavily Armored 1)Heavily Armored 1;S(JMP Heavily Armored 2)Heavily Armored 2;S(JMP Heavily Armored 3)Heavily Armored 3;S(JMP Heavily Armored 4)Heavily Armored 4;S(JMP Lands 1)Lands 1;S(JMP Lands 2)Lands 2;S(JMP Legion 1)Legion 1;S(JMP Legion 2)Legion 2;S(JMP Legion 3)Legion 3;S(JMP Legion 4)Legion 4;S(JMP Lightning 1)Lightning 1;S(JMP Lightning 2)Lightning 2;S(JMP Liliana)Liliana;S(JMP Milling)Milling;S(JMP Minions 1)Minions 1;S(JMP Minions 2)Minions 2;S(JMP Minions 3)Minions 3;S(JMP Minions 4)Minions 4;S(JMP Minotaurs 1)Minotaurs 1;S(JMP Minotaurs 2)Minotaurs 2;S(JMP Phyrexian)Phyrexian;S(JMP Pirates 1)Pirates 1;S(JMP Pirates 2)Pirates 2;S(JMP Plus One 1)Plus One 1;S(JMP Plus One 2)Plus One 2;S(JMP Plus One 3)Plus One 3;S(JMP Plus One 4)Plus One 4;S(JMP Predatory 1)Predatory 1;S(JMP Predatory 2)Predatory 2;S(JMP Predatory 3)Predatory 3;S(JMP Predatory 4)Predatory 4;S(JMP Rainbow)Rainbow;S(JMP Reanimated 1)Reanimated 1;S(JMP Reanimated 2)Reanimated 2;S(JMP Reanimated 3)Reanimated 3;S(JMP Reanimated 4)Reanimated 4;S(JMP Rogues 1)Rogues 1;S(JMP Rogues 2)Rogues 2;S(JMP Seismic)Seismic;S(JMP Smashing 1)Smashing 1;S(JMP Smashing 2)Smashing 2;S(JMP Smashing 3)Smashing 3;S(JMP Smashing 4)Smashing 4;S(JMP Spellcasting 1)Spellcasting 1;S(JMP Spellcasting 2)Spellcasting 2;S(JMP Spellcasting 3)Spellcasting 3;S(JMP Spellcasting 4)Spellcasting 4;S(JMP Spirits 1)Spirits 1;S(JMP Spirits 2)Spirits 2;S(JMP Spooky 1)Spooky 1;S(JMP Spooky 2)Spooky 2;S(JMP Spooky 3)Spooky 3;S(JMP Spooky 4)Spooky 4;S(JMP Teferi)Teferi;S(JMP Tree Hugging 1)Tree Hugging 1;S(JMP Tree Hugging 2)Tree Hugging 2;S(JMP Tree Hugging 3)Tree Hugging 3;S(JMP Tree Hugging 4)Tree Hugging 4;S(JMP Under the Sea 1)Under the Sea 1;S(JMP Under the Sea 2)Under the Sea 2;S(JMP Unicorns)Unicorns;S(JMP Vampires 1)Vampires 1;S(JMP Vampires 2)Vampires 2;S(JMP Vampires 3)Vampires 3;S(JMP Vampires 4)Vampires 4;S(JMP Walls)Walls;S(JMP Well-Read 1)Well-Read 1;S(JMP Well-Read 2)Well-Read 2;S(JMP Well-Read 3)Well-Read 3;S(JMP Well-Read 4)Well-Read 4;S(JMP Witchcraft 1)Witchcraft 1;S(JMP Witchcraft 2)Witchcraft 2;S(JMP Wizards 1)Wizards 1;S(JMP Wizards 2)Wizards 2;S(JMP Wizards 3)Wizards 3;S(JMP Wizards 4)Wizards 4)Themes
|
||||||
Amonkhet Remastered, 3/6/AKR, AKR
|
Amonkhet Remastered, 3/6/AKR, AKR
|
||||||
Double Masters, 3/6/2XM, 2XM
|
Double Masters, 3/6/2XM, 2XM
|
||||||
|
Zendikar Rising, 3/6/ZNR, ZNR
|
||||||
@@ -114,3 +114,4 @@ THB: 36 Boosters
|
|||||||
MB1: 24 Boosters
|
MB1: 24 Boosters
|
||||||
IKO: 36 Boosters
|
IKO: 36 Boosters
|
||||||
M21: 36 Boosters
|
M21: 36 Boosters
|
||||||
|
ZNR: 36 Boosters
|
||||||
@@ -80,3 +80,5 @@ IKO: 10 Boosters, 40 BasicLands
|
|||||||
#needs to be 20 BasicLands, 20 Foil BasicLands, 1 Colossification+|IKO|3
|
#needs to be 20 BasicLands, 20 Foil BasicLands, 1 Colossification+|IKO|3
|
||||||
M21: 10 Boosters, 40 BasicLands
|
M21: 10 Boosters, 40 BasicLands
|
||||||
#needs to be 20 BasicLands, 20 Foil BasicLands, 1 Pack Leader+|M21|3
|
#needs to be 20 BasicLands, 20 Foil BasicLands, 1 Pack Leader+|M21|3
|
||||||
|
ZNR: 10 Boosters, 40 BasicLands
|
||||||
|
#needs to be 20 BasicLands, 20 Foil BasicLands, 1 Charix, the Raging Isle+|ZNR|3
|
||||||
16
forge-gui/res/cardsfolder/a/akoum_warrior_akoum_teeth.txt
Normal file
16
forge-gui/res/cardsfolder/a/akoum_warrior_akoum_teeth.txt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
Name:Akoum Warrior
|
||||||
|
ManaCost:5 R
|
||||||
|
Types:Creature Minotaur Warrior
|
||||||
|
PT:4/5
|
||||||
|
K:Trample
|
||||||
|
AlternateMode:Modal
|
||||||
|
Oracle:Trample
|
||||||
|
|
||||||
|
ALTERNATE
|
||||||
|
|
||||||
|
Name:Akoum Teeth
|
||||||
|
ManaCost:no cost
|
||||||
|
Types:Land
|
||||||
|
K:CARDNAME enters the battlefield tapped.
|
||||||
|
A:AB$ Mana | Cost$ T | Produced$ R | SpellDescription$ Add {R}.
|
||||||
|
Oracle:Akoum Teeth enters the battlefield tapped.\n{T}: Add {R}.
|
||||||
8
forge-gui/res/cardsfolder/a/ancient_greenwarden.txt
Executable file
8
forge-gui/res/cardsfolder/a/ancient_greenwarden.txt
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
Name:Ancient Greenwarden
|
||||||
|
ManaCost:4 G G
|
||||||
|
Types:Creature Elemental
|
||||||
|
PT:5/7
|
||||||
|
K:Reach
|
||||||
|
S:Mode$ Continuous | Affected$ Land.YouCtrl | MayPlay$ True | AffectedZone$ Graveyard | Description$ You may play lands from your graveyard.
|
||||||
|
K:Panharmonicon:Land:If a land entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
|
||||||
|
Oracle:Reach\nYou may play lands from your graveyard.\nIf a land entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.
|
||||||
13
forge-gui/res/cardsfolder/a/anowon_the_ruin_thief.txt
Normal file
13
forge-gui/res/cardsfolder/a/anowon_the_ruin_thief.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Name:Anowon, the Ruin Thief
|
||||||
|
ManaCost:2 U B
|
||||||
|
Types:Legendary Creature Vampire Rogue
|
||||||
|
PT:2/4
|
||||||
|
S:Mode$ Continuous | Affected$ Rogue.Other+YouCtrl | AddPower$ 1 | AddToughness$ 1 | Description$ Other Rogues you control get +1/+1.
|
||||||
|
T:Mode$ DamageDoneOnce | CombatDamage$ True | ValidSource$ Rogue.YouCtrl | ValidTarget$ Player | TriggerZones$ Battlefield | Execute$ TrigMill | TriggerDescription$ Whenever one or more Rogues you control deal combat damage to a player, that player mills a card for each 1 damage dealt to them. If the player mills at least one creature card this way, you draw a card. (To mill a card, a player puts the top card of their library into their graveyard.)
|
||||||
|
SVar:TrigMill:DB$ Mill | Defined$ TriggeredTarget | NumCards$ X | References$ X | RememberMilled$ True | SubAbility$ DBDraw
|
||||||
|
SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ 1 | ConditionDefined$ Remembered | ConditionPresent$ Creature | SubAbility$ DBCleanup
|
||||||
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
|
SVar:X:TriggerCount$DamageAmount
|
||||||
|
DeckNeeds:Type$Rogue
|
||||||
|
DeckHas:Ability$Mill
|
||||||
|
Oracle:Other Rogues you control get +1/+1.\nWhenever one or more Rogues you control deal combat damage to a player, that player mills a card for each 1 damage dealt to them. If the player mills at least one creature card this way, you draw a card. (To mill a card, a player puts the top card of their library into their graveyard.)
|
||||||
12
forge-gui/res/cardsfolder/a/ashaya_soul_of_the_wild.txt
Executable file
12
forge-gui/res/cardsfolder/a/ashaya_soul_of_the_wild.txt
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
Name:Ashaya, Soul of the Wild
|
||||||
|
ManaCost:3 G G
|
||||||
|
Types:Legendary Creature Elemental
|
||||||
|
PT:*/*
|
||||||
|
S:Mode$ Continuous | EffectZone$ All | CharacteristicDefining$ True | SetPower$ X | SetToughness$ X | Description$ CARDNAME's power and toughness are each equal to the number of lands you control.
|
||||||
|
S:Mode$ Continuous | Affected$ Creature.nonToken+YouCtrl | AddType$ Forest & Land | Description$ Nontoken creatures you control are Forest lands in addition to their other types. (They're still affected by summoning sickness.)
|
||||||
|
SVar:X:Count$Valid Land.YouCtrl
|
||||||
|
SVar:Y:Count$Valid Creature.nonToken+YouCtrl
|
||||||
|
SVar:Z:SVar$X/Plus.Y
|
||||||
|
SVar:NeedsToPlayVar:Z GE4
|
||||||
|
SVar:BuffedBy:Land,Creature
|
||||||
|
Oracle:Ashaya, Soul of the Wild's power and toughness are each equal to the number of lands you control.\nNontoken creatures you control are Forest lands in addition to their other types. (They're still affected by summoning sickness.)
|
||||||
@@ -3,7 +3,6 @@ ManaCost:2 W W
|
|||||||
Types:Creature Human Wizard
|
Types:Creature Human Wizard
|
||||||
PT:2/2
|
PT:2/2
|
||||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ Detain | TriggerDescription$ When CARDNAME enters the battlefield, detain up to two target creatures your opponents control. (Until your next turn, those creatures can't attack or block and their activated abilities can't be activated.)
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ Detain | TriggerDescription$ When CARDNAME enters the battlefield, detain up to two target creatures your opponents control. (Until your next turn, those creatures can't attack or block and their activated abilities can't be activated.)
|
||||||
SVar:Detain:DB$ Pump | TargetMin$ 0 | TargetMax$ 2 | KW$ HIDDEN CARDNAME can't attack or block. & HIDDEN CARDNAME's activated abilities can't be activated. | IsCurse$ True | UntilYourNextTurn$ True | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature your opponent controls to detain.
|
SVar:Detain:DB$ Pump | TargetMin$ 0 | TargetMax$ 2 | KW$ HIDDEN CARDNAME can't attack or block. & HIDDEN CARDNAME's activated abilities can't be activated. | IsCurse$ True | UntilYourNextTurn$ True | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature your opponent controls to detain. | AILogic$ DetainNonLand
|
||||||
SVar:PlayMain1:TRUE
|
SVar:PlayMain1:TRUE
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/azorius_justiciar.jpg
|
|
||||||
Oracle:When Azorius Justiciar enters the battlefield, detain up to two target creatures your opponents control. (Until your next turn, those creatures can't attack or block and their activated abilities can't be activated.)
|
Oracle:When Azorius Justiciar enters the battlefield, detain up to two target creatures your opponents control. (Until your next turn, those creatures can't attack or block and their activated abilities can't be activated.)
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
Name:Bala Ged Recovery
|
||||||
|
ManaCost:2 G
|
||||||
|
Types:Sorcery
|
||||||
|
A:SP$ ChangeZone | Cost$ 2 G | ValidTgts$ Card.YouOwn | TgtPrompt$ Select target card | Origin$ Graveyard | Destination$ Hand | SpellDescription$ Return target card from your graveyard to your hand.
|
||||||
|
DeckHas:Ability$Graveyard
|
||||||
|
AlternateMode:Modal
|
||||||
|
Oracle:Return target card from your graveyard to your hand.
|
||||||
|
|
||||||
|
ALTERNATE
|
||||||
|
|
||||||
|
Name:Bala Ged Sanctuary
|
||||||
|
ManaCost:no cost
|
||||||
|
Types:Land
|
||||||
|
K:CARDNAME enters the battlefield tapped.
|
||||||
|
A:AB$ Mana | Cost$ T | Produced$ G | SpellDescription$ Add {G}.
|
||||||
|
Oracle:Bala Ged Sanctuary enters the battlefield tapped.\n{T}: Add {G}.
|
||||||
9
forge-gui/res/cardsfolder/b/base_camp.txt
Normal file
9
forge-gui/res/cardsfolder/b/base_camp.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Name:Base Camp
|
||||||
|
ManaCost:no cost
|
||||||
|
Types:Land
|
||||||
|
K:CARDNAME enters the battlefield tapped.
|
||||||
|
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
|
||||||
|
A:AB$ Mana | Cost$ T | Produced$ Any | RestrictValid$ Cleric,Rogue,Warrior,Wizard | SpellDescription$ Add one mana of any color. Spend this mana only to cast a Cleric, Rogue, Warrior, or Wizard spell or to activate an ability of a Cleric, Rogue, Warrior, or Wizard.
|
||||||
|
DeckHas:Ability$Party
|
||||||
|
DeckHints:Type$Cleric|Rogue|Warrior|Wizard
|
||||||
|
Oracle:Base Camp enters the battlefield tapped.\n{T}: Add {C}.\n{T}: Add one mana of any color. Spend this mana only to cast a Cleric, Rogue, Warrior, or Wizard spell or to activate an ability of a Cleric, Rogue, Warrior, or Wizard.
|
||||||
@@ -6,7 +6,7 @@ K:Vigilance
|
|||||||
K:Protection from multicolored
|
K:Protection from multicolored
|
||||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPutCounter | TriggerDescription$ When CARDNAME enters the battlefield, put a +1/+1 counter on target creature you control.
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigPutCounter | TriggerDescription$ When CARDNAME enters the battlefield, put a +1/+1 counter on target creature you control.
|
||||||
SVar:TrigPutCounter:DB$ PutCounter | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | CounterType$ P1P1 | CounterNum$ 1
|
SVar:TrigPutCounter:DB$ PutCounter | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control | CounterType$ P1P1 | CounterNum$ 1
|
||||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self+counters_GE1_P1P1 | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerController$ TriggeredCardController | TriggerDescription$ Whenever CARDNAME or another creature you control dies, if it had a +1/+1 counter on it, create a 2/2 white Knight creature token with vigilance.
|
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self+counters_GE1_P1P1 | Execute$ TrigToken | TriggerController$ TriggeredCardController | TriggerDescription$ Whenever CARDNAME or another creature you control dies, if it had a +1/+1 counter on it, create a 2/2 white Knight creature token with vigilance.
|
||||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.Other+YouCtrl+counters_GE1_P1P1 | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerController$ TriggeredCardController | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another creature you control dies, if it had a +1/+1 counter on it, create a 2/2 white Knight creature token with vigilance.
|
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.Other+YouCtrl+counters_GE1_P1P1 | TriggerZones$ Battlefield | Execute$ TrigToken | TriggerController$ TriggeredCardController | Secondary$ True | TriggerDescription$ Whenever CARDNAME or another creature you control dies, if it had a +1/+1 counter on it, create a 2/2 white Knight creature token with vigilance.
|
||||||
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_2_2_knight_vigilance | TokenOwner$ You
|
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ w_2_2_knight_vigilance | TokenOwner$ You
|
||||||
DeckHas:Ability$Counters & Ability$Token
|
DeckHas:Ability$Counters & Ability$Token
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ K:Menace
|
|||||||
S:Mode$ Continuous | Affected$ Card.Self | AddPower$ 3 | CheckSVar$ X | SVarCompare$ GE8 | Description$ CARDNAME gets +3/+0 as long as an opponent has eight or more cards in their graveyard.
|
S:Mode$ Continuous | Affected$ Card.Self | AddPower$ 3 | CheckSVar$ X | SVarCompare$ GE8 | Description$ CARDNAME gets +3/+0 as long as an opponent has eight or more cards in their graveyard.
|
||||||
SVar:X:PlayerCountOpponents$HighestCardsInGraveyard
|
SVar:X:PlayerCountOpponents$HighestCardsInGraveyard
|
||||||
AlternateMode:Modal
|
AlternateMode:Modal
|
||||||
Oracle:Blackbloom Rogue gets +3/+0 as long as an opponent has eight or more cards in their graveyard.
|
Oracle:Menace\nBlackbloom Rogue gets +3/+0 as long as an opponent has eight or more cards in their graveyard.
|
||||||
|
|
||||||
ALTERNATE
|
ALTERNATE
|
||||||
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
Name:Cellar Door
|
Name:Cellar Door
|
||||||
ManaCost:2
|
ManaCost:2
|
||||||
Types:Artifact
|
Types:Artifact
|
||||||
A:AB$ Mill | Cost$ 3 T | NumCards$ 1 | ValidTgts$ Player | TgtPrompt$ Choose a player | FromBottom$ True | RememberMilled$ True | SubAbility$ DBToken | SpellDescription$ Target player puts the bottom card of their library into their graveyard. If it's a creature card, you create a 2/2 black Zombie creature token.
|
A:AB$ Mill | Cost$ 3 T | NumCards$ 1 | ValidTgts$ Player | TgtPrompt$ Choose a player | FromBottom$ True | RememberMilled$ True | SubAbility$ DBToken | StackDescription$ {p:Targeted} puts the bottom card of their library into their graveyard. | SpellDescription$ Target player puts the bottom card of their library into their graveyard. If it's a creature card, you create a 2/2 black Zombie creature token.
|
||||||
SVar:DBToken:DB$ Token | LegacyImage$ b 2 2 zombie isd | TokenScript$ b_2_2_zombie | TokenOwner$ You | TokenAmount$ 1 | ConditionDefined$ Remembered | ConditionPresent$ Creature | ConditionCompare$ EQ1 | SubAbility$ DBCleanup
|
SVar:DBToken:DB$ Token | TokenScript$ b_2_2_zombie | TokenOwner$ You | TokenAmount$ 1 | ConditionDefined$ Remembered | ConditionPresent$ Creature | ConditionCompare$ EQ1 | SubAbility$ DBCleanup | StackDescription$ If it's a creature card, {p:You} creates a 2/2 black Zombie creature token. | SpellDescription$ If it's a creature card, you create a 2/2 black Zombie creature token.
|
||||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/cellar_door.jpg
|
|
||||||
Oracle:{3}, {T}: Target player puts the bottom card of their library into their graveyard. If it's a creature card, create a 2/2 black Zombie creature token.
|
Oracle:{3}, {T}: Target player puts the bottom card of their library into their graveyard. If it's a creature card, create a 2/2 black Zombie creature token.
|
||||||
|
|||||||
9
forge-gui/res/cardsfolder/c/cliffhaven_kitesail.txt
Executable file
9
forge-gui/res/cardsfolder/c/cliffhaven_kitesail.txt
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
Name:Cliffhaven Kitesail
|
||||||
|
ManaCost:1
|
||||||
|
Types:Artifact Equipment
|
||||||
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigAttach | TriggerDescription$ When CARDNAME enters the battlefield, attach it to target creature you control.
|
||||||
|
SVar:TrigAttach:DB$ Attach | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature you control
|
||||||
|
SVar:NeedsToPlay:Creature.YouCtrl+inZoneBattlefield
|
||||||
|
S:Mode$ Continuous | Affected$ Creature.EquippedBy | AddKeyword$ Flying | Description$ Equipped creature has flying.
|
||||||
|
K:Equip:2
|
||||||
|
Oracle:When Cliffhaven Kitesail enters the battlefield, attach it to target creature you control.\nEquipped creature has flying.\nEquip {2} ({2}: Attach to target creature you control. Equip only as a sorcery.)
|
||||||
10
forge-gui/res/cardsfolder/e/enigma_thief.txt
Normal file
10
forge-gui/res/cardsfolder/e/enigma_thief.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Name:Enigma Thief
|
||||||
|
ManaCost:5 U U
|
||||||
|
Types:Creature Sphinx Rogue
|
||||||
|
PT:5/5
|
||||||
|
K:Prowl:3 U
|
||||||
|
K:Flying
|
||||||
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ ReturnOneEach | TriggerDescription$ When CARDNAME enters the battlefield, for each opponent, return up to one target nonland permanent that player controls to its owner’s hand.
|
||||||
|
SVar:ReturnOneEach:DB$ ChangeZone | Origin$ Battlefield | Destination$ Hand | ValidTgts$ Permanent.nonLand+OppCtrl | TargetMin$ 0 | TargetMax$ OneEach | References$ OneEach | TargetsWithDifferentControllers$ True | TgtPrompt$ Select up to one target nonland permanent each opponent controls
|
||||||
|
SVar:OneEach:PlayerCountOpponents$Amount
|
||||||
|
Oracle:Prowl {3}{U} (You may cast this spell for its prowl cost if you dealt combat damage to a player this turn with a Sphinx or a Rogue.)\nFlying\nWhen Enigma Thief enters the battlefield, for each opponent, return up to one target nonland permanent that player controls to its owner’s hand.
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user