mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 04:38:00 +00:00
Merge remote-tracking branch 'upstream/master' into deck-importer-decks-file-format
This commit is contained in:
@@ -67,7 +67,7 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void reinitializeFromRules(CardRules newRules) {
|
void reinitializeFromRules(CardRules newRules) {
|
||||||
if(!newRules.getName().equals(this.getName()))
|
if (!newRules.getName().equals(this.getName()))
|
||||||
throw new UnsupportedOperationException("You cannot rename the card using the same CardRules object");
|
throw new UnsupportedOperationException("You cannot rename the card using the same CardRules object");
|
||||||
|
|
||||||
splitType = newRules.splitType;
|
splitType = newRules.splitType;
|
||||||
@@ -91,7 +91,7 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
int len = oracleText.length();
|
int len = oracleText.length();
|
||||||
for(int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
char c = oracleText.charAt(i); // This is to avoid needless allocations performed by toCharArray()
|
char c = oracleText.charAt(i); // This is to avoid needless allocations performed by toCharArray()
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case('('): isReminder = i > 0; break; // if oracle has only reminder, consider it valid rules (basic and true lands need this)
|
case('('): isReminder = i > 0; break; // if oracle has only reminder, consider it valid rules (basic and true lands need this)
|
||||||
@@ -99,7 +99,7 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
case('{'): isSymbol = true; break;
|
case('{'): isSymbol = true; break;
|
||||||
case('}'): isSymbol = false; break;
|
case('}'): isSymbol = false; break;
|
||||||
default:
|
default:
|
||||||
if(isSymbol && !isReminder) {
|
if (isSymbol && !isReminder) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case('W'): res |= MagicColor.WHITE; break;
|
case('W'): res |= MagicColor.WHITE; break;
|
||||||
case('U'): res |= MagicColor.BLUE; break;
|
case('U'): res |= MagicColor.BLUE; break;
|
||||||
@@ -317,7 +317,7 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
/** Instantiates class, reads a card. For batch operations better create you own reader instance. */
|
/** Instantiates class, reads a card. For batch operations better create you own reader instance. */
|
||||||
public static CardRules fromScript(Iterable<String> script) {
|
public static CardRules fromScript(Iterable<String> script) {
|
||||||
Reader crr = new Reader();
|
Reader crr = new Reader();
|
||||||
for(String line : script) {
|
for (String line : script) {
|
||||||
crr.parseLine(line);
|
crr.parseLine(line);
|
||||||
}
|
}
|
||||||
return crr.getCard();
|
return crr.getCard();
|
||||||
|
|||||||
@@ -270,7 +270,6 @@ public final class CardRulesPredicates {
|
|||||||
return new PredicateSuperType(type, isEqual);
|
return new PredicateSuperType(type, isEqual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks for color.
|
* Checks for color.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ public final class PaperCard implements Comparable<IPaperCard>, InventoryItemFro
|
|||||||
artIndex = Math.max(artIndex0, IPaperCard.DEFAULT_ART_INDEX);
|
artIndex = Math.max(artIndex0, IPaperCard.DEFAULT_ART_INDEX);
|
||||||
foil = foil0;
|
foil = foil0;
|
||||||
rarity = rarity0;
|
rarity = rarity0;
|
||||||
artist = (artist0 != null ? artist0 : IPaperCard.NO_ARTIST_NAME);
|
artist = (artist0 != null ? TextUtil.normalizeText(artist0) : IPaperCard.NO_ARTIST_NAME);
|
||||||
collectorNumber = (collectorNumber0 != null) && (collectorNumber0.length() > 0) ? collectorNumber0 : IPaperCard.NO_COLLECTOR_NUMBER;
|
collectorNumber = (collectorNumber0 != null) && (collectorNumber0.length() > 0) ? collectorNumber0 : IPaperCard.NO_COLLECTOR_NUMBER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ public class PaperToken implements InventoryItemFromSet, IPaperCard {
|
|||||||
String formatEdition = null == edition || CardEdition.UNKNOWN == edition ? "" : "_" + edition.getCode().toLowerCase();
|
String formatEdition = null == edition || CardEdition.UNKNOWN == edition ? "" : "_" + edition.getCode().toLowerCase();
|
||||||
|
|
||||||
this.imageFileName.add(String.format("%s%s", imageFileName, formatEdition));
|
this.imageFileName.add(String.format("%s%s", imageFileName, formatEdition));
|
||||||
for(int idx = 2; idx <= this.artIndex; idx++) {
|
for (int idx = 2; idx <= this.artIndex; idx++) {
|
||||||
this.imageFileName.add(String.format("%s%d%s", imageFileName, idx, formatEdition));
|
this.imageFileName.add(String.format("%s%d%s", imageFileName, idx, formatEdition));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class TokenDb implements ITokenDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void preloadTokens() {
|
public void preloadTokens() {
|
||||||
for(CardEdition edition : this.editions) {
|
for (CardEdition edition : this.editions) {
|
||||||
for (String name : edition.getTokens().keySet()) {
|
for (String name : edition.getTokens().keySet()) {
|
||||||
try {
|
try {
|
||||||
getToken(name, edition.getCode());
|
getToken(name, edition.getCode());
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package forge.util;
|
package forge.util;
|
||||||
|
|
||||||
|
import java.text.Normalizer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import forge.item.IPaperCard;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@@ -27,14 +29,19 @@ public class TextUtil {
|
|||||||
.put(10, "X").put(9, "IX")
|
.put(10, "X").put(9, "IX")
|
||||||
.put(5, "V").put(4, "IV").put(1, "I").build();
|
.put(5, "V").put(4, "IV").put(1, "I").build();
|
||||||
|
|
||||||
public final static String toRoman(int number) {
|
public static String toRoman(int number) {
|
||||||
if (number <= 0) {
|
if (number <= 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
int l = romanMap.floorKey(number);
|
int l = romanMap.floorKey(number);
|
||||||
return romanMap.get(l) + toRoman(number-l);
|
return romanMap.get(l) + toRoman(number-l);
|
||||||
}
|
}
|
||||||
|
public static String normalizeText(String text) {
|
||||||
|
if (text == null)
|
||||||
|
return IPaperCard.NO_ARTIST_NAME;
|
||||||
|
return Normalizer.normalize(text, Normalizer.Form.NFD);
|
||||||
|
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Safely converts an object to a String.
|
* Safely converts an object to a String.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -175,7 +175,29 @@ public final class GameActionUtil {
|
|||||||
for (final KeywordInterface inst : source.getKeywords()) {
|
for (final KeywordInterface inst : source.getKeywords()) {
|
||||||
final String keyword = inst.getOriginal();
|
final String keyword = inst.getOriginal();
|
||||||
|
|
||||||
if (keyword.startsWith("Escape")) {
|
if (keyword.startsWith("Disturb")) {
|
||||||
|
final String[] k = keyword.split(":");
|
||||||
|
final Cost disturbCost = new Cost(k[1], true);
|
||||||
|
|
||||||
|
final SpellAbility newSA = sa.copyWithManaCostReplaced(activator, disturbCost);
|
||||||
|
newSA.setActivatingPlayer(activator);
|
||||||
|
|
||||||
|
newSA.putParam("PrecostDesc", "Disturb —");
|
||||||
|
newSA.putParam("CostDesc", disturbCost.toString());
|
||||||
|
|
||||||
|
// makes new SpellDescription
|
||||||
|
final StringBuilder desc = new StringBuilder();
|
||||||
|
desc.append(newSA.getCostDescription());
|
||||||
|
desc.append("(").append(inst.getReminderText()).append(")");
|
||||||
|
newSA.setDescription(desc.toString());
|
||||||
|
newSA.putParam("AfterDescription", "(Disturbed)");
|
||||||
|
|
||||||
|
newSA.setAlternativeCost(AlternativeCost.Disturb);
|
||||||
|
newSA.getRestrictions().setZone(ZoneType.Graveyard);
|
||||||
|
newSA.setCardState(source.getAlternateState());
|
||||||
|
|
||||||
|
alternatives.add(newSA);
|
||||||
|
} else if (keyword.startsWith("Escape")) {
|
||||||
final String[] k = keyword.split(":");
|
final String[] k = keyword.split(":");
|
||||||
final Cost escapeCost = new Cost(k[1], true);
|
final Cost escapeCost = new Cost(k[1], true);
|
||||||
|
|
||||||
@@ -211,6 +233,13 @@ public final class GameActionUtil {
|
|||||||
if (keyword.contains(":")) {
|
if (keyword.contains(":")) {
|
||||||
final String[] k = keyword.split(":");
|
final String[] k = keyword.split(":");
|
||||||
flashback.setPayCosts(new Cost(k[1], false));
|
flashback.setPayCosts(new Cost(k[1], false));
|
||||||
|
String extra = k.length > 2 ? k[2] : "";
|
||||||
|
if (!extra.isEmpty()) {
|
||||||
|
String[] parts = extra.split("\\$");
|
||||||
|
String key = parts[0];
|
||||||
|
String value = parts[1];
|
||||||
|
flashback.putParam(key, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
alternatives.add(flashback);
|
alternatives.add(flashback);
|
||||||
} else if (keyword.startsWith("Foretell")) {
|
} else if (keyword.startsWith("Foretell")) {
|
||||||
|
|||||||
@@ -166,7 +166,6 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect {
|
|||||||
Map<AbilityKey, Object> moveParams = Maps.newEnumMap(AbilityKey.class);
|
Map<AbilityKey, Object> moveParams = Maps.newEnumMap(AbilityKey.class);
|
||||||
|
|
||||||
if (destination == ZoneType.Battlefield) {
|
if (destination == ZoneType.Battlefield) {
|
||||||
|
|
||||||
if (sa.hasAdditionalAbility("AnimateSubAbility")) {
|
if (sa.hasAdditionalAbility("AnimateSubAbility")) {
|
||||||
// need LKI before Animate does apply
|
// need LKI before Animate does apply
|
||||||
moveParams.put(AbilityKey.CardLKI, CardUtil.getLKICopy(c));
|
moveParams.put(AbilityKey.CardLKI, CardUtil.getLKICopy(c));
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package forge.game.ability.effects;
|
package forge.game.ability.effects;
|
||||||
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
@@ -40,7 +39,7 @@ public class LifeGainEffect extends SpellAbilityEffect {
|
|||||||
final int lifeAmount = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("LifeAmount"), sa);
|
final int lifeAmount = AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("LifeAmount"), sa);
|
||||||
|
|
||||||
List<Player> tgtPlayers = getDefinedPlayersOrTargeted(sa);
|
List<Player> tgtPlayers = getDefinedPlayersOrTargeted(sa);
|
||||||
if( tgtPlayers.isEmpty() ) {
|
if (tgtPlayers.isEmpty()) {
|
||||||
tgtPlayers.add(sa.getActivatingPlayer());
|
tgtPlayers.add(sa.getActivatingPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1943,7 +1943,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
} else {
|
} else {
|
||||||
sbLong.append(parts[0]).append(" ").append(ManaCostParser.parse(parts[1])).append("\r\n");
|
sbLong.append(parts[0]).append(" ").append(ManaCostParser.parse(parts[1])).append("\r\n");
|
||||||
}
|
}
|
||||||
} else if (keyword.startsWith("Morph") || keyword.startsWith("Megamorph") || keyword.startsWith("Escape") || keyword.startsWith("Foretell:")) {
|
} else if (keyword.startsWith("Morph") || keyword.startsWith("Megamorph")
|
||||||
|
|| keyword.startsWith("Escape") || keyword.startsWith("Foretell:")
|
||||||
|
|| keyword.startsWith("Disturb")) {
|
||||||
String[] k = keyword.split(":");
|
String[] k = keyword.split(":");
|
||||||
sbLong.append(k[0]);
|
sbLong.append(k[0]);
|
||||||
if (k.length > 1) {
|
if (k.length > 1) {
|
||||||
@@ -2033,7 +2035,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
} else if (keyword.equals("Provoke") || keyword.equals("Ingest") || keyword.equals("Unleash")
|
} else if (keyword.equals("Provoke") || keyword.equals("Ingest") || keyword.equals("Unleash")
|
||||||
|| keyword.equals("Soulbond") || keyword.equals("Partner") || keyword.equals("Retrace")
|
|| keyword.equals("Soulbond") || keyword.equals("Partner") || keyword.equals("Retrace")
|
||||||
|| keyword.equals("Living Weapon") || keyword.equals("Myriad") || keyword.equals("Exploit")
|
|| keyword.equals("Living Weapon") || keyword.equals("Myriad") || keyword.equals("Exploit")
|
||||||
|| keyword.equals("Changeling") || keyword.equals("Delve")
|
|| keyword.equals("Changeling") || keyword.equals("Delve") || keyword.equals("Decayed")
|
||||||
|| keyword.equals("Split second") || keyword.equals("Sunburst")
|
|| keyword.equals("Split second") || keyword.equals("Sunburst")
|
||||||
|| keyword.equals("Suspend") // for the ones without amount
|
|| keyword.equals("Suspend") // for the ones without amount
|
||||||
|| keyword.equals("Foretell") // for the ones without cost
|
|| keyword.equals("Foretell") // for the ones without cost
|
||||||
@@ -2544,7 +2546,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
|
|||||||
sbBefore.append("\r\n");
|
sbBefore.append("\r\n");
|
||||||
} else if (keyword.startsWith("Entwine") || keyword.startsWith("Madness")
|
} else if (keyword.startsWith("Entwine") || keyword.startsWith("Madness")
|
||||||
|| keyword.startsWith("Miracle") || keyword.startsWith("Recover")
|
|| keyword.startsWith("Miracle") || keyword.startsWith("Recover")
|
||||||
|| keyword.startsWith("Escape") || keyword.startsWith("Foretell:")) {
|
|| keyword.startsWith("Escape") || keyword.startsWith("Foretell:")
|
||||||
|
|| keyword.startsWith("Disturb")) {
|
||||||
final String[] k = keyword.split(":");
|
final String[] k = keyword.split(":");
|
||||||
final Cost cost = new Cost(k[1], false);
|
final Cost cost = new Cost(k[1], false);
|
||||||
|
|
||||||
|
|||||||
@@ -968,6 +968,26 @@ public class CardFactoryUtil {
|
|||||||
trigger.setOverridingAbility(AbilityFactory.getAbility(effect, card));
|
trigger.setOverridingAbility(AbilityFactory.getAbility(effect, card));
|
||||||
|
|
||||||
inst.addTrigger(trigger);
|
inst.addTrigger(trigger);
|
||||||
|
} else if (keyword.equals("Decayed")) {
|
||||||
|
final String attackTrig = "Mode$ Attacks | ValidCard$ Card.Self | Secondary$ True | TriggerDescription$ " +
|
||||||
|
"When a creature with decayed attacks, sacrifice it at end of combat.";
|
||||||
|
|
||||||
|
final String delayTrigStg = "DB$ DelayedTrigger | Mode$ Phase | Phase$ EndCombat | ValidPlayer$ Player | " +
|
||||||
|
"TriggerDescription$ At end of combat, sacrifice CARDNAME.";
|
||||||
|
|
||||||
|
final String trigSacStg = "DB$ SacrificeAll | Defined$ Self | Controller$ You";
|
||||||
|
|
||||||
|
SpellAbility delayTrigSA = AbilityFactory.getAbility(delayTrigStg, card);
|
||||||
|
|
||||||
|
AbilitySub sacSA = (AbilitySub) AbilityFactory.getAbility(trigSacStg, card);
|
||||||
|
delayTrigSA.setAdditionalAbility("Execute", sacSA);
|
||||||
|
|
||||||
|
final Trigger parsedTrigger = TriggerHandler.parseTrigger(attackTrig, card, intrinsic);
|
||||||
|
|
||||||
|
delayTrigSA.setIntrinsic(intrinsic);
|
||||||
|
|
||||||
|
parsedTrigger.setOverridingAbility(delayTrigSA);
|
||||||
|
inst.addTrigger(parsedTrigger);
|
||||||
} else if (keyword.equals("Demonstrate")) {
|
} else if (keyword.equals("Demonstrate")) {
|
||||||
final String trigScript = "Mode$ SpellCast | ValidCard$ Card.Self | TriggerDescription$ Demonstrate (" + inst.getReminderText() + ")";
|
final String trigScript = "Mode$ SpellCast | ValidCard$ Card.Self | TriggerDescription$ Demonstrate (" + inst.getReminderText() + ")";
|
||||||
final String youCopyStr = "DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True | Optional$ True | RememberCopies$ True";
|
final String youCopyStr = "DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True | Optional$ True | RememberCopies$ True";
|
||||||
@@ -2150,16 +2170,20 @@ public class CardFactoryUtil {
|
|||||||
sb.append("Event$ Moved | ValidCard$ Card.Self | Origin$ Stack | ExcludeDestination$ Exile ");
|
sb.append("Event$ Moved | ValidCard$ Card.Self | Origin$ Stack | ExcludeDestination$ Exile ");
|
||||||
sb.append("| ValidStackSa$ Spell.Flashback | Description$ Flashback");
|
sb.append("| ValidStackSa$ Spell.Flashback | Description$ Flashback");
|
||||||
|
|
||||||
if (keyword.contains(":")) {
|
if (keyword.contains(":")) { // K:Flashback:Cost:ExtraParam(Key$Value):ExtraDescription
|
||||||
final String[] k = keyword.split(":");
|
final String[] k = keyword.split(":");
|
||||||
final Cost cost = new Cost(k[1], false);
|
final Cost cost = new Cost(k[1], false);
|
||||||
sb.append( cost.isOnlyManaCost() ? " " : "—");
|
sb.append(cost.isOnlyManaCost() ? " " : "—");
|
||||||
|
|
||||||
sb.append(cost.toSimpleString());
|
sb.append(cost.toSimpleString());
|
||||||
|
|
||||||
if (!cost.isOnlyManaCost()) {
|
if (!cost.isOnlyManaCost()) {
|
||||||
sb.append(".");
|
sb.append(".");
|
||||||
}
|
}
|
||||||
|
String extraDesc = k.length > 3 ? k[3] : "";
|
||||||
|
if (!extraDesc.isEmpty()) {
|
||||||
|
sb.append(". ").append(extraDesc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.append(" (");
|
sb.append(" (");
|
||||||
@@ -3400,6 +3424,10 @@ public class CardFactoryUtil {
|
|||||||
}
|
}
|
||||||
} else if (keyword.startsWith("Dash")) {
|
} else if (keyword.startsWith("Dash")) {
|
||||||
effect = "Mode$ Continuous | Affected$ Card.Self+dashed | AddKeyword$ Haste";
|
effect = "Mode$ Continuous | Affected$ Card.Self+dashed | AddKeyword$ Haste";
|
||||||
|
} else if (keyword.equals("Decayed")) {
|
||||||
|
effect = "Mode$ Continuous | Affected$ Card.Self | AddHiddenKeyword$ CARDNAME can't block. | " +
|
||||||
|
"Secondary$ True";
|
||||||
|
svars.put("SacrificeEndCombat", "True");
|
||||||
} else if (keyword.equals("Defender")) {
|
} else if (keyword.equals("Defender")) {
|
||||||
effect = "Mode$ CantAttack | ValidCard$ Card.Self | DefenderKeyword$ True | Secondary$ True";
|
effect = "Mode$ CantAttack | ValidCard$ Card.Self | DefenderKeyword$ True | Secondary$ True";
|
||||||
} else if (keyword.equals("Devoid")) {
|
} else if (keyword.equals("Devoid")) {
|
||||||
|
|||||||
@@ -832,7 +832,7 @@ public class CardProperty {
|
|||||||
return Iterables.any(CardUtil.getThisTurnCast("Card", source, spellAbility), CardPredicates.sharesNameWith(card));
|
return Iterables.any(CardUtil.getThisTurnCast("Card", source, spellAbility), CardPredicates.sharesNameWith(card));
|
||||||
} else if (restriction.equals("MovedToGrave")) {
|
} else if (restriction.equals("MovedToGrave")) {
|
||||||
if (!(spellAbility instanceof SpellAbility)) {
|
if (!(spellAbility instanceof SpellAbility)) {
|
||||||
final SpellAbility root = ((SpellAbility)spellAbility).getRootAbility();
|
final SpellAbility root = ((SpellAbility) spellAbility).getRootAbility();
|
||||||
if (root != null && (root.getPaidList("MovedToGrave") != null)
|
if (root != null && (root.getPaidList("MovedToGrave") != null)
|
||||||
&& !root.getPaidList("MovedToGrave").isEmpty()) {
|
&& !root.getPaidList("MovedToGrave").isEmpty()) {
|
||||||
final CardCollectionView cards = root.getPaidList("MovedToGrave");
|
final CardCollectionView cards = root.getPaidList("MovedToGrave");
|
||||||
@@ -855,7 +855,7 @@ public class CardProperty {
|
|||||||
if (!(spellAbility instanceof SpellAbility)) {
|
if (!(spellAbility instanceof SpellAbility)) {
|
||||||
System.out.println("Looking at TriggeredCard but no SA?");
|
System.out.println("Looking at TriggeredCard but no SA?");
|
||||||
} else {
|
} else {
|
||||||
Card triggeredCard = ((Card)((SpellAbility)spellAbility).getTriggeringObject(AbilityKey.Card));
|
Card triggeredCard = ((Card) ((SpellAbility) spellAbility).getTriggeringObject(AbilityKey.Card));
|
||||||
if (triggeredCard != null && card.sharesNameWith(triggeredCard)) {
|
if (triggeredCard != null && card.sharesNameWith(triggeredCard)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -924,10 +924,9 @@ public class CardProperty {
|
|||||||
}
|
}
|
||||||
} else if (property.startsWith("SecondSpellCastThisTurn")) {
|
} else if (property.startsWith("SecondSpellCastThisTurn")) {
|
||||||
final List<Card> cards = CardUtil.getThisTurnCast("Card", source, spellAbility);
|
final List<Card> cards = CardUtil.getThisTurnCast("Card", source, spellAbility);
|
||||||
if (cards.size() < 2) {
|
if (cards.size() < 2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
} else if (cards.get(1) != card) {
|
||||||
else if (cards.get(1) != card) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.equals("ThisTurnCast")) {
|
} else if (property.equals("ThisTurnCast")) {
|
||||||
@@ -1232,8 +1231,7 @@ public class CardProperty {
|
|||||||
if (!cards.contains(card)) {
|
if (!cards.contains(card)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
} else if (property.startsWith("lowestCMC")) {
|
||||||
else if (property.startsWith("lowestCMC")) {
|
|
||||||
final CardCollectionView cards = game.getCardsIn(ZoneType.Battlefield);
|
final CardCollectionView cards = game.getCardsIn(ZoneType.Battlefield);
|
||||||
for (final Card crd : cards) {
|
for (final Card crd : cards) {
|
||||||
if (!crd.isLand() && !crd.isImmutable()) {
|
if (!crd.isLand() && !crd.isImmutable()) {
|
||||||
@@ -1369,9 +1367,7 @@ public class CardProperty {
|
|||||||
if (!Expressions.compare(y, property, x)) {
|
if (!Expressions.compare(y, property, x)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
} else if (property.startsWith("ManaCost")) {
|
||||||
|
|
||||||
else if (property.startsWith("ManaCost")) {
|
|
||||||
if (!card.getManaCost().getShortString().equals(property.substring(8))) {
|
if (!card.getManaCost().getShortString().equals(property.substring(8))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1412,7 +1408,7 @@ public class CardProperty {
|
|||||||
// These predicated refer to ongoing combat. If no combat happens, they'll return false (meaning not attacking/blocking ATM)
|
// These predicated refer to ongoing combat. If no combat happens, they'll return false (meaning not attacking/blocking ATM)
|
||||||
else if (property.startsWith("attacking")) {
|
else if (property.startsWith("attacking")) {
|
||||||
if (null == combat) return false;
|
if (null == combat) return false;
|
||||||
if (property.equals("attacking")) return card.isAttacking();
|
if (property.equals("attacking")) return card.isAttacking();
|
||||||
if (property.equals("attackingYou")) return combat.isAttacking(card, sourceController);
|
if (property.equals("attackingYou")) return combat.isAttacking(card, sourceController);
|
||||||
if (property.equals("attackingSame")) {
|
if (property.equals("attackingSame")) {
|
||||||
final GameEntity attacked = combat.getDefenderByAttacker(source);
|
final GameEntity attacked = combat.getDefenderByAttacker(source);
|
||||||
@@ -1424,10 +1420,10 @@ public class CardProperty {
|
|||||||
GameEntity defender = combat.getDefenderByAttacker(card);
|
GameEntity defender = combat.getDefenderByAttacker(card);
|
||||||
if (defender instanceof Card) {
|
if (defender instanceof Card) {
|
||||||
// attack on a planeswalker that was removed from combat
|
// attack on a planeswalker that was removed from combat
|
||||||
if (!((Card)defender).isPlaneswalker()) {
|
if (!((Card) defender).isPlaneswalker()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
defender = ((Card)defender).getController();
|
defender = ((Card) defender).getController();
|
||||||
}
|
}
|
||||||
if (!sourceController.equals(defender)) {
|
if (!sourceController.equals(defender)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1471,12 +1467,17 @@ public class CardProperty {
|
|||||||
if (combat.isBlocking(card, c)) {
|
if (combat.isBlocking(card, c)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (property.startsWith("sharesBlockingAssignmentWith")) {
|
} else if (property.startsWith("sharesBlockingAssignmentWith")) {
|
||||||
if (null == combat) { return false; }
|
if (null == combat) {
|
||||||
if (null == combat.getAttackersBlockedBy(source) || null == combat.getAttackersBlockedBy(card)) { return false; }
|
return false;
|
||||||
|
}
|
||||||
|
if (null == combat.getAttackersBlockedBy(source) || null == combat.getAttackersBlockedBy(card)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
CardCollection sourceBlocking = new CardCollection(combat.getAttackersBlockedBy(source));
|
CardCollection sourceBlocking = new CardCollection(combat.getAttackersBlockedBy(source));
|
||||||
CardCollection thisBlocking = new CardCollection(combat.getAttackersBlockedBy(card));
|
CardCollection thisBlocking = new CardCollection(combat.getAttackersBlockedBy(card));
|
||||||
@@ -1503,16 +1504,17 @@ public class CardProperty {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String valid = property.split(" ")[1];
|
String valid = property.split(" ")[1];
|
||||||
for(Card c : blocked) {
|
for (Card c : blocked) {
|
||||||
if (c.isValid(valid, card.getController(), source, spellAbility)) {
|
if (c.isValid(valid, card.getController(), source, spellAbility)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(Card c : AbilityUtils.getDefinedCards(source, valid, spellAbility)) {
|
for (Card c : AbilityUtils.getDefinedCards(source, valid, spellAbility)) {
|
||||||
if (blocked.contains(c)) {
|
if (blocked.contains(c)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
;
|
||||||
return false;
|
return false;
|
||||||
} else if (property.startsWith("blockedByValidThisTurn ")) {
|
} else if (property.startsWith("blockedByValidThisTurn ")) {
|
||||||
CardCollectionView blocked = card.getBlockedByThisTurn();
|
CardCollectionView blocked = card.getBlockedByThisTurn();
|
||||||
@@ -1527,7 +1529,8 @@ public class CardProperty {
|
|||||||
if (blocked.contains(c)) {
|
if (blocked.contains(c)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
;
|
||||||
return false;
|
return false;
|
||||||
} else if (property.startsWith("blockedBySourceThisTurn")) {
|
} else if (property.startsWith("blockedBySourceThisTurn")) {
|
||||||
return source.getBlockedByThisTurn().contains(card);
|
return source.getBlockedByThisTurn().contains(card);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import forge.game.spellability.SpellAbility;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
@@ -821,7 +822,7 @@ public class CardView extends GameEntityView {
|
|||||||
updateZoneText(c);
|
updateZoneText(c);
|
||||||
updateDamage(c);
|
updateDamage(c);
|
||||||
|
|
||||||
if (getBackup() == null && !c.isFaceDown() && c.hasBackSide()) {
|
if (getBackup() == null && !c.isFaceDown() && (c.hasBackSide()||c.isFlipCard()||c.isAdventureCard())) {
|
||||||
set(TrackableProperty.PaperCardBackup, c.getPaperCard());
|
set(TrackableProperty.PaperCardBackup, c.getPaperCard());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1300,6 +1301,37 @@ public class CardView extends GameEntityView {
|
|||||||
public boolean hasLandwalk() {
|
public boolean hasLandwalk() {
|
||||||
return get(TrackableProperty.HasLandwalk);
|
return get(TrackableProperty.HasLandwalk);
|
||||||
}
|
}
|
||||||
|
public boolean hasHasAftermath() {
|
||||||
|
return get(TrackableProperty.HasAftermath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean origProduceAnyMana() {
|
||||||
|
return get(TrackableProperty.OrigProduceAnyMana);
|
||||||
|
}
|
||||||
|
public boolean origProduceManaR() {
|
||||||
|
return get(TrackableProperty.OrigProduceManaR);
|
||||||
|
}
|
||||||
|
public boolean origProduceManaG() {
|
||||||
|
return get(TrackableProperty.OrigProduceManaG);
|
||||||
|
}
|
||||||
|
public boolean origProduceManaB() {
|
||||||
|
return get(TrackableProperty.OrigProduceManaB);
|
||||||
|
}
|
||||||
|
public boolean origProduceManaU() {
|
||||||
|
return get(TrackableProperty.OrigProduceManaU);
|
||||||
|
}
|
||||||
|
public boolean origProduceManaW() {
|
||||||
|
return get(TrackableProperty.OrigProduceManaW);
|
||||||
|
}
|
||||||
|
public boolean origProduceManaC() {
|
||||||
|
return get(TrackableProperty.OrigProduceManaC);
|
||||||
|
}
|
||||||
|
public int origCanProduceColoredMana() {
|
||||||
|
return get(TrackableProperty.CountOrigProduceColoredMana);
|
||||||
|
}
|
||||||
|
public int countBasicLandTypes() {
|
||||||
|
return get(TrackableProperty.CountBasicLandTypes);
|
||||||
|
}
|
||||||
|
|
||||||
public String getAbilityText() {
|
public String getAbilityText() {
|
||||||
return get(TrackableProperty.AbilityText);
|
return get(TrackableProperty.AbilityText);
|
||||||
@@ -1333,6 +1365,7 @@ public class CardView extends GameEntityView {
|
|||||||
set(TrackableProperty.HasInfect, c.hasKeyword(Keyword.INFECT, state));
|
set(TrackableProperty.HasInfect, c.hasKeyword(Keyword.INFECT, state));
|
||||||
set(TrackableProperty.HasStorm, c.hasKeyword(Keyword.STORM, state));
|
set(TrackableProperty.HasStorm, c.hasKeyword(Keyword.STORM, state));
|
||||||
set(TrackableProperty.HasLandwalk, c.hasKeyword(Keyword.LANDWALK, state));
|
set(TrackableProperty.HasLandwalk, c.hasKeyword(Keyword.LANDWALK, state));
|
||||||
|
set(TrackableProperty.HasAftermath, c.hasKeyword(Keyword.AFTERMATH, state));
|
||||||
updateAbilityText(c, state);
|
updateAbilityText(c, state);
|
||||||
//set protectionKey for Icons
|
//set protectionKey for Icons
|
||||||
set(TrackableProperty.ProtectionKey, c.getProtectionKey());
|
set(TrackableProperty.ProtectionKey, c.getProtectionKey());
|
||||||
@@ -1340,6 +1373,84 @@ public class CardView extends GameEntityView {
|
|||||||
set(TrackableProperty.HexproofKey, c.getHexproofKey());
|
set(TrackableProperty.HexproofKey, c.getHexproofKey());
|
||||||
//keywordkey
|
//keywordkey
|
||||||
set(TrackableProperty.KeywordKey, c.getKeywordKey());
|
set(TrackableProperty.KeywordKey, c.getKeywordKey());
|
||||||
|
//update Trackable Mana Color for BG Colors
|
||||||
|
updateManaColorBG(state);
|
||||||
|
}
|
||||||
|
void updateManaColorBG(CardState state) {
|
||||||
|
boolean anyMana = false;
|
||||||
|
boolean rMana = false;
|
||||||
|
boolean gMana = false;
|
||||||
|
boolean bMana = false;
|
||||||
|
boolean uMana = false;
|
||||||
|
boolean wMana = false;
|
||||||
|
boolean cMana = false;
|
||||||
|
int count = 0;
|
||||||
|
int basicLandTypes = 0;
|
||||||
|
if (!state.getManaAbilities().isEmpty()) {
|
||||||
|
for (SpellAbility sa : state.getManaAbilities()) {
|
||||||
|
if (sa == null || sa.getManaPart() == null)
|
||||||
|
continue;
|
||||||
|
if (sa.getManaPart().isAnyMana()) {
|
||||||
|
anyMana = true;
|
||||||
|
}
|
||||||
|
switch (sa.getManaPart().getOrigProduced()) {
|
||||||
|
case "R":
|
||||||
|
if (!rMana) {
|
||||||
|
count += 1;
|
||||||
|
rMana = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "G":
|
||||||
|
if (!gMana) {
|
||||||
|
count += 1;
|
||||||
|
gMana = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "B":
|
||||||
|
if (!bMana) {
|
||||||
|
count += 1;
|
||||||
|
bMana = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "U":
|
||||||
|
if (!uMana) {
|
||||||
|
count += 1;
|
||||||
|
uMana = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "W":
|
||||||
|
if (!wMana) {
|
||||||
|
count += 1;
|
||||||
|
wMana = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "C":
|
||||||
|
if (!cMana) {
|
||||||
|
cMana = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isForest())
|
||||||
|
basicLandTypes += 1;
|
||||||
|
if (isMountain())
|
||||||
|
basicLandTypes += 1;
|
||||||
|
if (isSwamp())
|
||||||
|
basicLandTypes += 1;
|
||||||
|
if (isPlains())
|
||||||
|
basicLandTypes += 1;
|
||||||
|
if (isIsland())
|
||||||
|
basicLandTypes += 1;
|
||||||
|
set(TrackableProperty.CountBasicLandTypes, basicLandTypes);
|
||||||
|
set(TrackableProperty.OrigProduceManaR, rMana);
|
||||||
|
set(TrackableProperty.OrigProduceManaG, gMana);
|
||||||
|
set(TrackableProperty.OrigProduceManaB, bMana);
|
||||||
|
set(TrackableProperty.OrigProduceManaU, uMana);
|
||||||
|
set(TrackableProperty.OrigProduceManaW, wMana);
|
||||||
|
set(TrackableProperty.OrigProduceManaC, cMana);
|
||||||
|
set(TrackableProperty.CountOrigProduceColoredMana, count);
|
||||||
|
set(TrackableProperty.OrigProduceAnyMana, anyMana);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBasicLand() {
|
public boolean isBasicLand() {
|
||||||
@@ -1375,6 +1486,12 @@ public class CardView extends GameEntityView {
|
|||||||
public boolean isIsland() {
|
public boolean isIsland() {
|
||||||
return getType().hasSubtype("Island");
|
return getType().hasSubtype("Island");
|
||||||
}
|
}
|
||||||
|
public boolean isVehicle() {
|
||||||
|
return getType().hasSubtype("Vehicle");
|
||||||
|
}
|
||||||
|
public boolean isArtifact() {
|
||||||
|
return getType().isArtifact();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//special methods for updating card and player properties as needed and returning the new collection
|
//special methods for updating card and player properties as needed and returning the new collection
|
||||||
|
|||||||
@@ -89,7 +89,6 @@ public class TokenCreateTable extends ForwardingTable<Player, Card, Integer> {
|
|||||||
result += c.getValue();
|
result += c.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ public class TokenInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static protected void protoTypeApplyTextChange(final Card result, final SpellAbility sa) {
|
static protected void protoTypeApplyTextChange(final Card result, final SpellAbility sa) {
|
||||||
// update Token with CardTextChanges
|
// update Token with CardTextChanges
|
||||||
Map<String, String> colorMap = sa.getChangedTextColors();
|
Map<String, String> colorMap = sa.getChangedTextColors();
|
||||||
Map<String, String> typeMap = sa.getChangedTextTypes();
|
Map<String, String> typeMap = sa.getChangedTextTypes();
|
||||||
if (!colorMap.isEmpty()) {
|
if (!colorMap.isEmpty()) {
|
||||||
|
|||||||
@@ -46,12 +46,14 @@ public enum Keyword {
|
|||||||
CYCLING("Cycling", KeywordWithCost.class, false, "%s, Discard this card: Draw a card."), //Typecycling reminder text handled by Cycling class
|
CYCLING("Cycling", KeywordWithCost.class, false, "%s, Discard this card: Draw a card."), //Typecycling reminder text handled by Cycling class
|
||||||
DASH("Dash", KeywordWithCost.class, false, "You may cast this spell for its dash cost. If you do, it gains haste, and it's returned from the battlefield to its owner's hand at the beginning of the next end step."),
|
DASH("Dash", KeywordWithCost.class, false, "You may cast this spell for its dash cost. If you do, it gains haste, and it's returned from the battlefield to its owner's hand at the beginning of the next end step."),
|
||||||
DEATHTOUCH("Deathtouch", SimpleKeyword.class, true, "Any amount of damage this deals to a creature is enough to destroy it."),
|
DEATHTOUCH("Deathtouch", SimpleKeyword.class, true, "Any amount of damage this deals to a creature is enough to destroy it."),
|
||||||
|
DECAYED("Decayed", SimpleKeyword.class, true, "This creature can't block. When it attacks, sacrifice it at end of combat."),
|
||||||
DEFENDER("Defender", SimpleKeyword.class, true, "This creature can't attack."),
|
DEFENDER("Defender", SimpleKeyword.class, true, "This creature can't attack."),
|
||||||
DELVE("Delve", SimpleKeyword.class, true, "As an additional cost to cast this spell, you may exile any number of cards from your graveyard. Each card exiled this way reduces the cost to cast this spell by {1}."),
|
DELVE("Delve", SimpleKeyword.class, true, "As an additional cost to cast this spell, you may exile any number of cards from your graveyard. Each card exiled this way reduces the cost to cast this spell by {1}."),
|
||||||
DEMONSTRATE("Demonstrate", SimpleKeyword.class, false, "When you cast this spell, you may copy it. If you do, choose an opponent to also copy it. Players may choose new targets for their copies."),
|
DEMONSTRATE("Demonstrate", SimpleKeyword.class, false, "When you cast this spell, you may copy it. If you do, choose an opponent to also copy it. Players may choose new targets for their copies."),
|
||||||
DETHRONE("Dethrone", SimpleKeyword.class, false, "Whenever this creature attacks the player with the most life or tied for the most life, put a +1/+1 counter on it."),
|
DETHRONE("Dethrone", SimpleKeyword.class, false, "Whenever this creature attacks the player with the most life or tied for the most life, put a +1/+1 counter on it."),
|
||||||
DEVOUR("Devour", KeywordWithAmount.class, false, "As this creature enters the battlefield, you may sacrifice any number of creatures. This creature enters the battlefield with {%d:+1/+1 counter} on it for each creature sacrificed this way."),
|
DEVOUR("Devour", KeywordWithAmount.class, false, "As this creature enters the battlefield, you may sacrifice any number of creatures. This creature enters the battlefield with {%d:+1/+1 counter} on it for each creature sacrificed this way."),
|
||||||
DEVOID("Devoid", SimpleKeyword.class, true, "This card has no color."),
|
DEVOID("Devoid", SimpleKeyword.class, true, "This card has no color."),
|
||||||
|
DISTURB("Disturb", KeywordWithCost.class, false, "You may cast this card from your graveyard transformed for its disturb cost."),
|
||||||
DOUBLE_STRIKE("Double Strike", SimpleKeyword.class, true, "This creature deals both first-strike and regular combat damage."),
|
DOUBLE_STRIKE("Double Strike", SimpleKeyword.class, true, "This creature deals both first-strike and regular combat damage."),
|
||||||
DREDGE("Dredge", KeywordWithAmount.class, false, "If you would draw a card, instead you may put exactly {%d:card} from the top of your library into your graveyard. If you do, return this card from your graveyard to your hand. Otherwise, draw a card."),
|
DREDGE("Dredge", KeywordWithAmount.class, false, "If you would draw a card, instead you may put exactly {%d:card} from the top of your library into your graveyard. If you do, return this card from your graveyard to your hand. Otherwise, draw a card."),
|
||||||
ECHO("Echo", KeywordWithCost.class, false, "At the beginning of your upkeep, if this permanent came under your control since the beginning of your last upkeep, sacrifice it unless you pay %s."),
|
ECHO("Echo", KeywordWithCost.class, false, "At the beginning of your upkeep, if this permanent came under your control since the beginning of your last upkeep, sacrifice it unless you pay %s."),
|
||||||
@@ -77,7 +79,7 @@ public enum Keyword {
|
|||||||
FIRST_STRIKE("First Strike", SimpleKeyword.class, true, "This creature deals combat damage before creatures without first strike."),
|
FIRST_STRIKE("First Strike", SimpleKeyword.class, true, "This creature deals combat damage before creatures without first strike."),
|
||||||
FLANKING("Flanking", SimpleKeyword.class, false, "Whenever this creature becomes blocked by a creature without flanking, the blocking creature gets -1/-1 until end of turn."),
|
FLANKING("Flanking", SimpleKeyword.class, false, "Whenever this creature becomes blocked by a creature without flanking, the blocking creature gets -1/-1 until end of turn."),
|
||||||
FLASH("Flash", SimpleKeyword.class, true, "You may cast this spell any time you could cast an instant."),
|
FLASH("Flash", SimpleKeyword.class, true, "You may cast this spell any time you could cast an instant."),
|
||||||
FLASHBACK("Flashback", KeywordWithCost.class, false, "You may cast this card from your graveyard by paying %s rather than paying its mana cost. If you do, exile it as it resolves."),
|
FLASHBACK("Flashback", KeywordWithCost.class, false, "You may cast this card from your graveyard for its flashback cost. Then exile it."),
|
||||||
FLYING("Flying", SimpleKeyword.class, true, "This creature can't be blocked except by creatures with flying or reach."),
|
FLYING("Flying", SimpleKeyword.class, true, "This creature can't be blocked except by creatures with flying or reach."),
|
||||||
FORETELL("Foretell", KeywordWithCost.class, false, "During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost."),
|
FORETELL("Foretell", KeywordWithCost.class, false, "During your turn, you may pay {2} and exile this card from your hand face down. Cast it on a later turn for its foretell cost."),
|
||||||
FORTIFY("Fortify", KeywordWithCost.class, false, "%s: Attach to target land you control. Fortify only as a sorcery."),
|
FORTIFY("Fortify", KeywordWithCost.class, false, "%s: Attach to target land you control. Fortify only as a sorcery."),
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ public enum AlternativeCost {
|
|||||||
Bestow,
|
Bestow,
|
||||||
Cycling, // ActivatedAbility
|
Cycling, // ActivatedAbility
|
||||||
Dash,
|
Dash,
|
||||||
|
Disturb,
|
||||||
Emerge,
|
Emerge,
|
||||||
Escape,
|
Escape,
|
||||||
Evoke,
|
Evoke,
|
||||||
|
|||||||
@@ -1370,6 +1370,10 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
return isAlternativeCost(AlternativeCost.Dash);
|
return isAlternativeCost(AlternativeCost.Dash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final boolean isDisturb() {
|
||||||
|
return isAlternativeCost(AlternativeCost.Disturb);
|
||||||
|
}
|
||||||
|
|
||||||
public final boolean isEscape() {
|
public final boolean isEscape() {
|
||||||
return isAlternativeCost(AlternativeCost.Escape);
|
return isAlternativeCost(AlternativeCost.Escape);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,18 @@ public enum TrackableProperty {
|
|||||||
HasChangedColors(TrackableTypes.BooleanType),
|
HasChangedColors(TrackableTypes.BooleanType),
|
||||||
ChangedTypes(TrackableTypes.StringMapType),
|
ChangedTypes(TrackableTypes.StringMapType),
|
||||||
|
|
||||||
|
//check produce mana for BG
|
||||||
|
OrigProduceManaR(TrackableTypes.BooleanType),
|
||||||
|
OrigProduceManaG(TrackableTypes.BooleanType),
|
||||||
|
OrigProduceManaB(TrackableTypes.BooleanType),
|
||||||
|
OrigProduceManaU(TrackableTypes.BooleanType),
|
||||||
|
OrigProduceManaW(TrackableTypes.BooleanType),
|
||||||
|
OrigProduceManaC(TrackableTypes.BooleanType),
|
||||||
|
OrigProduceAnyMana(TrackableTypes.BooleanType),
|
||||||
|
CountOrigProduceColoredMana(TrackableTypes.IntegerType),
|
||||||
|
//number of basic landtypes
|
||||||
|
CountBasicLandTypes(TrackableTypes.IntegerType),
|
||||||
|
|
||||||
KeywordKey(TrackableTypes.StringType),
|
KeywordKey(TrackableTypes.StringType),
|
||||||
HasDeathtouch(TrackableTypes.BooleanType),
|
HasDeathtouch(TrackableTypes.BooleanType),
|
||||||
HasDevoid(TrackableTypes.BooleanType),
|
HasDevoid(TrackableTypes.BooleanType),
|
||||||
@@ -132,6 +144,7 @@ public enum TrackableProperty {
|
|||||||
HasTrample(TrackableTypes.BooleanType),
|
HasTrample(TrackableTypes.BooleanType),
|
||||||
HasVigilance(TrackableTypes.BooleanType),
|
HasVigilance(TrackableTypes.BooleanType),
|
||||||
HasLandwalk(TrackableTypes.BooleanType),
|
HasLandwalk(TrackableTypes.BooleanType),
|
||||||
|
HasAftermath(TrackableTypes.BooleanType),
|
||||||
//protectionkey
|
//protectionkey
|
||||||
ProtectionKey(TrackableTypes.StringType),
|
ProtectionKey(TrackableTypes.StringType),
|
||||||
//hexproofkey
|
//hexproofkey
|
||||||
|
|||||||
@@ -472,6 +472,12 @@ public class Graphics {
|
|||||||
|
|
||||||
batch.begin();
|
batch.begin();
|
||||||
}
|
}
|
||||||
|
public void drawRectLines(float thickness, Color color, float x, float y, float w, float h) {
|
||||||
|
drawLine(thickness, color, x, y, x+w, y);
|
||||||
|
drawLine(thickness, color, x+thickness/2f, y+thickness/2f, x+thickness/2f, y+h-thickness/2f);
|
||||||
|
drawLine(thickness, color, x, y+h, x+w, y+h);
|
||||||
|
drawLine(thickness, color, x+w-thickness/2f, y+thickness/2f, x+w-thickness/2f, y+h-thickness/2f);
|
||||||
|
}
|
||||||
|
|
||||||
public void fillRect(FSkinColor skinColor, float x, float y, float w, float h) {
|
public void fillRect(FSkinColor skinColor, float x, float y, float w, float h) {
|
||||||
fillRect(skinColor.getColor(), x, y, w, h);
|
fillRect(skinColor.getColor(), x, y, w, h);
|
||||||
@@ -850,6 +856,18 @@ public class Graphics {
|
|||||||
|
|
||||||
//use nifty trick with multiple text renders to draw outlined text
|
//use nifty trick with multiple text renders to draw outlined text
|
||||||
public void drawOutlinedText(String text, FSkinFont skinFont, Color textColor, Color outlineColor, float x, float y, float w, float h, boolean wrap, int horzAlignment, boolean centerVertically) {
|
public void drawOutlinedText(String text, FSkinFont skinFont, Color textColor, Color outlineColor, float x, float y, float w, float h, boolean wrap, int horzAlignment, boolean centerVertically) {
|
||||||
|
drawOutlinedText(text, skinFont, textColor, outlineColor, x, y, w, h, wrap, horzAlignment, centerVertically, false);
|
||||||
|
}
|
||||||
|
public void drawOutlinedText(String text, FSkinFont skinFont, Color textColor, Color outlineColor, float x, float y, float w, float h, boolean wrap, int horzAlignment, boolean centerVertically, boolean shadow) {
|
||||||
|
if (shadow) {
|
||||||
|
float oldAlpha = alphaComposite;
|
||||||
|
alphaComposite = 0.4f;
|
||||||
|
drawText(text, skinFont, outlineColor, x - 1.5f, y + 1.5f, w, h, wrap, horzAlignment, centerVertically);
|
||||||
|
drawText(text, skinFont, outlineColor, x + 1.5f, y + 1.5f, w, h, wrap, horzAlignment, centerVertically);
|
||||||
|
drawText(text, skinFont, outlineColor, x + 1.5f, y - 1.5f, w, h, wrap, horzAlignment, centerVertically);
|
||||||
|
drawText(text, skinFont, outlineColor, x - 1.5f, y - 1.5f, w, h, wrap, horzAlignment, centerVertically);
|
||||||
|
alphaComposite = oldAlpha;
|
||||||
|
}
|
||||||
drawText(text, skinFont, outlineColor, x - 1, y, w, h, wrap, horzAlignment, centerVertically);
|
drawText(text, skinFont, outlineColor, x - 1, y, w, h, wrap, horzAlignment, centerVertically);
|
||||||
drawText(text, skinFont, outlineColor, x, y - 1, w, h, wrap, horzAlignment, centerVertically);
|
drawText(text, skinFont, outlineColor, x, y - 1, w, h, wrap, horzAlignment, centerVertically);
|
||||||
drawText(text, skinFont, outlineColor, x - 1, y - 1, w, h, wrap, horzAlignment, centerVertically);
|
drawText(text, skinFont, outlineColor, x - 1, y - 1, w, h, wrap, horzAlignment, centerVertically);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.badlogic.gdx.Gdx;
|
|||||||
import com.badlogic.gdx.graphics.GL20;
|
import com.badlogic.gdx.graphics.GL20;
|
||||||
import com.badlogic.gdx.graphics.Pixmap.Format;
|
import com.badlogic.gdx.graphics.Pixmap.Format;
|
||||||
import com.badlogic.gdx.graphics.Texture;
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
|
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
|
||||||
import com.badlogic.gdx.math.Matrix4;
|
import com.badlogic.gdx.math.Matrix4;
|
||||||
|
|
||||||
@@ -44,8 +45,30 @@ public abstract class FBufferedImage extends FImageComplex {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextureRegion getTextureRegion() {
|
||||||
|
return new TextureRegion(checkFrameBuffer().getColorBufferTexture());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Texture getTexture() {
|
public Texture getTexture() {
|
||||||
|
return checkFrameBuffer().getColorBufferTexture();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
final FrameBuffer fb = frameBuffer;
|
||||||
|
if (fb != null) {
|
||||||
|
frameBuffer = null;
|
||||||
|
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
fb.dispose(); //must be disposed on EDT thread
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameBuffer checkFrameBuffer() {
|
||||||
if (frameBuffer == null) {
|
if (frameBuffer == null) {
|
||||||
Gdx.gl.glDisable(GL20.GL_SCISSOR_TEST); //prevent buffered image being clipped
|
Gdx.gl.glDisable(GL20.GL_SCISSOR_TEST); //prevent buffered image being clipped
|
||||||
|
|
||||||
@@ -69,20 +92,7 @@ public abstract class FBufferedImage extends FImageComplex {
|
|||||||
|
|
||||||
Gdx.gl.glEnable(GL20.GL_SCISSOR_TEST);
|
Gdx.gl.glEnable(GL20.GL_SCISSOR_TEST);
|
||||||
}
|
}
|
||||||
return frameBuffer.getColorBufferTexture();
|
return frameBuffer;
|
||||||
}
|
|
||||||
|
|
||||||
public void clear() {
|
|
||||||
final FrameBuffer fb = frameBuffer;
|
|
||||||
if (fb != null) {
|
|
||||||
frameBuffer = null;
|
|
||||||
FThreads.invokeInEdtNowOrLater(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
fb.dispose(); //must be disposed on EDT thread
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void draw(Graphics g, float w, float h);
|
protected abstract void draw(Graphics g, float w, float h);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package forge.assets;
|
|||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.badlogic.gdx.graphics.Texture;
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
import forge.Graphics;
|
import forge.Graphics;
|
||||||
|
|
||||||
//Special wrapper for a texture to be loaded later when it's needed
|
//Special wrapper for a texture to be loaded later when it's needed
|
||||||
@@ -32,6 +33,14 @@ public class FDelayLoadImage extends FImageComplex {
|
|||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextureRegion getTextureRegion() {
|
||||||
|
if (texture == null) {
|
||||||
|
texture = new Texture(Gdx.files.absolute(filename));
|
||||||
|
}
|
||||||
|
return new TextureRegion(texture);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRegionX() {
|
public int getRegionX() {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package forge.assets;
|
package forge.assets;
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Texture;
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
|
|
||||||
public abstract class FImageComplex implements FImage {
|
public abstract class FImageComplex implements FImage {
|
||||||
public abstract Texture getTexture();
|
public abstract Texture getTexture();
|
||||||
|
public abstract TextureRegion getTextureRegion();
|
||||||
public abstract int getRegionX();
|
public abstract int getRegionX();
|
||||||
public abstract int getRegionY();
|
public abstract int getRegionY();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package forge.assets;
|
|||||||
|
|
||||||
import com.badlogic.gdx.graphics.Texture;
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
import forge.Graphics;
|
import forge.Graphics;
|
||||||
|
|
||||||
public class FRotatedImage extends FImageComplex {
|
public class FRotatedImage extends FImageComplex {
|
||||||
@@ -33,6 +34,11 @@ public class FRotatedImage extends FImageComplex {
|
|||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextureRegion getTextureRegion() {
|
||||||
|
return new TextureRegion(texture);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRegionX() {
|
public int getRegionX() {
|
||||||
return srcX;
|
return srcX;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public class FSkin {
|
|||||||
private static String preferredName;
|
private static String preferredName;
|
||||||
private static boolean loaded = false;
|
private static boolean loaded = false;
|
||||||
public static Texture hdLogo = null;
|
public static Texture hdLogo = null;
|
||||||
|
public static Texture overlay_alpha = null;
|
||||||
|
|
||||||
public static void changeSkin(final String skinName) {
|
public static void changeSkin(final String skinName) {
|
||||||
final ForgePreferences prefs = FModel.getPreferences();
|
final ForgePreferences prefs = FModel.getPreferences();
|
||||||
@@ -124,10 +125,27 @@ public class FSkin {
|
|||||||
|
|
||||||
FSkinTexture.BG_TEXTURE.load(); //load background texture early for splash screen
|
FSkinTexture.BG_TEXTURE.load(); //load background texture early for splash screen
|
||||||
|
|
||||||
|
//load theme logo while changing skins
|
||||||
|
final FileHandle theme_logo = getSkinFile("hd_logo.png");
|
||||||
|
if (theme_logo.exists()) {
|
||||||
|
Texture txOverlay = new Texture(theme_logo, true);
|
||||||
|
txOverlay.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||||
|
hdLogo = txOverlay;
|
||||||
|
} else {
|
||||||
|
hdLogo = null;
|
||||||
|
}
|
||||||
|
final FileHandle duals_overlay = getDefaultSkinFile("overlay_alpha.png");
|
||||||
|
if (duals_overlay.exists()) {
|
||||||
|
Texture txAlphaLines = new Texture(duals_overlay, true);
|
||||||
|
txAlphaLines.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
||||||
|
overlay_alpha = txAlphaLines;
|
||||||
|
} else {
|
||||||
|
overlay_alpha = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (splashScreen != null) {
|
if (splashScreen != null) {
|
||||||
final FileHandle f = getSkinFile("bg_splash.png");
|
final FileHandle f = getSkinFile("bg_splash.png");
|
||||||
final FileHandle f2 = getSkinFile("bg_splash_hd.png"); //HD Splashscreen
|
final FileHandle f2 = getSkinFile("bg_splash_hd.png"); //HD Splashscreen
|
||||||
final FileHandle f3 = getSkinFile("hd_logo.png");
|
|
||||||
|
|
||||||
if (!f.exists()) {
|
if (!f.exists()) {
|
||||||
if (!skinName.equals("default")) {
|
if (!skinName.equals("default")) {
|
||||||
@@ -149,14 +167,6 @@ public class FSkin {
|
|||||||
splashScreen.setBackground(new TextureRegion(txSplash, 0, 0, w, h - 100));
|
splashScreen.setBackground(new TextureRegion(txSplash, 0, 0, w, h - 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f3.exists()) {
|
|
||||||
Texture txOverlay = new Texture(f3, true);
|
|
||||||
txOverlay.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear);
|
|
||||||
hdLogo = txOverlay;
|
|
||||||
} else {
|
|
||||||
hdLogo = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pixmap pxSplash = new Pixmap(f);
|
Pixmap pxSplash = new Pixmap(f);
|
||||||
FProgressBar.BACK_COLOR = new Color(pxSplash.getPixel(25, h - 75));
|
FProgressBar.BACK_COLOR = new Color(pxSplash.getPixel(25, h - 75));
|
||||||
FProgressBar.FORE_COLOR = new Color(pxSplash.getPixel(75, h - 75));
|
FProgressBar.FORE_COLOR = new Color(pxSplash.getPixel(75, h - 75));
|
||||||
@@ -217,9 +227,12 @@ public class FSkin {
|
|||||||
final FileHandle f11 = getSkinFile(ForgeConstants.SPRITE_BUTTONS_FILE);
|
final FileHandle f11 = getSkinFile(ForgeConstants.SPRITE_BUTTONS_FILE);
|
||||||
final FileHandle f12 = getSkinFile(ForgeConstants.SPRITE_START_FILE);
|
final FileHandle f12 = getSkinFile(ForgeConstants.SPRITE_START_FILE);
|
||||||
final FileHandle f13 = getDefaultSkinFile(ForgeConstants.SPRITE_DECKBOX_FILE);
|
final FileHandle f13 = getDefaultSkinFile(ForgeConstants.SPRITE_DECKBOX_FILE);
|
||||||
|
|
||||||
|
/*TODO Themeable
|
||||||
final FileHandle f14 = getDefaultSkinFile(ForgeConstants.SPRITE_SETLOGO_FILE);
|
final FileHandle f14 = getDefaultSkinFile(ForgeConstants.SPRITE_SETLOGO_FILE);
|
||||||
final FileHandle f15 = getSkinFile(ForgeConstants.SPRITE_SETLOGO_FILE);
|
final FileHandle f15 = getSkinFile(ForgeConstants.SPRITE_SETLOGO_FILE);
|
||||||
final FileHandle f16 = getDefaultSkinFile(ForgeConstants.SPRITE_WATERMARK_FILE);
|
final FileHandle f16 = getDefaultSkinFile(ForgeConstants.SPRITE_WATERMARK_FILE);
|
||||||
|
*/
|
||||||
|
|
||||||
try {
|
try {
|
||||||
textures.put(f1.path(), new Texture(f1));
|
textures.put(f1.path(), new Texture(f1));
|
||||||
|
|||||||
@@ -115,6 +115,28 @@ public enum FSkinImage implements FImage {
|
|||||||
WATERMARK_W (FSkinProp.IMG_WATERMARK_W, SourceFile.WATERMARKS),
|
WATERMARK_W (FSkinProp.IMG_WATERMARK_W, SourceFile.WATERMARKS),
|
||||||
WATERMARK_C (FSkinProp.IMG_WATERMARK_C, SourceFile.WATERMARKS),
|
WATERMARK_C (FSkinProp.IMG_WATERMARK_C, SourceFile.WATERMARKS),
|
||||||
|
|
||||||
|
//CardBG
|
||||||
|
CARDBG_A (FSkinProp.IMG_CARDBG_A, SourceFile.CARDBG),
|
||||||
|
CARDBG_B (FSkinProp.IMG_CARDBG_B, SourceFile.CARDBG),
|
||||||
|
CARDBG_BG (FSkinProp.IMG_CARDBG_BG, SourceFile.CARDBG),
|
||||||
|
CARDBG_BR (FSkinProp.IMG_CARDBG_BR, SourceFile.CARDBG),
|
||||||
|
CARDBG_C (FSkinProp.IMG_CARDBG_C, SourceFile.CARDBG),
|
||||||
|
CARDBG_G (FSkinProp.IMG_CARDBG_G, SourceFile.CARDBG),
|
||||||
|
CARDBG_L (FSkinProp.IMG_CARDBG_L, SourceFile.CARDBG),
|
||||||
|
CARDBG_M (FSkinProp.IMG_CARDBG_M, SourceFile.CARDBG),
|
||||||
|
CARDBG_R (FSkinProp.IMG_CARDBG_R, SourceFile.CARDBG),
|
||||||
|
CARDBG_RG (FSkinProp.IMG_CARDBG_RG, SourceFile.CARDBG),
|
||||||
|
CARDBG_U (FSkinProp.IMG_CARDBG_U, SourceFile.CARDBG),
|
||||||
|
CARDBG_UB (FSkinProp.IMG_CARDBG_UB, SourceFile.CARDBG),
|
||||||
|
CARDBG_UG (FSkinProp.IMG_CARDBG_UG, SourceFile.CARDBG),
|
||||||
|
CARDBG_UR (FSkinProp.IMG_CARDBG_UR, SourceFile.CARDBG),
|
||||||
|
CARDBG_V (FSkinProp.IMG_CARDBG_V, SourceFile.CARDBG),
|
||||||
|
CARDBG_W (FSkinProp.IMG_CARDBG_W, SourceFile.CARDBG),
|
||||||
|
CARDBG_WB (FSkinProp.IMG_CARDBG_WB, SourceFile.CARDBG),
|
||||||
|
CARDBG_WG (FSkinProp.IMG_CARDBG_WG, SourceFile.CARDBG),
|
||||||
|
CARDBG_WR (FSkinProp.IMG_CARDBG_WR, SourceFile.CARDBG),
|
||||||
|
CARDBG_WU (FSkinProp.IMG_CARDBG_WU, SourceFile.CARDBG),
|
||||||
|
|
||||||
//Gameplay
|
//Gameplay
|
||||||
TAP (FSkinProp.IMG_TAP, SourceFile.MANAICONS),
|
TAP (FSkinProp.IMG_TAP, SourceFile.MANAICONS),
|
||||||
UNTAP (FSkinProp.IMG_UNTAP, SourceFile.MANAICONS),
|
UNTAP (FSkinProp.IMG_UNTAP, SourceFile.MANAICONS),
|
||||||
@@ -439,6 +461,7 @@ public enum FSkinImage implements FImage {
|
|||||||
MANAICONS(ForgeConstants.SPRITE_MANAICONS_FILE),
|
MANAICONS(ForgeConstants.SPRITE_MANAICONS_FILE),
|
||||||
SETLOGOS(ForgeConstants.SPRITE_SETLOGO_FILE),
|
SETLOGOS(ForgeConstants.SPRITE_SETLOGO_FILE),
|
||||||
WATERMARKS(ForgeConstants.SPRITE_WATERMARK_FILE),
|
WATERMARKS(ForgeConstants.SPRITE_WATERMARK_FILE),
|
||||||
|
CARDBG(ForgeConstants.SPRITE_CARDBG_FILE),
|
||||||
PLANAR_CONQUEST(ForgeConstants.SPRITE_PLANAR_CONQUEST_FILE);
|
PLANAR_CONQUEST(ForgeConstants.SPRITE_PLANAR_CONQUEST_FILE);
|
||||||
|
|
||||||
private final String filename;
|
private final String filename;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package forge.assets;
|
|||||||
|
|
||||||
import com.badlogic.gdx.graphics.Texture;
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
import forge.Graphics;
|
import forge.Graphics;
|
||||||
|
|
||||||
public class FTextureImage extends FImageComplex {
|
public class FTextureImage extends FImageComplex {
|
||||||
@@ -26,6 +27,11 @@ public class FTextureImage extends FImageComplex {
|
|||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextureRegion getTextureRegion() {
|
||||||
|
return new TextureRegion(texture);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRegionX() {
|
public int getRegionX() {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -27,6 +27,11 @@ public class FTextureRegionImage extends FImageComplex {
|
|||||||
return textureRegion.getTexture();
|
return textureRegion.getTexture();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TextureRegion getTextureRegion() {
|
||||||
|
return textureRegion;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRegionX() {
|
public int getRegionX() {
|
||||||
return textureRegion.getRegionX();
|
return textureRegion.getRegionX();
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class CardAvatarImage implements FImage {
|
|||||||
@Override
|
@Override
|
||||||
public void draw(Graphics g, float x, float y, float w, float h) {
|
public void draw(Graphics g, float x, float y, float w, float h) {
|
||||||
//force to get the avatar since the the cardartcache & loadingcache is always cleared on screen change or the battle bar will display black
|
//force to get the avatar since the the cardartcache & loadingcache is always cleared on screen change or the battle bar will display black
|
||||||
image = CardRenderer.getCardArt(imageKey, false, false, false);
|
image = CardRenderer.getCardArt(imageKey, false, false, false, false, false, false, false, false, true);
|
||||||
if (image == null) {
|
if (image == null) {
|
||||||
return; //can't draw anything if can't be loaded yet
|
return; //can't draw anything if can't be loaded yet
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,14 +38,14 @@ public class CardImage implements FImage {
|
|||||||
image = ImageCache.getImage(card);
|
image = ImageCache.getImage(card);
|
||||||
if (image == null) {
|
if (image == null) {
|
||||||
if (!Forge.enableUIMask.equals("Off")) //render this if mask is still loading
|
if (!Forge.enableUIMask.equals("Off")) //render this if mask is still loading
|
||||||
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(card), false, x, y, w, h, CardStackPosition.Top);
|
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(card), false, x, y, w, h, CardStackPosition.Top, Forge.enableUIMask.equals("Art"), true);
|
||||||
|
|
||||||
return; //can't draw anything if can't be loaded yet
|
return; //can't draw anything if can't be loaded yet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (image == ImageCache.defaultImage) {
|
if (image == ImageCache.defaultImage || Forge.enableUIMask.equals("Art")) {
|
||||||
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(card), false, x, y, w, h, CardStackPosition.Top);
|
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(card), false, x, y, w, h, CardStackPosition.Top, true, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (Forge.enableUIMask.equals("Full")) {
|
if (Forge.enableUIMask.equals("Full")) {
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ import static forge.card.CardRenderer.isModernFrame;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import forge.ImageKeys;
|
||||||
|
import forge.assets.*;
|
||||||
|
import forge.item.PaperCard;
|
||||||
|
import forge.util.ImageUtil;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
import com.badlogic.gdx.graphics.Color;
|
||||||
@@ -15,15 +19,6 @@ import com.google.common.collect.ImmutableList;
|
|||||||
|
|
||||||
import forge.Forge;
|
import forge.Forge;
|
||||||
import forge.Graphics;
|
import forge.Graphics;
|
||||||
import forge.assets.FBufferedImage;
|
|
||||||
import forge.assets.FImage;
|
|
||||||
import forge.assets.FSkin;
|
|
||||||
import forge.assets.FSkinColor;
|
|
||||||
import forge.assets.FSkinFont;
|
|
||||||
import forge.assets.FSkinImage;
|
|
||||||
import forge.assets.FSkinTexture;
|
|
||||||
import forge.assets.ImageCache;
|
|
||||||
import forge.assets.TextRenderer;
|
|
||||||
import forge.card.CardRenderer.CardStackPosition;
|
import forge.card.CardRenderer.CardStackPosition;
|
||||||
import forge.card.mana.ManaCost;
|
import forge.card.mana.ManaCost;
|
||||||
import forge.game.GameView;
|
import forge.game.GameView;
|
||||||
@@ -48,6 +43,10 @@ public class CardImageRenderer {
|
|||||||
private static float prevImageWidth, prevImageHeight;
|
private static float prevImageWidth, prevImageHeight;
|
||||||
private static final float BLACK_BORDER_THICKNESS_RATIO = 0.021f;
|
private static final float BLACK_BORDER_THICKNESS_RATIO = 0.021f;
|
||||||
|
|
||||||
|
private static Color fromDetailColor(DetailColors detailColor) {
|
||||||
|
return FSkinColor.fromRGB(detailColor.r, detailColor.g, detailColor.b);
|
||||||
|
}
|
||||||
|
|
||||||
public static void forceStaticFieldUpdate() {
|
public static void forceStaticFieldUpdate() {
|
||||||
//force static fields to be updated the next time a card image is rendered
|
//force static fields to be updated the next time a card image is rendered
|
||||||
prevImageWidth = 0;
|
prevImageWidth = 0;
|
||||||
@@ -78,13 +77,17 @@ public class CardImageRenderer {
|
|||||||
|
|
||||||
public static void drawFaceDownCard(CardView card, Graphics g, float x, float y, float w, float h) {
|
public static void drawFaceDownCard(CardView card, Graphics g, float x, float y, float w, float h) {
|
||||||
//try to draw the card sleeves first
|
//try to draw the card sleeves first
|
||||||
if (FSkin.getSleeves().get(card.getOwner()) != null)
|
FImage sleeves = MatchController.getPlayerSleeve(card.getOwner());
|
||||||
g.drawImage(FSkin.getSleeves().get(card.getOwner()), x, y, w, h);
|
if (sleeves != null)
|
||||||
|
g.drawImage(sleeves, x, y, w, h);
|
||||||
else
|
else
|
||||||
drawArt(g, x, y, w, h);
|
drawArt(null, g, x, y, w, h, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawCardImage(Graphics g, CardView card, boolean altState, float x, float y, float w, float h, CardStackPosition pos) {
|
public static void drawCardImage(Graphics g, CardView card, boolean altState, float x, float y, float w, float h, CardStackPosition pos, boolean useCardBGTexture, boolean showArtist) {
|
||||||
|
drawCardImage(g, card, altState, x, y, w, h, pos, useCardBGTexture, false, false, showArtist);
|
||||||
|
}
|
||||||
|
public static void drawCardImage(Graphics g, CardView card, boolean altState, float x, float y, float w, float h, CardStackPosition pos, boolean useCardBGTexture, boolean noText, boolean isChoiceList, boolean showArtist) {
|
||||||
updateStaticFields(w, h);
|
updateStaticFields(w, h);
|
||||||
|
|
||||||
float blackBorderThickness = w * BLACK_BORDER_THICKNESS_RATIO;
|
float blackBorderThickness = w * BLACK_BORDER_THICKNESS_RATIO;
|
||||||
@@ -94,8 +97,16 @@ public class CardImageRenderer {
|
|||||||
w -= 2 * blackBorderThickness;
|
w -= 2 * blackBorderThickness;
|
||||||
h -= 2 * blackBorderThickness;
|
h -= 2 * blackBorderThickness;
|
||||||
|
|
||||||
final CardStateView state = card.getState(altState);
|
CardStateView state = altState ? card.getAlternateState() : isChoiceList && card.isSplitCard() ? card.getLeftSplitState() : card.getCurrentState();
|
||||||
|
final boolean isFaceDown = card.isFaceDown();
|
||||||
final boolean canShow = MatchController.instance.mayView(card);
|
final boolean canShow = MatchController.instance.mayView(card);
|
||||||
|
//override
|
||||||
|
if (isFaceDown && altState && card.isSplitCard())
|
||||||
|
state = card.getLeftSplitState();
|
||||||
|
boolean isSaga = state.getType().hasSubtype("Saga");
|
||||||
|
boolean isClass = state.getType().hasSubtype("Class");
|
||||||
|
boolean isDungeon = state.getType().isDungeon();
|
||||||
|
boolean drawDungeon = isDungeon && CardRenderer.getCardArt(card) != null;
|
||||||
|
|
||||||
if (!canShow) {
|
if (!canShow) {
|
||||||
drawFaceDownCard(card, g, x, y, w, h);
|
drawFaceDownCard(card, g, x, y, w, h);
|
||||||
@@ -104,14 +115,12 @@ public class CardImageRenderer {
|
|||||||
|
|
||||||
//determine colors for borders
|
//determine colors for borders
|
||||||
final List<DetailColors> borderColors;
|
final List<DetailColors> borderColors;
|
||||||
final boolean isFaceDown = card.isFaceDown();
|
|
||||||
if (isFaceDown) {
|
if (isFaceDown) {
|
||||||
borderColors = ImmutableList.of(DetailColors.FACE_DOWN);
|
borderColors = !altState ? ImmutableList.of(DetailColors.FACE_DOWN) : !useCardBGTexture ? ImmutableList.of(DetailColors.FACE_DOWN) : CardDetailUtil.getBorderColors(state, canShow);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
borderColors = CardDetailUtil.getBorderColors(state, canShow);
|
borderColors = CardDetailUtil.getBorderColors(state, canShow);
|
||||||
}
|
}
|
||||||
Color[] colors = fillColorBackground(g, borderColors, x, y, w, h);
|
Color[] colors = useCardBGTexture ? drawCardBackgroundTexture(state, g, borderColors, x, y, w, h) : fillColorBackground(g, borderColors, x, y, w, h);
|
||||||
|
|
||||||
float artInset = blackBorderThickness * 0.5f;
|
float artInset = blackBorderThickness * 0.5f;
|
||||||
float outerBorderThickness = 2 * blackBorderThickness - artInset;
|
float outerBorderThickness = 2 * blackBorderThickness - artInset;
|
||||||
@@ -122,7 +131,7 @@ public class CardImageRenderer {
|
|||||||
|
|
||||||
//draw header containing name and mana cost
|
//draw header containing name and mana cost
|
||||||
Color[] headerColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.NAME_BOX_TINT);
|
Color[] headerColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.NAME_BOX_TINT);
|
||||||
drawHeader(g, card, state, headerColors, x, y, w, headerHeight);
|
drawHeader(g, card, state, headerColors, x, y, w, headerHeight, isFaceDown && !altState, false);
|
||||||
|
|
||||||
if (pos == CardStackPosition.BehindVert) { return; } //remaining rendering not needed if card is behind another card in a vertical stack
|
if (pos == CardStackPosition.BehindVert) { return; } //remaining rendering not needed if card is behind another card in a vertical stack
|
||||||
boolean onTop = (pos == CardStackPosition.Top);
|
boolean onTop = (pos == CardStackPosition.Top);
|
||||||
@@ -134,14 +143,16 @@ public class CardImageRenderer {
|
|||||||
float typeBoxHeight = 2 * TYPE_FONT.getCapHeight();
|
float typeBoxHeight = 2 * TYPE_FONT.getCapHeight();
|
||||||
float ptBoxHeight = 0;
|
float ptBoxHeight = 0;
|
||||||
float textBoxHeight = h - headerHeight - artHeight - typeBoxHeight - outerBorderThickness - artInset;
|
float textBoxHeight = h - headerHeight - artHeight - typeBoxHeight - outerBorderThickness - artInset;
|
||||||
|
|
||||||
if (state.isCreature() || state.isPlaneswalker() || state.getType().hasSubtype("Vehicle")) {
|
if (state.isCreature() || state.isPlaneswalker() || state.getType().hasSubtype("Vehicle")) {
|
||||||
//if P/T box needed, make room for it
|
|
||||||
ptBoxHeight = 2 * PT_FONT.getCapHeight();
|
ptBoxHeight = 2 * PT_FONT.getCapHeight();
|
||||||
textBoxHeight -= ptBoxHeight;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
textBoxHeight -= 2 * artInset;
|
|
||||||
}
|
}
|
||||||
|
//space for artist
|
||||||
|
textBoxHeight -= 2 * PT_FONT.getCapHeight();
|
||||||
|
PaperCard paperCard = ImageUtil.getPaperCardFromImageKey(state.getImageKey());
|
||||||
|
String artist = "WOTC";
|
||||||
|
if (paperCard != null && !paperCard.getArtist().isEmpty())
|
||||||
|
artist = paperCard.getArtist();
|
||||||
float minTextBoxHeight = 2 * headerHeight;
|
float minTextBoxHeight = 2 * headerHeight;
|
||||||
if (textBoxHeight < minTextBoxHeight) {
|
if (textBoxHeight < minTextBoxHeight) {
|
||||||
if (textBoxHeight < minTextBoxHeight) {
|
if (textBoxHeight < minTextBoxHeight) {
|
||||||
@@ -156,53 +167,103 @@ public class CardImageRenderer {
|
|||||||
|
|
||||||
//draw art box with Forge icon
|
//draw art box with Forge icon
|
||||||
if (artHeight > 0) {
|
if (artHeight > 0) {
|
||||||
drawArt(g, x + artInset, y, artWidth, artHeight);
|
if (isSaga)
|
||||||
|
drawArt(card, g, x + artInset+(artWidth/2), y, artWidth/2, artHeight+textBoxHeight, altState, isFaceDown);
|
||||||
|
else if (isClass)
|
||||||
|
drawArt(card, g, x + artInset, y, artWidth/2, artHeight+textBoxHeight, altState, isFaceDown);
|
||||||
|
else if (isDungeon) {
|
||||||
|
if (drawDungeon) {
|
||||||
|
drawArt(card, g, x + artInset, y, artWidth, artHeight+textBoxHeight, altState, isFaceDown);
|
||||||
|
y += textBoxHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
drawArt(card, g, x + artInset, y, artWidth, artHeight, altState, isFaceDown);
|
||||||
y += artHeight;
|
y += artHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
//draw type line
|
if (isSaga) {
|
||||||
drawTypeLine(g, card, state, canShow, headerColors, x, y, w, typeBoxHeight);
|
//draw text box
|
||||||
y += typeBoxHeight;
|
Color[] textBoxColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.TEXT_BOX_TINT);
|
||||||
|
drawTextBox(g, card, state, textBoxColors, x + artInset, y-artHeight, (w - 2 * artInset)/2, textBoxHeight+artHeight, onTop, useCardBGTexture, noText, altState, isFaceDown, canShow, isChoiceList);
|
||||||
|
y += textBoxHeight;
|
||||||
|
|
||||||
//draw text box
|
//draw type line
|
||||||
Color[] textBoxColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.TEXT_BOX_TINT);
|
drawTypeLine(g, state, canShow, headerColors, x, y, w, typeBoxHeight, noText, false, false);
|
||||||
drawTextBox(g, card, state, textBoxColors, x + artInset, y, w - 2 * artInset, textBoxHeight, onTop);
|
y += typeBoxHeight;
|
||||||
y += textBoxHeight;
|
} else if (isClass) {
|
||||||
|
//draw text box
|
||||||
|
Color[] textBoxColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.TEXT_BOX_TINT);
|
||||||
|
drawTextBox(g, card, state, textBoxColors, x + artInset+(artWidth/2), y-artHeight, (w - 2 * artInset)/2, textBoxHeight+artHeight, onTop, useCardBGTexture, noText, altState, isFaceDown, canShow, isChoiceList);
|
||||||
|
y += textBoxHeight;
|
||||||
|
|
||||||
|
//draw type line
|
||||||
|
drawTypeLine(g, state, canShow, headerColors, x, y, w, typeBoxHeight, noText, false, false);
|
||||||
|
y += typeBoxHeight;
|
||||||
|
} else if (isDungeon) {
|
||||||
|
if (!drawDungeon) {
|
||||||
|
//draw textbox
|
||||||
|
Color[] textBoxColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.TEXT_BOX_TINT);
|
||||||
|
drawTextBox(g, card, state, textBoxColors, x + artInset, y-artHeight, (w - 2 * artInset), textBoxHeight+artHeight, onTop, useCardBGTexture, noText, altState, isFaceDown, canShow, isChoiceList);
|
||||||
|
y += textBoxHeight;
|
||||||
|
}
|
||||||
|
drawTypeLine(g, state, canShow, headerColors, x, y, w, typeBoxHeight, noText, false, false);
|
||||||
|
y += typeBoxHeight;
|
||||||
|
} else {
|
||||||
|
//draw type line
|
||||||
|
drawTypeLine(g, state, canShow, headerColors, x, y, w, typeBoxHeight, noText, false, false);
|
||||||
|
y += typeBoxHeight;
|
||||||
|
|
||||||
|
//draw text box
|
||||||
|
Color[] textBoxColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.TEXT_BOX_TINT);
|
||||||
|
drawTextBox(g, card, state, textBoxColors, x + artInset, y, w - 2 * artInset, textBoxHeight, onTop, useCardBGTexture, noText, altState, isFaceDown, canShow, isChoiceList);
|
||||||
|
y += textBoxHeight;
|
||||||
|
}
|
||||||
|
|
||||||
//draw P/T box
|
//draw P/T box
|
||||||
if (onTop && ptBoxHeight > 0) {
|
if (onTop && ptBoxHeight > 0) {
|
||||||
//only needed if on top since otherwise P/T will be hidden
|
//only needed if on top since otherwise P/T will be hidden
|
||||||
Color[] ptColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.PT_BOX_TINT);
|
Color[] ptColors = FSkinColor.tintColors(Color.WHITE, colors, CardRenderer.PT_BOX_TINT);
|
||||||
drawPtBox(g, card, state, ptColors, x, y - 2 * artInset, w, ptBoxHeight);
|
drawPtBox(g, card, state, ptColors, x, y - 2 * artInset, w, ptBoxHeight, noText);
|
||||||
}
|
}
|
||||||
|
//draw artist
|
||||||
|
if (showArtist)
|
||||||
|
g.drawOutlinedText(artist, TEXT_FONT, Color.WHITE, Color.DARK_GRAY, x+(TYPE_FONT.getCapHeight()/2), y+(TYPE_FONT.getCapHeight()/2), w, h, false, Align.left, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void drawHeader(Graphics g, CardView card, CardStateView state, Color[] colors, float x, float y, float w, float h) {
|
private static void drawHeader(Graphics g, CardView card, CardStateView state, Color[] colors, float x, float y, float w, float h, boolean noText, boolean isAdventure) {
|
||||||
|
float oldAlpha = g.getfloatAlphaComposite();
|
||||||
|
if (isAdventure)
|
||||||
|
g.setAlphaComposite(0.8f);
|
||||||
fillColorBackground(g, colors, x, y, w, h);
|
fillColorBackground(g, colors, x, y, w, h);
|
||||||
|
g.setAlphaComposite(oldAlpha);
|
||||||
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
||||||
|
|
||||||
float padding = h / 8;
|
float padding = h / 8;
|
||||||
|
|
||||||
//draw mana cost for card
|
|
||||||
float manaCostWidth = 0;
|
float manaCostWidth = 0;
|
||||||
ManaCost mainManaCost = state.getManaCost();
|
float manaSymbolSize = isAdventure ? MANA_SYMBOL_SIZE * 0.75f : MANA_SYMBOL_SIZE;
|
||||||
if (card.isSplitCard() && card.getAlternateState() != null) {
|
if (!noText) {
|
||||||
//handle rendering both parts of split card
|
//draw mana cost for card
|
||||||
mainManaCost = card.getLeftSplitState().getManaCost();
|
ManaCost mainManaCost = state.getManaCost();
|
||||||
ManaCost otherManaCost = card.getAlternateState().getManaCost();
|
if (card.isSplitCard() && card.getAlternateState() != null) {
|
||||||
manaCostWidth = CardFaceSymbols.getWidth(otherManaCost, MANA_SYMBOL_SIZE) + HEADER_PADDING;
|
//handle rendering both parts of split card
|
||||||
CardFaceSymbols.drawManaCost(g, otherManaCost, x + w - manaCostWidth, y + (h - MANA_SYMBOL_SIZE) / 2, MANA_SYMBOL_SIZE);
|
mainManaCost = card.getLeftSplitState().getManaCost();
|
||||||
//draw "//" between two parts of mana cost
|
ManaCost otherManaCost = card.getRightSplitState().getManaCost();
|
||||||
manaCostWidth += NAME_FONT.getBounds("//").width + HEADER_PADDING;
|
manaCostWidth = CardFaceSymbols.getWidth(otherManaCost, manaSymbolSize) + HEADER_PADDING;
|
||||||
g.drawText("//", NAME_FONT, Color.BLACK, x + w - manaCostWidth, y, w, h, false, Align.left, true);
|
CardFaceSymbols.drawManaCost(g, otherManaCost, x + w - manaCostWidth, y + (h - manaSymbolSize) / 2, manaSymbolSize);
|
||||||
|
//draw "//" between two parts of mana cost
|
||||||
|
manaCostWidth += NAME_FONT.getBounds("//").width + HEADER_PADDING;
|
||||||
|
g.drawText("//", NAME_FONT, Color.BLACK, x + w - manaCostWidth, y, w, h, false, Align.left, true);
|
||||||
|
}
|
||||||
|
manaCostWidth += CardFaceSymbols.getWidth(mainManaCost, manaSymbolSize) + HEADER_PADDING;
|
||||||
|
CardFaceSymbols.drawManaCost(g, mainManaCost, x + w - manaCostWidth, y + (h - manaSymbolSize) / 2, manaSymbolSize);
|
||||||
}
|
}
|
||||||
manaCostWidth += CardFaceSymbols.getWidth(mainManaCost, MANA_SYMBOL_SIZE) + HEADER_PADDING;
|
|
||||||
CardFaceSymbols.drawManaCost(g, mainManaCost, x + w - manaCostWidth, y + (h - MANA_SYMBOL_SIZE) / 2, MANA_SYMBOL_SIZE);
|
|
||||||
|
|
||||||
//draw name for card
|
//draw name for card
|
||||||
x += padding;
|
x += padding;
|
||||||
w -= 2 * padding;
|
w -= 2 * padding;
|
||||||
g.drawText(CardTranslation.getTranslatedName(state.getName()), NAME_FONT, Color.BLACK, x, y, w - manaCostWidth - padding, h, false, Align.left, true);
|
if (!noText)
|
||||||
|
g.drawText(CardTranslation.getTranslatedName(state.getName()), NAME_FONT, Color.BLACK, x, y, w - manaCostWidth - padding, h, false, Align.left, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final FBufferedImage forgeArt;
|
public static final FBufferedImage forgeArt;
|
||||||
@@ -221,37 +282,128 @@ public class CardImageRenderer {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void drawArt(Graphics g, float x, float y, float w, float h) {
|
private static void drawArt(CardView cv, Graphics g, float x, float y, float w, float h, boolean altState, boolean isFaceDown) {
|
||||||
g.drawImage(forgeArt, x, y, w, h);
|
if (cv == null) {
|
||||||
|
if (isFaceDown) {
|
||||||
|
Texture cardBack = ImageCache.getImage(ImageKeys.getTokenKey(ImageKeys.HIDDEN_CARD), false);
|
||||||
|
if (cardBack != null) {
|
||||||
|
g.drawImage(cardBack, x, y, w, h);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//fallback
|
||||||
|
g.drawImage(forgeArt, x, y, w, h);
|
||||||
|
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Forge.enableUIMask.equals("Art")) {
|
||||||
|
FImageComplex cardArt = CardRenderer.getCardArt(cv);
|
||||||
|
FImageComplex altArt = cardArt;
|
||||||
|
boolean isHidden = (cv.getCurrentState().getImageKey().equals(ImageKeys.getTokenKey(ImageKeys.HIDDEN_CARD))
|
||||||
|
|| cv.getCurrentState().getImageKey().equals(ImageKeys.getTokenKey(ImageKeys.FORETELL_IMAGE)));
|
||||||
|
if (cardArt != null) {
|
||||||
|
if (isHidden && !altState) {
|
||||||
|
g.drawImage(forgeArt, x, y, w, h);
|
||||||
|
} else if (cv.getCurrentState().getImageKey().equals(ImageKeys.getTokenKey(ImageKeys.MANIFEST_IMAGE)) && !altState) {
|
||||||
|
altArt = CardRenderer.getAlternateCardArt(ImageKeys.getTokenKey(ImageKeys.MANIFEST_IMAGE), false);
|
||||||
|
g.drawImage(altArt, x, y, w, h);
|
||||||
|
} else if (cv.getCurrentState().getImageKey().equals(ImageKeys.getTokenKey(ImageKeys.MORPH_IMAGE)) && !altState) {
|
||||||
|
altArt = CardRenderer.getAlternateCardArt(ImageKeys.getTokenKey(ImageKeys.MORPH_IMAGE), false);
|
||||||
|
g.drawImage(altArt, x, y, w, h);
|
||||||
|
} else {
|
||||||
|
if (cv.hasAlternateState()) {
|
||||||
|
if (altState) {
|
||||||
|
if (cv.getAlternateState().isPlaneswalker())
|
||||||
|
altArt = CardRenderer.getAlternateCardArt(cv.getAlternateState().getImageKey(), cv.getAlternateState().isPlaneswalker());
|
||||||
|
else {
|
||||||
|
altArt = CardRenderer.getCardArt(cv.getAlternateState().getImageKey(), cv.isSplitCard(), cv.getAlternateState().isPlane() || cv.getAlternateState().isPhenomenon(), cv.getText().contains("Aftermath"),
|
||||||
|
cv.getAlternateState().getType().hasSubtype("Saga"), cv.getAlternateState().getType().hasSubtype("Class"), cv.getAlternateState().getType().isDungeon(), cv.isFlipCard(), cv.getAlternateState().isPlaneswalker(), CardRenderer.isModernFrame(cv));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cv.isSplitCard()) {
|
||||||
|
drawSplitCard(cv, altArt, g, x, y, w, h, altState, isFaceDown);
|
||||||
|
} else if (cv.isFlipCard()) {
|
||||||
|
drawFlipCard(isFaceDown ? altArt : cardArt, g, x, y, w, h, altState);
|
||||||
|
} else {
|
||||||
|
g.drawImage(altArt, x, y, w, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g.drawImage(forgeArt, x, y, w, h);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g.drawImage(forgeArt, x, y, w, h);
|
||||||
|
}
|
||||||
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
||||||
}
|
}
|
||||||
|
private static void drawSplitCard(CardView card, FImageComplex cardArt, Graphics g, float x, float y, float w, float h, boolean altState, boolean isFaceDown) {
|
||||||
private static void drawTypeLine(Graphics g, CardView card, CardStateView state, boolean canShow, Color[] colors, float x, float y, float w, float h) {
|
CardView alt = card.getBackup();
|
||||||
|
if (alt == null)
|
||||||
|
alt = card.getAlternateState().getCard();
|
||||||
|
CardView cv = altState && isFaceDown ? alt : card;
|
||||||
|
boolean isAftermath = altState ? cv.getAlternateState().hasHasAftermath(): cv.getRightSplitState().hasHasAftermath();
|
||||||
|
if (!isAftermath) {
|
||||||
|
CardEdition ed = FModel.getMagicDb().getEditions().get(cv.getCurrentState().getSetCode());
|
||||||
|
boolean isOldFrame = ed != null && !ed.isModern();
|
||||||
|
float modH = isOldFrame ? cardArt.getHeight()/12f : 0f;
|
||||||
|
float modW = !isOldFrame ? cardArt.getWidth()/12f : 0f;
|
||||||
|
float modW2 = !isOldFrame ? cardArt.getWidth()/6f : 0f;
|
||||||
|
float srcY = cardArt.getHeight() * 13f / 354f;
|
||||||
|
float srcHeight = cardArt.getHeight() * 190f / 354f;
|
||||||
|
float dh = srcHeight * (1 - cardArt.getWidth() / srcHeight / CardRenderer.CARD_ART_RATIO);
|
||||||
|
srcHeight -= dh;
|
||||||
|
srcY += dh / 2;
|
||||||
|
g.drawRotatedImage(cardArt.getTexture(), x, y, h+modH, w / 2, x + w / 2, y + w / 2, cardArt.getRegionX()+(int)modW, (int)srcY, (int)(cardArt.getWidth()-modW2), (int)srcHeight, -90);
|
||||||
|
g.drawRotatedImage(cardArt.getTexture(), x, y + w / 2, h+modH, w / 2, x + w / 2, y + w / 2, cardArt.getRegionX()+(int)modW, (int)cardArt.getHeight() - (int)(srcY + srcHeight), (int)(cardArt.getWidth()-modW2), (int)srcHeight, -90);
|
||||||
|
g.drawLine(BORDER_THICKNESS, Color.BLACK, x+w/2, y, x+w/2, y+h);
|
||||||
|
} else {
|
||||||
|
FImageComplex secondArt = CardRenderer.getAftermathSecondCardArt(cv.getCurrentState().getImageKey());
|
||||||
|
g.drawRotatedImage(cardArt.getTexture(), x, y, w, h / 2, x + w, y + h / 2, cardArt.getRegionX(), cardArt.getRegionY(), (int)cardArt.getWidth(), (int)cardArt.getHeight() /2, 0);
|
||||||
|
g.drawRotatedImage(secondArt.getTexture(), x - h / 2 , y + h / 2, h /2, w, x, y + h / 2, secondArt.getRegionX(), secondArt.getRegionY(), (int)secondArt.getWidth(), (int)secondArt.getHeight(), 90);
|
||||||
|
g.drawLine(BORDER_THICKNESS, Color.BLACK, x, y+h/2, x+w, y+h/2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static void drawFlipCard(FImageComplex cardArt, Graphics g, float x, float y, float w, float h, boolean altState) {
|
||||||
|
if (altState)
|
||||||
|
g.drawRotatedImage(cardArt.getTextureRegion(), x, y, w, h, x + w / 2, y + h / 2, 180);
|
||||||
|
else
|
||||||
|
g.drawImage(cardArt, x, y, w, h);
|
||||||
|
}
|
||||||
|
private static void drawTypeLine(Graphics g, CardStateView state, boolean canShow, Color[] colors, float x, float y, float w, float h, boolean noText, boolean noRarity, boolean isAdventure) {
|
||||||
|
float oldAlpha = g.getfloatAlphaComposite();
|
||||||
|
if (isAdventure)
|
||||||
|
g.setAlphaComposite(0.6f);
|
||||||
fillColorBackground(g, colors, x, y, w, h);
|
fillColorBackground(g, colors, x, y, w, h);
|
||||||
|
g.setAlphaComposite(oldAlpha);
|
||||||
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
||||||
|
|
||||||
float padding = h / 8;
|
float padding = h / 8;
|
||||||
|
|
||||||
//draw square icon for rarity
|
//draw square icon for rarity
|
||||||
float iconSize = h * 0.9f;
|
if (!noRarity) {
|
||||||
float iconPadding = (h - iconSize) / 2;
|
float iconSize = h * 0.9f;
|
||||||
w -= iconSize + iconPadding * 2;
|
float iconPadding = (h - iconSize) / 2;
|
||||||
//g.fillRect(CardRenderer.getRarityColor(state.getRarity()), x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
w -= iconSize + iconPadding * 2;
|
||||||
if (state.getRarity() == null) {
|
//g.fillRect(CardRenderer.getRarityColor(state.getRarity()), x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
||||||
g.drawImage(FSkinImage.SET_SPECIAL, x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
if (state.getRarity() == null) {
|
||||||
} else if (state.getRarity() == CardRarity.Special ) {
|
g.drawImage(FSkinImage.SET_SPECIAL, x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
||||||
g.drawImage(FSkinImage.SET_SPECIAL, x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
} else if (state.getRarity() == CardRarity.Special ) {
|
||||||
} else if (state.getRarity() == CardRarity.MythicRare) {
|
g.drawImage(FSkinImage.SET_SPECIAL, x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
||||||
g.drawImage(FSkinImage.SET_MYTHIC, x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
} else if (state.getRarity() == CardRarity.MythicRare) {
|
||||||
} else if (state.getRarity() == CardRarity.Rare) {
|
g.drawImage(FSkinImage.SET_MYTHIC, x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
||||||
g.drawImage(FSkinImage.SET_RARE, x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
} else if (state.getRarity() == CardRarity.Rare) {
|
||||||
} else if (state.getRarity() == CardRarity.Uncommon) {
|
g.drawImage(FSkinImage.SET_RARE, x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
||||||
g.drawImage(FSkinImage.SET_UNCOMMON, x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
} else if (state.getRarity() == CardRarity.Uncommon) {
|
||||||
} else {
|
g.drawImage(FSkinImage.SET_UNCOMMON, x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
||||||
g.drawImage(FSkinImage.SET_COMMON, x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
} else {
|
||||||
|
g.drawImage(FSkinImage.SET_COMMON, x + w + iconPadding, y + (h - iconSize) / 2, iconSize, iconSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//draw type
|
//draw type
|
||||||
|
if (noText)
|
||||||
|
return;
|
||||||
x += padding;
|
x += padding;
|
||||||
g.drawText(CardDetailUtil.formatCardType(state, canShow), TYPE_FONT, Color.BLACK, x, y, w, h, false, Align.left, true);
|
g.drawText(CardDetailUtil.formatCardType(state, canShow), TYPE_FONT, Color.BLACK, x, y, w, h, false, Align.left, true);
|
||||||
}
|
}
|
||||||
@@ -259,7 +411,28 @@ public class CardImageRenderer {
|
|||||||
//use text renderer to handle mana symbols and reminder text
|
//use text renderer to handle mana symbols and reminder text
|
||||||
private static final TextRenderer cardTextRenderer = new TextRenderer(true);
|
private static final TextRenderer cardTextRenderer = new TextRenderer(true);
|
||||||
|
|
||||||
private static void drawTextBox(Graphics g, CardView card, CardStateView state, Color[] colors, float x, float y, float w, float h, boolean onTop) {
|
private static void drawTextBox(Graphics g, CardView card, CardStateView state, Color[] colors, float x, float y, float w, float h, boolean onTop, boolean useCardBGTexture, boolean noText, boolean altstate, boolean isFacedown, boolean canShow, boolean isChoiceList) {
|
||||||
|
if (card.isAdventureCard()) {
|
||||||
|
if ((isFacedown && !altstate) || card.getZone() == ZoneType.Stack || isChoiceList || altstate) {
|
||||||
|
setTextBox(g, card, state, colors, x, y, w, h, onTop, useCardBGTexture, noText, 0f, 0f, false, altstate, isFacedown);
|
||||||
|
} else {
|
||||||
|
//left
|
||||||
|
//float headerHeight = Math.max(MANA_SYMBOL_SIZE + 2 * HEADER_PADDING, 2 * TYPE_FONT.getCapHeight()) + 2;
|
||||||
|
float typeBoxHeight = 2 * TYPE_FONT.getCapHeight();
|
||||||
|
drawHeader(g, card, card.getState(true), colors, x, y, w - (w / 2), typeBoxHeight, noText, true);
|
||||||
|
drawTypeLine(g, card.getState(true), canShow, colors, x, y + typeBoxHeight, w - (w / 2), typeBoxHeight, noText, true, true);
|
||||||
|
float mod = (typeBoxHeight + typeBoxHeight);
|
||||||
|
setTextBox(g, card, state, colors, x, y + mod, w - (w / 2), h - mod, onTop, useCardBGTexture, noText, typeBoxHeight, typeBoxHeight, true, altstate, isFacedown);
|
||||||
|
//right
|
||||||
|
setTextBox(g, card, state, colors, x + w / 2, y, w - (w / 2), h, onTop, useCardBGTexture, noText, 0f, 0f, false, altstate, isFacedown);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setTextBox(g, card, state, colors, x, y, w, h, onTop, useCardBGTexture, noText, 0f, 0f, false, altstate, isFacedown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static void setTextBox(Graphics g, CardView card, CardStateView state, Color[] colors, float x, float y, float w, float h, boolean onTop, boolean useCardBGTexture, boolean noText, float adventureHeaderHeight, float adventureTypeHeight, boolean drawAdventure, boolean altstate, boolean isFaceDown) {
|
||||||
|
boolean fakeDuals = false;
|
||||||
|
//update land bg colors
|
||||||
if (state.isLand()) {
|
if (state.isLand()) {
|
||||||
DetailColors modColors = DetailColors.WHITE;
|
DetailColors modColors = DetailColors.WHITE;
|
||||||
if (state.isBasicLand()) {
|
if (state.isBasicLand()) {
|
||||||
@@ -273,53 +446,165 @@ public class CardImageRenderer {
|
|||||||
modColors = DetailColors.BLACK;
|
modColors = DetailColors.BLACK;
|
||||||
else if (state.isPlains())
|
else if (state.isPlains())
|
||||||
modColors = DetailColors.LAND;
|
modColors = DetailColors.LAND;
|
||||||
|
} if (state.origCanProduceColoredMana() == 2) {
|
||||||
|
//dual colors
|
||||||
|
Color[] colorPairs = new Color[2];
|
||||||
|
//init Color
|
||||||
|
colorPairs[0] = fromDetailColor(DetailColors.WHITE);
|
||||||
|
colorPairs[1] = fromDetailColor(DetailColors.WHITE);
|
||||||
|
//override
|
||||||
|
if (state.origProduceAnyMana()) {
|
||||||
|
colorPairs[0] = fromDetailColor(DetailColors.MULTICOLOR);
|
||||||
|
colorPairs[1] = fromDetailColor(DetailColors.MULTICOLOR);
|
||||||
|
} else {
|
||||||
|
fakeDuals = true;
|
||||||
|
if (state.origProduceManaW() && state.origProduceManaU()) {
|
||||||
|
colorPairs[0] = fromDetailColor(DetailColors.LAND);
|
||||||
|
colorPairs[1] = fromDetailColor(DetailColors.BLUE);
|
||||||
|
} else if (state.origProduceManaW() && state.origProduceManaB()) {
|
||||||
|
colorPairs[0] = fromDetailColor(DetailColors.LAND);
|
||||||
|
colorPairs[1] = fromDetailColor(DetailColors.BLACK);
|
||||||
|
} else if (state.origProduceManaW() && state.origProduceManaR()) {
|
||||||
|
colorPairs[0] = fromDetailColor(DetailColors.LAND);
|
||||||
|
colorPairs[1] = fromDetailColor(DetailColors.RED);
|
||||||
|
} else if (state.origProduceManaW() && state.origProduceManaG()) {
|
||||||
|
colorPairs[0] = fromDetailColor(DetailColors.LAND);
|
||||||
|
colorPairs[1] = fromDetailColor(DetailColors.GREEN);
|
||||||
|
} else if (state.origProduceManaU() && state.origProduceManaB()) {
|
||||||
|
colorPairs[0] = fromDetailColor(DetailColors.BLUE);
|
||||||
|
colorPairs[1] = fromDetailColor(DetailColors.BLACK);
|
||||||
|
} else if (state.origProduceManaU() && state.origProduceManaR()) {
|
||||||
|
colorPairs[0] = fromDetailColor(DetailColors.BLUE);
|
||||||
|
colorPairs[1] = fromDetailColor(DetailColors.RED);
|
||||||
|
} else if (state.origProduceManaU() && state.origProduceManaG()) {
|
||||||
|
colorPairs[0] = fromDetailColor(DetailColors.BLUE);
|
||||||
|
colorPairs[1] = fromDetailColor(DetailColors.GREEN);
|
||||||
|
} else if (state.origProduceManaB() && state.origProduceManaR()) {
|
||||||
|
colorPairs[0] = fromDetailColor(DetailColors.BLACK);
|
||||||
|
colorPairs[1] = fromDetailColor(DetailColors.RED);
|
||||||
|
} else if (state.origProduceManaB() && state.origProduceManaG()) {
|
||||||
|
colorPairs[0] = fromDetailColor(DetailColors.BLACK);
|
||||||
|
colorPairs[1] = fromDetailColor(DetailColors.GREEN);
|
||||||
|
} else if (state.origProduceManaR() && state.origProduceManaG()) {
|
||||||
|
colorPairs[0] = fromDetailColor(DetailColors.RED);
|
||||||
|
colorPairs[1] = fromDetailColor(DetailColors.GREEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
colorPairs = FSkinColor.tintColors(Color.WHITE, colorPairs, 0.3f);
|
||||||
|
float oldAlpha = g.getfloatAlphaComposite();
|
||||||
|
if (!useCardBGTexture)
|
||||||
|
fillColorBackground(g, colorPairs, x, y, w, h);
|
||||||
|
else {
|
||||||
|
g.setAlphaComposite(0.95f);
|
||||||
|
fillColorBackground(g, colorPairs, x, y, w, h);
|
||||||
|
if (fakeDuals && state.countBasicLandTypes() == 2) {
|
||||||
|
g.setAlphaComposite(0.1f);
|
||||||
|
drawAlphaLines(g, x, y, w, h);
|
||||||
|
}
|
||||||
|
g.setAlphaComposite(oldAlpha);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//override bg color
|
||||||
|
if (state.origCanProduceColoredMana() > 2 || state.origProduceAnyMana()) {
|
||||||
|
modColors = DetailColors.MULTICOLOR;
|
||||||
|
} else if (state.origCanProduceColoredMana() == 1) {
|
||||||
|
if (state.origProduceManaW())
|
||||||
|
modColors = DetailColors.LAND;
|
||||||
|
else if (state.origProduceManaB())
|
||||||
|
modColors = DetailColors.BLACK;
|
||||||
|
else if (state.origProduceManaG())
|
||||||
|
modColors = DetailColors.GREEN;
|
||||||
|
else if (state.origProduceManaR())
|
||||||
|
modColors = DetailColors.RED;
|
||||||
|
else if (state.origProduceManaU())
|
||||||
|
modColors = DetailColors.BLUE;
|
||||||
|
}
|
||||||
|
Color bgColor = fromDetailColor(modColors);
|
||||||
|
bgColor = FSkinColor.tintColor(Color.WHITE, bgColor, CardRenderer.NAME_BOX_TINT);
|
||||||
|
float oldAlpha = g.getfloatAlphaComposite();
|
||||||
|
if (!useCardBGTexture)
|
||||||
|
g.fillRect(bgColor, x, y, w, h);
|
||||||
|
else {
|
||||||
|
g.setAlphaComposite(0.95f);
|
||||||
|
g.fillRect(bgColor, x, y, w, h);
|
||||||
|
g.setAlphaComposite(oldAlpha);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Color bgColor = FSkinColor.fromRGB(modColors.r, modColors.g, modColors.b);
|
|
||||||
bgColor = FSkinColor.tintColor(Color.WHITE, bgColor, CardRenderer.NAME_BOX_TINT);
|
|
||||||
g.fillRect(bgColor, x, y, w, h);
|
|
||||||
} else {
|
} else {
|
||||||
fillColorBackground(g, colors, x, y, w, h);
|
float oldAlpha = g.getfloatAlphaComposite();
|
||||||
|
if (!useCardBGTexture)
|
||||||
|
fillColorBackground(g, colors, x, y, w, h);
|
||||||
|
else {
|
||||||
|
g.setAlphaComposite(0.95f);
|
||||||
|
fillColorBackground(g, colors, x, y, w, h);
|
||||||
|
g.setAlphaComposite(oldAlpha);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
||||||
|
|
||||||
if (!onTop) { return; } //remaining rendering only needed if card on top
|
if (!onTop) { return; } //remaining rendering only needed if card on top
|
||||||
|
|
||||||
if (state.isBasicLand()) {
|
if (state.isBasicLand()) {
|
||||||
//draw icons for basic lands
|
//draw watermark
|
||||||
FSkinImage image;
|
FSkinImage image = null;
|
||||||
switch (state.getName().replaceFirst("^Snow-Covered ", "")) {
|
if (state.origCanProduceColoredMana() == 1 && !state.origProduceManaC()) {
|
||||||
case "Plains":
|
if (state.isPlains())
|
||||||
image = FSkinImage.WATERMARK_W;
|
image = FSkinImage.WATERMARK_W;
|
||||||
break;
|
else if (state.isIsland())
|
||||||
case "Island":
|
image = FSkinImage.WATERMARK_U;
|
||||||
image = FSkinImage.WATERMARK_U;
|
else if (state.isSwamp())
|
||||||
break;
|
image = FSkinImage.WATERMARK_B;
|
||||||
case "Swamp":
|
else if (state.isMountain())
|
||||||
image = FSkinImage.WATERMARK_B;
|
image = FSkinImage.WATERMARK_R;
|
||||||
break;
|
else if (state.isForest())
|
||||||
case "Mountain":
|
image = FSkinImage.WATERMARK_G;
|
||||||
image = FSkinImage.WATERMARK_R;
|
} else if (state.origProduceManaC()) {
|
||||||
break;
|
|
||||||
case "Forest":
|
|
||||||
image = FSkinImage.WATERMARK_G;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
image = FSkinImage.WATERMARK_C;
|
image = FSkinImage.WATERMARK_C;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
float iconSize = h * 0.75f;
|
if (image != null) {
|
||||||
g.drawImage(image, x + (w - iconSize) / 2, y + (h - iconSize) / 2, iconSize, iconSize);
|
float iconSize = h * 0.75f;
|
||||||
}
|
g.drawImage(image, x + (w - iconSize) / 2, y + (h - iconSize) / 2, iconSize, iconSize);
|
||||||
else {
|
}
|
||||||
|
} else {
|
||||||
boolean needTranslation = true;
|
boolean needTranslation = true;
|
||||||
|
String text = "";
|
||||||
if (card.isToken()) {
|
if (card.isToken()) {
|
||||||
if (card.getCloneOrigin() == null)
|
if (card.getCloneOrigin() == null)
|
||||||
needTranslation = false;
|
needTranslation = false;
|
||||||
}
|
}
|
||||||
final String text = !card.isSplitCard() ?
|
if (drawAdventure) {
|
||||||
card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(state.getName(), "") : null) :
|
// draw left textbox text
|
||||||
card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(card.getLeftSplitState().getName(), card.getRightSplitState().getName()) : null );
|
if (noText)
|
||||||
if (StringUtils.isEmpty(text)) { return; }
|
return;
|
||||||
|
if (card.isAdventureCard()) {
|
||||||
|
CardView cv = card.getBackup();
|
||||||
|
if (cv == null || isFaceDown)
|
||||||
|
cv = card;
|
||||||
|
text = cv.getText(cv.getState(true), needTranslation ? CardTranslation.getTranslationTexts(cv.getName(), "") : null);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
text = !card.isSplitCard() ?
|
||||||
|
card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(state.getName(), "") : null) :
|
||||||
|
card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(card.getLeftSplitState().getName(), card.getRightSplitState().getName()) : null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (noText)
|
||||||
|
return;
|
||||||
|
if (card.isAdventureCard()) {
|
||||||
|
CardView cv = card.getBackup();
|
||||||
|
if (cv == null || isFaceDown)
|
||||||
|
cv = card;
|
||||||
|
text = cv.getText(cv.getState(false), needTranslation ? CardTranslation.getTranslationTexts(cv.getName(), "") : null);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
text = !card.isSplitCard() ?
|
||||||
|
card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(state.getName(), "") : null) :
|
||||||
|
card.getText(state, needTranslation ? CardTranslation.getTranslationTexts(card.getLeftSplitState().getName(), card.getRightSplitState().getName()) : null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(text)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
float padding = TEXT_FONT.getCapHeight() * 0.75f;
|
float padding = TEXT_FONT.getCapHeight() * 0.75f;
|
||||||
x += padding;
|
x += padding;
|
||||||
@@ -329,8 +614,12 @@ public class CardImageRenderer {
|
|||||||
cardTextRenderer.drawText(g, text, TEXT_FONT, Color.BLACK, x, y, w, h, y, h, true, Align.left, true);
|
cardTextRenderer.drawText(g, text, TEXT_FONT, Color.BLACK, x, y, w, h, y, h, true, Align.left, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private static void drawAlphaLines(Graphics g, float x, float y, float w, float h) {
|
||||||
private static void drawPtBox(Graphics g, CardView card, CardStateView state, Color[] colors, float x, float y, float w, float h) {
|
if (FSkin.overlay_alpha != null) {
|
||||||
|
g.drawImage(FSkin.overlay_alpha, x, y, w, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static void drawPtBox(Graphics g, CardView card, CardStateView state, Color[] colors, float x, float y, float w, float h, boolean noText) {
|
||||||
List<String> pieces = new ArrayList<>();
|
List<String> pieces = new ArrayList<>();
|
||||||
if (state.isCreature()) {
|
if (state.isCreature()) {
|
||||||
pieces.add(String.valueOf(state.getPower()));
|
pieces.add(String.valueOf(state.getPower()));
|
||||||
@@ -369,6 +658,8 @@ public class CardImageRenderer {
|
|||||||
fillColorBackground(g, colors, x, y, w, h);
|
fillColorBackground(g, colors, x, y, w, h);
|
||||||
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
g.drawRect(BORDER_THICKNESS, Color.BLACK, x, y, w, h);
|
||||||
|
|
||||||
|
if (noText)
|
||||||
|
return;
|
||||||
x += (boxWidth - totalPieceWidth) / 2;
|
x += (boxWidth - totalPieceWidth) / 2;
|
||||||
for (int i = 0; i < pieces.size(); i++) {
|
for (int i = 0; i < pieces.size(); i++) {
|
||||||
g.drawText(pieces.get(i), PT_FONT, Color.BLACK, x, y, w, h, false, Align.left, true);
|
g.drawText(pieces.get(i), PT_FONT, Color.BLACK, x, y, w, h, false, Align.left, true);
|
||||||
@@ -399,8 +690,8 @@ public class CardImageRenderer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (image == ImageCache.defaultImage) { //support drawing card image manually if card image not found
|
if (image == ImageCache.defaultImage || Forge.enableUIMask.equals("Art")) { //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, true, true);
|
||||||
} else {
|
} else {
|
||||||
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;
|
||||||
@@ -517,11 +808,79 @@ public class CardImageRenderer {
|
|||||||
Color[] colors = new Color[backColors.size()];
|
Color[] colors = new Color[backColors.size()];
|
||||||
for (int i = 0; i < colors.length; i++) {
|
for (int i = 0; i < colors.length; i++) {
|
||||||
DetailColors dc = backColors.get(i);
|
DetailColors dc = backColors.get(i);
|
||||||
colors[i] = FSkinColor.fromRGB(dc.r, dc.g, dc.b);
|
colors[i] = fromDetailColor(dc);
|
||||||
}
|
}
|
||||||
fillColorBackground(g, colors, x, y, w, h);
|
fillColorBackground(g, colors, x, y, w, h);
|
||||||
return colors;
|
return colors;
|
||||||
}
|
}
|
||||||
|
public static Color[] drawCardBackgroundTexture(CardStateView state, Graphics g, List<DetailColors> backColors, float x, float y, float w, float h) {
|
||||||
|
boolean isHybrid = state.getManaCost().hasHybrid();
|
||||||
|
Color[] colors = new Color[backColors.size()];
|
||||||
|
for (int i = 0; i < colors.length; i++) {
|
||||||
|
DetailColors dc = backColors.get(i);
|
||||||
|
colors[i] = fromDetailColor(dc);
|
||||||
|
}
|
||||||
|
switch (backColors.size()) {
|
||||||
|
case 1:
|
||||||
|
if (backColors.get(0) == DetailColors.FACE_DOWN) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_C, x, y, w,h);
|
||||||
|
} else if (backColors.get(0) == DetailColors.LAND) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_L, x, y, w,h);
|
||||||
|
}else if (backColors.get(0) == DetailColors.MULTICOLOR) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_M, x, y, w,h);
|
||||||
|
} else if (backColors.get(0) == DetailColors.COLORLESS) {
|
||||||
|
if (state.isVehicle())
|
||||||
|
g.drawImage(FSkinImage.CARDBG_V, x, y, w,h);
|
||||||
|
else if (state.isArtifact())
|
||||||
|
g.drawImage(FSkinImage.CARDBG_A, x, y, w,h);
|
||||||
|
else
|
||||||
|
g.drawImage(FSkinImage.CARDBG_C, x, y, w,h);
|
||||||
|
} else if (backColors.get(0) == DetailColors.GREEN) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_G, x, y, w,h);
|
||||||
|
} else if (backColors.get(0) == DetailColors.RED) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_R, x, y, w,h);
|
||||||
|
} else if (backColors.get(0) == DetailColors.BLACK) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_B, x, y, w,h);
|
||||||
|
} else if (backColors.get(0) == DetailColors.BLUE) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_U, x, y, w,h);
|
||||||
|
} else if (backColors.get(0) == DetailColors.WHITE) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_W, x, y, w,h);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (!isHybrid) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_M, x, y, w, h);
|
||||||
|
} else if (backColors.contains(DetailColors.WHITE) && backColors.contains(DetailColors.BLUE)) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_WU, x, y, w, h);
|
||||||
|
} else if (backColors.contains(DetailColors.WHITE) && backColors.contains(DetailColors.BLACK)) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_WB, x, y, w, h);
|
||||||
|
} else if (backColors.contains(DetailColors.WHITE) && backColors.contains(DetailColors.RED)) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_WR, x, y, w, h);
|
||||||
|
} else if (backColors.contains(DetailColors.WHITE) && backColors.contains(DetailColors.GREEN)) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_WG, x, y, w, h);
|
||||||
|
} else if (backColors.contains(DetailColors.BLUE) && backColors.contains(DetailColors.BLACK)) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_UB, x, y, w, h);
|
||||||
|
} else if (backColors.contains(DetailColors.BLUE) && backColors.contains(DetailColors.RED)) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_UR, x, y, w, h);
|
||||||
|
} else if (backColors.contains(DetailColors.BLUE) && backColors.contains(DetailColors.GREEN)) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_UG, x, y, w, h);
|
||||||
|
} else if (backColors.contains(DetailColors.BLACK) && backColors.contains(DetailColors.RED)) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_BR, x, y, w, h);
|
||||||
|
} else if (backColors.contains(DetailColors.BLACK) && backColors.contains(DetailColors.GREEN)) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_BG, x, y, w, h);
|
||||||
|
} else if (backColors.contains(DetailColors.RED) && backColors.contains(DetailColors.GREEN)) {
|
||||||
|
g.drawImage(FSkinImage.CARDBG_RG, x, y, w, h);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
g.drawImage(FSkinImage.CARDBG_M, x, y, w, h);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g.drawImage(FSkinImage.CARDBG_C, x, y, w,h);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return colors;
|
||||||
|
}
|
||||||
public static void fillColorBackground(Graphics g, Color[] colors, float x, float y, float w, float h) {
|
public static void fillColorBackground(Graphics g, Color[] colors, float x, float y, float w, float h) {
|
||||||
switch (colors.length) {
|
switch (colors.length) {
|
||||||
case 1:
|
case 1:
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import forge.ImageKeys;
|
||||||
|
import forge.localinstance.properties.ForgeConstants;
|
||||||
|
import forge.util.FileUtil;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
@@ -195,6 +198,7 @@ public class CardRenderer {
|
|||||||
private static final Map<String, FImageComplex> cardArtCache = new HashMap<>(1024);
|
private static final Map<String, FImageComplex> cardArtCache = new HashMap<>(1024);
|
||||||
public static final float CARD_ART_RATIO = 1.302f;
|
public static final float CARD_ART_RATIO = 1.302f;
|
||||||
public static final float CARD_ART_HEIGHT_PERCENTAGE = 0.43f;
|
public static final float CARD_ART_HEIGHT_PERCENTAGE = 0.43f;
|
||||||
|
private static List<String> classicModuleCardtoCrop = FileUtil.readFile(ForgeConstants.CLASSIC_MODULE_CARD_TO_CROP_FILE);
|
||||||
|
|
||||||
public static void clearcardArtCache(){
|
public static void clearcardArtCache(){
|
||||||
cardArtCache.clear();
|
cardArtCache.clear();
|
||||||
@@ -207,16 +211,22 @@ public class CardRenderer {
|
|||||||
|
|
||||||
public static FImageComplex getCardArt(IPaperCard pc, boolean backFace) {
|
public static FImageComplex getCardArt(IPaperCard pc, boolean backFace) {
|
||||||
CardType type = pc.getRules().getType();
|
CardType type = pc.getRules().getType();
|
||||||
return getCardArt(pc.getImageKey(backFace), pc.getRules().getSplitType() == CardSplitType.Split, type.isPlane() || type.isPhenomenon(),pc.getRules().getOracleText().contains("Aftermath"));
|
return getCardArt(pc.getImageKey(backFace), pc.getRules().getSplitType() == CardSplitType.Split,
|
||||||
|
type.isPlane() || type.isPhenomenon(),pc.getRules().getOracleText().contains("Aftermath"),
|
||||||
|
type.hasSubtype("Saga"), type.hasSubtype("Class"), type.isDungeon(), CardSplitType.Flip.equals(pc.getRules().getSplitType()),
|
||||||
|
type.isPlaneswalker(), isModernFrame(pc));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FImageComplex getCardArt(CardView card) {
|
public static FImageComplex getCardArt(CardView card) {
|
||||||
CardTypeView type = card.getCurrentState().getType();
|
CardTypeView type = card.getCurrentState().getType();
|
||||||
return getCardArt(card.getCurrentState().getImageKey(), card.isSplitCard(), type.isPlane() || type.isPhenomenon(),card.getText().contains("Aftermath"));
|
return getCardArt(card.getCurrentState().getImageKey(), card.isSplitCard(), type.isPlane() || type.isPhenomenon(),
|
||||||
|
card.getText().contains("Aftermath"), type.hasSubtype("Saga"), type.hasSubtype("Class"), type.isDungeon(),
|
||||||
|
card.isFlipCard(), type.isPlaneswalker(), isModernFrame(card));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FImageComplex getCardArt(String imageKey, boolean isSplitCard, boolean isHorizontalCard, boolean isAftermathCard) {
|
public static FImageComplex getCardArt(String imageKey, boolean isSplitCard, boolean isHorizontalCard, boolean isAftermathCard, boolean isSaga, boolean isClass, boolean isDungeon, boolean isFlipCard, boolean isPlanesWalker, boolean isModernFrame) {
|
||||||
FImageComplex cardArt = cardArtCache.get(imageKey);
|
FImageComplex cardArt = cardArtCache.get(imageKey);
|
||||||
|
boolean isClassicModule = classicModuleCardtoCrop.contains(imageKey.substring(ImageKeys.CARD_PREFIX.length()).replace(".jpg","").replace(".png", ""));
|
||||||
if (cardArt == null) {
|
if (cardArt == null) {
|
||||||
Texture image = new RendererCachedCardImage(imageKey, true).getImage();
|
Texture image = new RendererCachedCardImage(imageKey, true).getImage();
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
@@ -227,12 +237,41 @@ public class CardRenderer {
|
|||||||
float x, y;
|
float x, y;
|
||||||
float w = image.getWidth();
|
float w = image.getWidth();
|
||||||
float h = image.getHeight();
|
float h = image.getHeight();
|
||||||
if (isSplitCard && !isAftermathCard) { //allow rotated image for split cards
|
if (isClassicModule) {
|
||||||
|
x = w * 0.09f;
|
||||||
|
y = h * 0.2f;
|
||||||
|
w -= 2f * x;
|
||||||
|
h -= 3f * y;
|
||||||
|
}else if (isPlanesWalker) {
|
||||||
|
x = w * 0.09f;
|
||||||
|
y = h * 0.11f;
|
||||||
|
w -= 2f * x;
|
||||||
|
h -= 5.71f * y;
|
||||||
|
} else if (isFlipCard) {
|
||||||
|
x = w * 0.09f;
|
||||||
|
y = h * 0.32f;
|
||||||
|
w -= 2f * x;
|
||||||
|
h -= 2.1f * y;
|
||||||
|
} else if (isDungeon) {
|
||||||
|
x = w * 0.09f;
|
||||||
|
y = h * 0.1f;
|
||||||
|
w -= 2f * x;
|
||||||
|
h -= 2.2f * y;
|
||||||
|
} else if (isClass) {
|
||||||
|
x = w * 0.09f;
|
||||||
|
y = h * 0.11f;
|
||||||
|
w -= 1.1f * x + w / 2;
|
||||||
|
h -= 2.45f * y;
|
||||||
|
} else if (isSaga) {
|
||||||
|
x = (w * 0.1f) + (w * 0.8f / 2);
|
||||||
|
y = h * 0.11f;
|
||||||
|
w -= 1.16f * x;
|
||||||
|
h -= 2.45f * y;
|
||||||
|
} else if (isSplitCard && !isAftermathCard) { //allow rotated image for split cards
|
||||||
x = w * 33f / 250f;
|
x = w * 33f / 250f;
|
||||||
y = 0; //delay adjusting y and h until drawn
|
y = 0; //delay adjusting y and h until drawn
|
||||||
w *= 106f / 250f;
|
w *= 106f / 250f;
|
||||||
}
|
} else if (isHorizontalCard) { //allow rotated image for horizontal cards
|
||||||
else if (isHorizontalCard) { //allow rotated image for horizontal cards
|
|
||||||
float artX = 40f, artY = 40f;
|
float artX = 40f, artY = 40f;
|
||||||
float artW = 350f, artH = 156f;
|
float artW = 350f, artH = 156f;
|
||||||
float srcW = 430f, srcH = 300f;
|
float srcW = 430f, srcH = 300f;
|
||||||
@@ -241,8 +280,7 @@ public class CardRenderer {
|
|||||||
y = h * 40f / srcH;
|
y = h * 40f / srcH;
|
||||||
w *= artW / srcW;
|
w *= artW / srcW;
|
||||||
h *= artH / srcH;
|
h *= artH / srcH;
|
||||||
}
|
} else { //rotate art clockwise if its not the correct orientation
|
||||||
else { //rotate art clockwise if its not the correct orientation
|
|
||||||
x = w * artY / srcH;
|
x = w * artY / srcH;
|
||||||
y = h * (srcW - artW - artX) / srcW;
|
y = h * (srcW - artW - artX) / srcW;
|
||||||
w *= artH / srcH;
|
w *= artH / srcH;
|
||||||
@@ -251,19 +289,18 @@ public class CardRenderer {
|
|||||||
cardArtCache.put(imageKey, cardArt);
|
cardArtCache.put(imageKey, cardArt);
|
||||||
return cardArt;
|
return cardArt;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
//adjust smaller crop
|
||||||
x = w * 0.1f;
|
x = isModernFrame ? w * 0.1f :w * 0.12f;
|
||||||
y = h * 0.11f;
|
y = isModernFrame ? h * 0.12f : h * 0.11f;
|
||||||
w -= 2 * x;
|
w -= isModernFrame ? 2 * x : 2.1f * x;
|
||||||
h *= CARD_ART_HEIGHT_PERCENTAGE;
|
h *= CARD_ART_HEIGHT_PERCENTAGE;
|
||||||
float ratioRatio = w / h / CARD_ART_RATIO;
|
float ratioRatio = w / h / CARD_ART_RATIO;
|
||||||
if (ratioRatio > 1) { //if too wide, shrink width
|
if (ratioRatio > 1) { //if too wide, shrink width
|
||||||
float dw = w * (ratioRatio - 1);
|
float dw = w * (ratioRatio - 1);
|
||||||
w -= dw;
|
w -= dw;
|
||||||
x += dw / 2;
|
x += dw / 2;
|
||||||
}
|
} else { //if too tall, shrink height
|
||||||
else { //if too tall, shrink height
|
|
||||||
float dh = h * (1 - ratioRatio);
|
float dh = h * (1 - ratioRatio);
|
||||||
h -= dh;
|
h -= dh;
|
||||||
y += dh / 2;
|
y += dh / 2;
|
||||||
@@ -290,16 +327,15 @@ public class CardRenderer {
|
|||||||
if (image != null) {
|
if (image != null) {
|
||||||
if (image == ImageCache.defaultImage) {
|
if (image == ImageCache.defaultImage) {
|
||||||
cardArt = CardImageRenderer.forgeArt;
|
cardArt = CardImageRenderer.forgeArt;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
float x, y;
|
float x, y;
|
||||||
float w = image.getWidth();
|
float w = image.getWidth();
|
||||||
float h = image.getHeight();
|
float h = image.getHeight();
|
||||||
//allow rotated image for split cards
|
//allow rotated image for split cards
|
||||||
x = w * 138f / 250f;
|
x = w * 138f / 250f;
|
||||||
y = h * 210f / 370f; //delay adjusting y and h until drawn
|
y = h * 210f / 370f; //delay adjusting y and h until drawn
|
||||||
w *= 68f / 250f;
|
w *= 68f / 250f;
|
||||||
h *= 128f / 370f;
|
h *= 128f / 370f;
|
||||||
|
|
||||||
cardArt = new FTextureRegionImage(new TextureRegion(image, Math.round(x), Math.round(y), Math.round(w), Math.round(h)));
|
cardArt = new FTextureRegionImage(new TextureRegion(image, Math.round(x), Math.round(y), Math.round(w), Math.round(h)));
|
||||||
|
|
||||||
@@ -310,6 +346,52 @@ public class CardRenderer {
|
|||||||
return cardArt;
|
return cardArt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static FImageComplex getAlternateCardArt(final String imageKey, boolean isPlanesWalker) {
|
||||||
|
FImageComplex cardArt = cardArtCache.get("Alternate_"+imageKey);
|
||||||
|
if (cardArt == null) {
|
||||||
|
Texture image = new CachedCardImage(imageKey) {
|
||||||
|
@Override
|
||||||
|
public void onImageFetched() {
|
||||||
|
ImageCache.clear();
|
||||||
|
cardArtCache.remove("Alternate_" + imageKey);
|
||||||
|
}
|
||||||
|
}.getImage();
|
||||||
|
if (image != null) {
|
||||||
|
if (image == ImageCache.defaultImage) {
|
||||||
|
cardArt = CardImageRenderer.forgeArt;
|
||||||
|
} else {
|
||||||
|
float x, y;
|
||||||
|
float w = image.getWidth();
|
||||||
|
float h = image.getHeight();
|
||||||
|
if (isPlanesWalker) {
|
||||||
|
x = w * 0.09f;
|
||||||
|
y = h * 0.11f;
|
||||||
|
w -= 2f * x;
|
||||||
|
h -= 5.71f * y;
|
||||||
|
} else {
|
||||||
|
x = w * 0.1f;
|
||||||
|
y = h * 0.11f;
|
||||||
|
w -= 2 * x;
|
||||||
|
h *= CARD_ART_HEIGHT_PERCENTAGE;
|
||||||
|
float ratioRatio = w / h / CARD_ART_RATIO;
|
||||||
|
if (ratioRatio > 1) { //if too wide, shrink width
|
||||||
|
float dw = w * (ratioRatio - 1);
|
||||||
|
w -= dw;
|
||||||
|
x += dw / 2;
|
||||||
|
} else { //if too tall, shrink height
|
||||||
|
float dh = h * (1 - ratioRatio);
|
||||||
|
h -= dh;
|
||||||
|
y += dh / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cardArt = new FTextureRegionImage(new TextureRegion(image, Math.round(x), Math.round(y), Math.round(w), Math.round(h)));
|
||||||
|
}
|
||||||
|
cardArtCache.put("Alternate_"+imageKey, cardArt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cardArt;
|
||||||
|
}
|
||||||
|
|
||||||
public static void drawCardListItem(Graphics g, FSkinFont font, FSkinColor foreColor, CardView card, int count, String suffix, float x, float y, float w, float h, boolean compactMode) {
|
public static void drawCardListItem(Graphics g, FSkinFont font, FSkinColor foreColor, CardView card, int count, String suffix, float x, float y, float w, float h, boolean compactMode) {
|
||||||
final CardStateView state = card.getCurrentState();
|
final CardStateView state = card.getCurrentState();
|
||||||
if (card.getId() > 0) {
|
if (card.getId() > 0) {
|
||||||
@@ -457,8 +539,8 @@ public class CardRenderer {
|
|||||||
minusxy = 0.135f*radius;
|
minusxy = 0.135f*radius;
|
||||||
}
|
}
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
if (image == ImageCache.defaultImage) {
|
if (image == ImageCache.defaultImage || Forge.enableUIMask.equals("Art")) {
|
||||||
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(pc), false, x, y, w, h, pos);
|
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(pc), false, x, y, w, h, pos, true, true);
|
||||||
} else {
|
} else {
|
||||||
if (Forge.enableUIMask.equals("Full")) {
|
if (Forge.enableUIMask.equals("Full")) {
|
||||||
if (ImageCache.isBorderlessCardArt(image))
|
if (ImageCache.isBorderlessCardArt(image))
|
||||||
@@ -482,13 +564,13 @@ public class CardRenderer {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//if card has invalid or no texture due to sudden changes in ImageCache, draw CardImageRenderer instead and wait for it to refresh automatically
|
//if card has invalid or no texture due to sudden changes in ImageCache, draw CardImageRenderer instead and wait for it to refresh automatically
|
||||||
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(pc), false, x, y, w, h, pos);
|
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(pc), false, x, y, w, h, pos, Forge.enableUIMask.equals("Art"), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void drawCard(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos, boolean rotate) {
|
public static void drawCard(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos, boolean rotate) {
|
||||||
drawCard(g, card, x, y, w, h, pos, rotate, false);
|
drawCard(g, card, x, y, w, h, pos, rotate, false, false);
|
||||||
}
|
}
|
||||||
public static void drawCard(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos, boolean rotate, boolean showAltState) {
|
public static void drawCard(Graphics g, CardView card, float x, float y, float w, float h, CardStackPosition pos, boolean rotate, boolean showAltState, boolean isChoiceList) {
|
||||||
boolean canshow = MatchController.instance.mayView(card);
|
boolean canshow = MatchController.instance.mayView(card);
|
||||||
boolean showsleeves = card.isFaceDown() && card.isInZone(EnumSet.of(ZoneType.Exile)); //fix facedown card image ie gonti lord of luxury
|
boolean showsleeves = card.isFaceDown() && card.isInZone(EnumSet.of(ZoneType.Exile)); //fix facedown card image ie gonti lord of luxury
|
||||||
Texture image = new RendererCachedCardImage(card, false).getImage( showAltState ? card.getAlternateState().getImageKey() : card.getCurrentState().getImageKey());
|
Texture image = new RendererCachedCardImage(card, false).getImage( showAltState ? card.getAlternateState().getImageKey() : card.getCurrentState().getImageKey());
|
||||||
@@ -501,8 +583,12 @@ public class CardRenderer {
|
|||||||
minusxy = 0.135f*radius;
|
minusxy = 0.135f*radius;
|
||||||
}
|
}
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
if (image == ImageCache.defaultImage) {
|
if (image == ImageCache.defaultImage || Forge.enableUIMask.equals("Art")) {
|
||||||
CardImageRenderer.drawCardImage(g, card, false, x, y, w, h, pos);
|
float oldAlpha = g.getfloatAlphaComposite();
|
||||||
|
if (card.isPhasedOut())
|
||||||
|
g.setAlphaComposite(0.2f);
|
||||||
|
CardImageRenderer.drawCardImage(g, card, showAltState, x, y, w, h, pos, true, false, isChoiceList, !showCardIdOverlay(card));
|
||||||
|
g.setAlphaComposite(oldAlpha);
|
||||||
} else if (showsleeves) {
|
} else if (showsleeves) {
|
||||||
if (!card.isForeTold())
|
if (!card.isForeTold())
|
||||||
g.drawImage(sleeves, x, y, w, h);
|
g.drawImage(sleeves, x, y, w, h);
|
||||||
@@ -544,7 +630,11 @@ public class CardRenderer {
|
|||||||
drawFoilEffect(g, card, x, y, w, h, false);
|
drawFoilEffect(g, card, x, y, w, h, false);
|
||||||
} else {
|
} else {
|
||||||
//if card has invalid or no texture due to sudden changes in ImageCache, draw CardImageRenderer instead and wait for it to refresh automatically
|
//if card has invalid or no texture due to sudden changes in ImageCache, draw CardImageRenderer instead and wait for it to refresh automatically
|
||||||
CardImageRenderer.drawCardImage(g, card, false, x, y, w, h, pos);
|
float oldAlpha = g.getfloatAlphaComposite();
|
||||||
|
if (card.isPhasedOut())
|
||||||
|
g.setAlphaComposite(0.2f);
|
||||||
|
CardImageRenderer.drawCardImage(g, card, showAltState, x, y, w, h, pos, Forge.enableUIMask.equals("Art"), false, isChoiceList, !showCardIdOverlay(card));
|
||||||
|
g.setAlphaComposite(oldAlpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -557,7 +647,7 @@ public class CardRenderer {
|
|||||||
boolean unselectable = !MatchController.instance.isSelectable(card) && MatchController.instance.isSelecting();
|
boolean unselectable = !MatchController.instance.isSelectable(card) && MatchController.instance.isSelecting();
|
||||||
float cx, cy, cw, ch;
|
float cx, cy, cw, ch;
|
||||||
cx = x; cy = y; cw = w; ch = h;
|
cx = x; cy = y; cw = w; ch = h;
|
||||||
drawCard(g, card, x, y, w, h, pos, false, showAltState);
|
drawCard(g, card, x, y, w, h, pos, false, showAltState, isChoiceList);
|
||||||
|
|
||||||
float padding = w * PADDING_MULTIPLIER; //adjust for card border
|
float padding = w * PADDING_MULTIPLIER; //adjust for card border
|
||||||
x += padding;
|
x += padding;
|
||||||
@@ -684,7 +774,7 @@ public class CardRenderer {
|
|||||||
multiplier = 0.150f;
|
multiplier = 0.150f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
g.drawOutlinedText(CardTranslation.getTranslatedName(details.getName()), FSkinFont.forHeight(h * multiplier), Color.WHITE, Color.BLACK, x + padding -1f, y + padding, w - 2 * padding, h * 0.4f, true, Align.left, false);
|
g.drawOutlinedText(CardTranslation.getTranslatedName(details.getName()), FSkinFont.forHeight(h * multiplier), Color.WHITE, Color.BLACK, x + padding -1f, y + padding, w - 2 * padding, h * 0.4f, true, Align.left, false, true);
|
||||||
}
|
}
|
||||||
if (showCardManaCostOverlay(card)) {
|
if (showCardManaCostOverlay(card)) {
|
||||||
float manaSymbolSize = w / 4.5f;
|
float manaSymbolSize = w / 4.5f;
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ public class CardZoom extends FOverlay {
|
|||||||
}
|
}
|
||||||
if (flipIconBounds != null && flipIconBounds.contains(x, y)) {
|
if (flipIconBounds != null && flipIconBounds.contains(x, y)) {
|
||||||
if (currentCard.isFaceDown() && currentCard.getBackup() != null) {
|
if (currentCard.isFaceDown() && currentCard.getBackup() != null) {
|
||||||
if (currentCard.getBackup().hasBackSide()) {
|
if (currentCard.getBackup().hasBackSide() || currentCard.getBackup().isFlipCard() || currentCard.getBackup().isAdventureCard()) {
|
||||||
show(currentCard.getBackup());
|
show(currentCard.getBackup());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import com.badlogic.gdx.utils.Align;
|
|||||||
import forge.Forge;
|
import forge.Forge;
|
||||||
import forge.Forge.KeyInputAdapter;
|
import forge.Forge.KeyInputAdapter;
|
||||||
import forge.Graphics;
|
import forge.Graphics;
|
||||||
|
import forge.ImageKeys;
|
||||||
import forge.assets.FImage;
|
import forge.assets.FImage;
|
||||||
import forge.assets.FImageComplex;
|
import forge.assets.FImageComplex;
|
||||||
import forge.assets.FSkin;
|
import forge.assets.FSkin;
|
||||||
@@ -24,17 +25,15 @@ import forge.assets.FSkinColor.Colors;
|
|||||||
import forge.assets.FSkinFont;
|
import forge.assets.FSkinFont;
|
||||||
import forge.assets.FSkinImage;
|
import forge.assets.FSkinImage;
|
||||||
import forge.assets.ImageCache;
|
import forge.assets.ImageCache;
|
||||||
import forge.card.CardFaceSymbols;
|
import forge.card.*;
|
||||||
import forge.card.CardRenderer;
|
|
||||||
import forge.card.CardRenderer.CardStackPosition;
|
import forge.card.CardRenderer.CardStackPosition;
|
||||||
import forge.card.CardZoom;
|
|
||||||
import forge.card.ColorSet;
|
|
||||||
import forge.deck.ArchetypeDeckGenerator;
|
import forge.deck.ArchetypeDeckGenerator;
|
||||||
import forge.deck.CardThemedDeckGenerator;
|
import forge.deck.CardThemedDeckGenerator;
|
||||||
import forge.deck.CommanderDeckGenerator;
|
import forge.deck.CommanderDeckGenerator;
|
||||||
import forge.deck.DeckProxy;
|
import forge.deck.DeckProxy;
|
||||||
import forge.deck.FDeckViewer;
|
import forge.deck.FDeckViewer;
|
||||||
import forge.deck.io.DeckPreferences;
|
import forge.deck.io.DeckPreferences;
|
||||||
|
import forge.game.card.CardView;
|
||||||
import forge.gamemodes.planarconquest.ConquestCommander;
|
import forge.gamemodes.planarconquest.ConquestCommander;
|
||||||
import forge.item.InventoryItem;
|
import forge.item.InventoryItem;
|
||||||
import forge.item.PaperCard;
|
import forge.item.PaperCard;
|
||||||
@@ -54,6 +53,7 @@ import forge.toolbox.FEvent.FEventHandler;
|
|||||||
import forge.toolbox.FLabel;
|
import forge.toolbox.FLabel;
|
||||||
import forge.toolbox.FScrollPane;
|
import forge.toolbox.FScrollPane;
|
||||||
import forge.toolbox.FTextField;
|
import forge.toolbox.FTextField;
|
||||||
|
import forge.util.ImageUtil;
|
||||||
import forge.util.Localizer;
|
import forge.util.Localizer;
|
||||||
import forge.util.TextUtil;
|
import forge.util.TextUtil;
|
||||||
import forge.util.Utils;
|
import forge.util.Utils;
|
||||||
@@ -1016,8 +1016,20 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
|||||||
} else {
|
} else {
|
||||||
//commander bg
|
//commander bg
|
||||||
g.drawImage(FSkin.getDeckbox().get(0), FSkin.getDeckbox().get(0), x, y, w, h, Color.GREEN, selected);
|
g.drawImage(FSkin.getDeckbox().get(0), FSkin.getDeckbox().get(0), x, y, w, h, Color.GREEN, selected);
|
||||||
TextureRegion tr = ImageCache.croppedBorderImage(dpImg);
|
|
||||||
g.drawImage(tr, x+(w-w*scale)/2, y+(h-h*scale)/1.5f, w*scale, h*scale);
|
PaperCard paperCard = null;
|
||||||
|
String imageKey = item.getImageKey(false);
|
||||||
|
if (imageKey != null) {
|
||||||
|
if (imageKey.startsWith(ImageKeys.CARD_PREFIX))
|
||||||
|
paperCard = ImageUtil.getPaperCardFromImageKey(imageKey);
|
||||||
|
}
|
||||||
|
if (paperCard != null && Forge.enableUIMask.equals("Art")) {
|
||||||
|
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(paperCard), false,
|
||||||
|
x + (w - w * scale) / 2, y + (h - h * scale) / 1.5f, w * scale, h * scale, CardStackPosition.Top, true, false, false, true);
|
||||||
|
} else {
|
||||||
|
TextureRegion tr = ImageCache.croppedBorderImage(dpImg);
|
||||||
|
g.drawImage(tr, x + (w - w * scale) / 2, y + (h - h * scale) / 1.5f, w * scale, h * scale);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//fake labelname shadow
|
//fake labelname shadow
|
||||||
g.drawText(item.getName(), GROUP_HEADER_FONT, Color.BLACK, (x + PADDING)-1f, (y + PADDING*2)+1f, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, false);
|
g.drawText(item.getName(), GROUP_HEADER_FONT, Color.BLACK, (x + PADDING)-1f, (y + PADDING*2)+1f, w - 2 * PADDING, h - 2 * PADDING, true, Align.center, false);
|
||||||
@@ -1026,8 +1038,8 @@ public class ImageView<T extends InventoryItem> extends ItemView<T> {
|
|||||||
} else {
|
} else {
|
||||||
if (!dp.isGeneratedDeck()){
|
if (!dp.isGeneratedDeck()){
|
||||||
//If deck has Commander, use it as cardArt reference
|
//If deck has Commander, use it as cardArt reference
|
||||||
String deckImageKey = dp.getDeck().getCommanders().isEmpty() ? dp.getHighestCMCCard().getImageKey(false) : dp.getDeck().getCommanders().get(0).getImageKey(false);
|
PaperCard paperCard = dp.getDeck().getCommanders().isEmpty() ? dp.getHighestCMCCard() : dp.getDeck().getCommanders().get(0);
|
||||||
FImageComplex cardArt = CardRenderer.getCardArt(deckImageKey, false, false, false);
|
FImageComplex cardArt = CardRenderer.getCardArt(paperCard);
|
||||||
//draw the deckbox
|
//draw the deckbox
|
||||||
if (cardArt == null){
|
if (cardArt == null){
|
||||||
//draw generic box if null or still loading
|
//draw generic box if null or still loading
|
||||||
|
|||||||
@@ -161,6 +161,10 @@ public class HomeScreen extends FScreen {
|
|||||||
return QuestCommander;
|
return QuestCommander;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getActiveButtonIndex() {
|
||||||
|
return activeButtonIndex;
|
||||||
|
}
|
||||||
|
|
||||||
public String getQuestWorld() {
|
public String getQuestWorld() {
|
||||||
return QuestWorld;
|
return QuestWorld;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,8 +105,11 @@ public class LoadGameMenu extends FPopupMenu {
|
|||||||
protected void buildMenu() {
|
protected void buildMenu() {
|
||||||
FScreen currentScreen = Forge.getCurrentScreen();
|
FScreen currentScreen = Forge.getCurrentScreen();
|
||||||
for (LoadGameScreen lgs : LoadGameScreen.values()) {
|
for (LoadGameScreen lgs : LoadGameScreen.values()) {
|
||||||
addItem(lgs.item);
|
//fixes the overlapping menu items when the user suddenly switch from load game screen index to another screen
|
||||||
lgs.item.setSelected(currentScreen == lgs.screen);
|
if (HomeScreen.instance.getActiveButtonIndex() == 1) {
|
||||||
|
addItem(lgs.item);
|
||||||
|
lgs.item.setSelected(currentScreen == lgs.screen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -521,7 +521,7 @@ public class SettingsPage extends TabPage<SettingsScreen> {
|
|||||||
lstSettings.addItem(new CustomSelectSetting(FPref.UI_ENABLE_BORDER_MASKING,
|
lstSettings.addItem(new CustomSelectSetting(FPref.UI_ENABLE_BORDER_MASKING,
|
||||||
localizer.getMessage("lblBorderMaskOption"),
|
localizer.getMessage("lblBorderMaskOption"),
|
||||||
localizer.getMessage("nlBorderMaskOption"),
|
localizer.getMessage("nlBorderMaskOption"),
|
||||||
new String[]{"Off", "Crop", "Full"}) {
|
new String[]{"Off", "Crop", "Full", "Art"}) {
|
||||||
@Override
|
@Override
|
||||||
public void valueChanged(String newValue) {
|
public void valueChanged(String newValue) {
|
||||||
super.valueChanged(newValue);
|
super.valueChanged(newValue);
|
||||||
|
|||||||
@@ -393,7 +393,7 @@ public class FChoiceList<T> extends FList<T> implements ActivateHandler {
|
|||||||
boolean showAlt = false;
|
boolean showAlt = false;
|
||||||
if(cardView.hasAlternateState()){
|
if(cardView.hasAlternateState()){
|
||||||
if(cardView.hasBackSide())
|
if(cardView.hasBackSide())
|
||||||
showAlt = value.contains(cardView.getBackSideName());
|
showAlt = value.contains(cardView.getBackSideName()) || cardView.getAlternateState().getAbilityText().contains(value);
|
||||||
else if (cardView.isAdventureCard())
|
else if (cardView.isAdventureCard())
|
||||||
showAlt = value.equals(cardView.getAlternateState().getAbilityText());
|
showAlt = value.equals(cardView.getAlternateState().getAbilityText());
|
||||||
else if (cardView.isSplitCard()) {
|
else if (cardView.isSplitCard()) {
|
||||||
@@ -520,9 +520,12 @@ public class FChoiceList<T> extends FList<T> implements ActivateHandler {
|
|||||||
@Override
|
@Override
|
||||||
public void drawValue(Graphics g, T value, FSkinFont font, FSkinColor foreColor, boolean pressed, float x, float y, float w, float h) {
|
public void drawValue(Graphics g, T value, FSkinFont font, FSkinColor foreColor, boolean pressed, float x, float y, float w, float h) {
|
||||||
//should fix NPE ie Thief of Sanity, Gonti... etc
|
//should fix NPE ie Thief of Sanity, Gonti... etc
|
||||||
CardView cv = ((IHasCardView)value).getCardView().isFaceDown() && ((IHasCardView)value).getCardView().isInZone(EnumSet.of(ZoneType.Exile)) ? ((IHasCardView)value).getCardView().getBackup() : ((IHasCardView)value).getCardView();
|
CardView cv = ((IHasCardView)value).getCardView();
|
||||||
boolean showAlternate = showAlternate(cv, value.toString());
|
if (cv != null) {
|
||||||
CardRenderer.drawCardWithOverlays(g, cv, x, y, VStack.CARD_WIDTH, VStack.CARD_HEIGHT, CardStackPosition.Top, false, showAlternate, true);
|
CardView render = cv.isFaceDown() && cv.isInZone(EnumSet.of(ZoneType.Exile)) ? cv.getBackup() : cv;
|
||||||
|
boolean showAlternate = showAlternate(render, value.toString());
|
||||||
|
CardRenderer.drawCardWithOverlays(g, render, x, y, VStack.CARD_WIDTH, VStack.CARD_HEIGHT, CardStackPosition.Top, false, showAlternate, true);
|
||||||
|
}
|
||||||
|
|
||||||
float dx = VStack.CARD_WIDTH + FList.PADDING;
|
float dx = VStack.CARD_WIDTH + FList.PADDING;
|
||||||
x += dx;
|
x += dx;
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ ManaCost:4 U
|
|||||||
Types:Creature Shapeshifter
|
Types:Creature Shapeshifter
|
||||||
PT:0/0
|
PT:0/0
|
||||||
K:ETBReplacement:Copy:DBCopy:Optional
|
K:ETBReplacement:Copy:DBCopy:Optional
|
||||||
SVar:DBCopy:DB$ Clone | Choices$ Creature.Other | ChoiceZone$ Graveyard | SpellDescription$ You may have CARDNAME enter the battlefield as a copy of any artifact on the battlefield.
|
SVar:DBCopy:DB$ Clone | Choices$ Creature.Other | ChoiceZone$ Graveyard | SpellDescription$ You may have CARDNAME enter the battlefield as a copy of any creature card in a graveyard.
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/body_double.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/body_double.jpg
|
||||||
Oracle:You may have Body Double enter the battlefield as a copy of any creature card in a graveyard.
|
Oracle:You may have Body Double enter the battlefield as a copy of any creature card in a graveyard.
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ Types:Land
|
|||||||
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
|
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
|
||||||
A:AB$ Mana | Cost$ T | Produced$ W | SubAbility$ DBPain | SpellDescription$ Add {W}. CARDNAME deals 1 damage to you.
|
A:AB$ Mana | Cost$ T | Produced$ W | SubAbility$ DBPain | SpellDescription$ Add {W}. CARDNAME deals 1 damage to you.
|
||||||
A:AB$ Mana | Cost$ T | Produced$ G | SubAbility$ DBPain | SpellDescription$ Add {G}. CARDNAME deals 1 damage to you.
|
A:AB$ Mana | Cost$ T | Produced$ G | SubAbility$ DBPain | SpellDescription$ Add {G}. CARDNAME deals 1 damage to you.
|
||||||
SVar:DBPain:DB$DealDamage | NumDmg$ 1 | Defined$ You
|
SVar:DBPain:DB$ DealDamage | NumDmg$ 1 | Defined$ You
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/brushland.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/brushland.jpg
|
||||||
Oracle:{T}: Add {C}.\n{T}: Add {G} or {W}. Brushland deals 1 damage to you.
|
Oracle:{T}: Add {C}.\n{T}: Add {G} or {W}. Brushland deals 1 damage to you.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Name:Chrome Mox
|
|||||||
ManaCost:0
|
ManaCost:0
|
||||||
Types:Artifact
|
Types:Artifact
|
||||||
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | OptionalDecider$ You | Execute$ TrigExile | TriggerDescription$ Imprint — When CARDNAME enters the battlefield, you may exile a nonartifact, nonland card from your hand.
|
T:Mode$ ChangesZone | ValidCard$ Card.Self | Origin$ Any | Destination$ Battlefield | OptionalDecider$ You | Execute$ TrigExile | TriggerDescription$ Imprint — When CARDNAME enters the battlefield, you may exile a nonartifact, nonland card from your hand.
|
||||||
SVar:TrigExile:DB$ChangeZone | Imprint$ True | Origin$ Hand | Destination$ Exile | ChangeType$ Card.nonArtifact+nonLand | ChangeNum$ 1
|
SVar:TrigExile:DB$ ChangeZone | Imprint$ True | Origin$ Hand | Destination$ Exile | ChangeType$ Card.nonArtifact+nonLand | ChangeNum$ 1
|
||||||
A:AB$ ManaReflected | Cost$ T | Valid$ Defined.Imprinted | ColorOrType$ Color | ReflectProperty$ Is | SpellDescription$ Add one mana of any of the exiled card's colors.
|
A:AB$ ManaReflected | Cost$ T | Valid$ Defined.Imprinted | ColorOrType$ Color | ReflectProperty$ Is | SpellDescription$ Add one mana of any of the exiled card's colors.
|
||||||
T:Mode$ ChangesZone | Origin$ Battlefield | ValidCard$ Card.Self | Destination$ Any | Execute$ DBCleanup | Static$ True
|
T:Mode$ ChangesZone | Origin$ Battlefield | ValidCard$ Card.Self | Destination$ Any | Execute$ DBCleanup | Static$ True
|
||||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsImprinted+ExiledWithSource | Execute$ DBForget
|
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsImprinted+ExiledWithSource | Execute$ DBForget
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ ManaCost:no cost
|
|||||||
Types:Land
|
Types:Land
|
||||||
A:AB$ Mana | Cost$ T | Produced$ Any | Amount$ 1 | SpellDescription$ Add one mana of any color.
|
A:AB$ Mana | Cost$ T | Produced$ Any | Amount$ 1 | SpellDescription$ Add one mana of any color.
|
||||||
T:Mode$ Taps | ValidCard$ Card.Self | Execute$ TrigDamage | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME becomes tapped, it deals 1 damage to you.
|
T:Mode$ Taps | ValidCard$ Card.Self | Execute$ TrigDamage | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME becomes tapped, it deals 1 damage to you.
|
||||||
SVar:TrigDamage:DB$DealDamage | Defined$ You | NumDmg$ 1
|
SVar:TrigDamage:DB$ DealDamage | Defined$ You | NumDmg$ 1
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/city_of_brass.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/city_of_brass.jpg
|
||||||
Oracle:Whenever City of Brass becomes tapped, it deals 1 damage to you.\n{T}: Add one mana of any color.
|
Oracle:Whenever City of Brass becomes tapped, it deals 1 damage to you.\n{T}: Add one mana of any color.
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ A:AB$ ChangeZoneAll | Cost$ Sac<1/CARDNAME> | ChangeType$ Card.Creature+IsRememb
|
|||||||
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
T:Mode$ ChangesZone | Origin$ Exile | Destination$ Any | Static$ True | ValidCard$ Card.IsRemembered+ExiledWithSource | Execute$ DBForget
|
||||||
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
SVar:DBForget:DB$ Pump | ForgetObjects$ TriggeredCard
|
||||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup
|
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | Static$ True | ValidCard$ Card.Self | Execute$ DBCleanup
|
||||||
SVar:DBCleanup:DB$Cleanup | ClearRemembered$ True
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
SVar:NonStackingEffect:True
|
SVar:NonStackingEffect:True
|
||||||
AI:RemoveDeck:All
|
AI:RemoveDeck:All
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/cold_storage.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/cold_storage.jpg
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Name:Devour Intellect
|
Name:Devour Intellect
|
||||||
ManaCost:B
|
ManaCost:B
|
||||||
Types:Sorcery
|
Types:Sorcery
|
||||||
A:SP$ Pump | TgtPrompt$ Select target opponent | ValidTgt$ Opponent | SubAbility$ DBBranch
|
A:SP$ Pump | TgtPrompt$ Select target opponent | ValidTgts$ Opponent | SubAbility$ DBBranch
|
||||||
SVar:DBBranch:DB$ Branch | BranchConditionSVar$ TreasureCheck | BranchConditionSVarCompare$ GE1 | FalseSubAbility$ DBDiscard | TrueSubAbility$ DBTreasureDiscard
|
SVar:DBBranch:DB$ Branch | BranchConditionSVar$ TreasureCheck | BranchConditionSVarCompare$ GE1 | FalseSubAbility$ DBDiscard | TrueSubAbility$ DBTreasureDiscard
|
||||||
SVar:DBDiscard:DB$ Discard | Defined$ Targeted | NumCards$ 1 | Mode$ TgtChoose
|
SVar:DBDiscard:DB$ Discard | Defined$ Targeted | NumCards$ 1 | Mode$ TgtChoose
|
||||||
SVar:DBTreasureDiscard:DB$ Discard | Defined$ Targeted | NumCards$ 1 | Mode$ RevealYouChoose | DiscardValid$ Card.nonLand
|
SVar:DBTreasureDiscard:DB$ Discard | Defined$ Targeted | NumCards$ 1 | Mode$ RevealYouChoose | DiscardValid$ Card.nonLand
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ ManaCost:2 W B G
|
|||||||
Types:Legendary Creature Nightmare Insect
|
Types:Legendary Creature Nightmare Insect
|
||||||
PT:3/3
|
PT:3/3
|
||||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ PutKeywordCounter | TriggerDescription$ When CARDNAME enters the battlefield, put a flying counter on any creature you control if a creature card in your graveyard has flying. Repeat this process for first strike, double strike, deathtouch, hexproof, indestructible, lifelink, menace, reach, trample, and vigilance. Then put a +1/+1 counter on NICKNAME for each counter put on a creature this way.
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ PutKeywordCounter | TriggerDescription$ When CARDNAME enters the battlefield, put a flying counter on any creature you control if a creature card in your graveyard has flying. Repeat this process for first strike, double strike, deathtouch, hexproof, indestructible, lifelink, menace, reach, trample, and vigilance. Then put a +1/+1 counter on NICKNAME for each counter put on a creature this way.
|
||||||
SVar:PutKeywordCounter:DB$ PutCounter | Choices$ Creature.YouCtrl | ChoiceTitle$ Choose a creature | SharedKeywords$ Flying & First Strike & Double Strike & Deathtouch & Hexproof & Indestructible & Lifelink & Menace & Reach & Trample & Vigilance | SharedKeywordsZone$ Graveyard | SharedRestrictions$ Card.YouOwn | CounterNum$ 1 | RememberAmount$ True | SubAbility$ PutCounters
|
SVar:PutKeywordCounter:DB$ PutCounter | Choices$ Creature.YouCtrl | ChoiceTitle$ Choose a creature | SharedKeywords$ Flying & First Strike & Double Strike & Deathtouch & Hexproof & Indestructible & Lifelink & Menace & Reach & Trample & Vigilance | SharedKeywordsZone$ Graveyard | SharedRestrictions$ Creature.YouOwn | CounterNum$ 1 | RememberAmount$ True | SubAbility$ PutCounters
|
||||||
SVar:PutCounters:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ X | SubAbility$ DBCleanup
|
SVar:PutCounters:DB$ PutCounter | Defined$ Self | CounterType$ P1P1 | CounterNum$ X | SubAbility$ DBCleanup
|
||||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
SVar:X:Count$RememberedNumber
|
SVar:X:Count$RememberedNumber
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Name:Promise of Tomorrow
|
|||||||
ManaCost:2 W
|
ManaCost:2 W
|
||||||
Types:Enchantment
|
Types:Enchantment
|
||||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigChange | TriggerDescription$ Whenever a creature you control dies, exile it.
|
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.YouCtrl | TriggerZones$ Battlefield | Execute$ TrigChange | TriggerDescription$ Whenever a creature you control dies, exile it.
|
||||||
SVar:TrigChange:DB$ ChangeZone | Defined$ TriggeredCard | Origin$ Graveyard | Destination$ Exile
|
SVar:TrigChange:DB$ ChangeZone | Defined$ TriggeredNewCardLKICopy | Origin$ Graveyard | Destination$ Exile
|
||||||
T:Mode$ Phase | Phase$ End of Turn | TriggerZones$ Battlefield | IsPresent$ Creature.YouCtrl | PresentCompare$ EQ0 | Execute$ TrigSac | TriggerDescription$ At the beginning of each end step, if you control no creatures, sacrifice CARDNAME and return all cards exiled with it to the battlefield under your control.
|
T:Mode$ Phase | Phase$ End of Turn | TriggerZones$ Battlefield | IsPresent$ Creature.YouCtrl | PresentCompare$ EQ0 | Execute$ TrigSac | TriggerDescription$ At the beginning of each end step, if you control no creatures, sacrifice CARDNAME and return all cards exiled with it to the battlefield under your control.
|
||||||
SVar:TrigSac:DB$ Sacrifice | Defined$ Self | SubAbility$ DBChangeZoneAll
|
SVar:TrigSac:DB$ Sacrifice | Defined$ Self | SubAbility$ DBChangeZoneAll
|
||||||
SVar:DBChangeZoneAll:DB$ ChangeZoneAll | Origin$ Exile | Destination$ Battlefield | ChangeType$ Card.ExiledWithSource
|
SVar:DBChangeZoneAll:DB$ ChangeZoneAll | Origin$ Exile | Destination$ Battlefield | ChangeType$ Card.ExiledWithSource
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}.
|
|||||||
A:AB$ Mana | Cost$ T | Produced$ U | SubAbility$ DBPain | SpellDescription$ Add {U}. CARDNAME deals 1 damage to you.
|
A:AB$ Mana | Cost$ T | Produced$ U | SubAbility$ DBPain | SpellDescription$ Add {U}. CARDNAME deals 1 damage to you.
|
||||||
A:AB$ Mana | Cost$ T | Produced$ G | SubAbility$ DBPain | SpellDescription$ Add {G}. CARDNAME deals 1 damage to you.
|
A:AB$ Mana | Cost$ T | Produced$ G | SubAbility$ DBPain | SpellDescription$ Add {G}. CARDNAME deals 1 damage to you.
|
||||||
K:CARDNAME enters the battlefield tapped.
|
K:CARDNAME enters the battlefield tapped.
|
||||||
SVar:DBPain:DB$DealDamage | NumDmg$ 1 | Defined$ You
|
SVar:DBPain:DB$ DealDamage | NumDmg$ 1 | Defined$ You
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/skyshroud_forest.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/skyshroud_forest.jpg
|
||||||
Oracle:Skyshroud Forest enters the battlefield tapped.\n{T}: Add {C}.\n{T}: Add {G} or {U}. Skyshroud Forest deals 1 damage to you.
|
Oracle:Skyshroud Forest enters the battlefield tapped.\n{T}: Add {C}.\n{T}: Add {G} or {U}. Skyshroud Forest deals 1 damage to you.
|
||||||
|
|||||||
7
forge-gui/res/cardsfolder/upcoming/avacyns_memorial.txt
Normal file
7
forge-gui/res/cardsfolder/upcoming/avacyns_memorial.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Name:Avacyn's Memorial
|
||||||
|
ManaCost:5 W W W
|
||||||
|
Types:Legendary Artifact
|
||||||
|
K:Indestructible
|
||||||
|
S:Mode$ Continuous | Affected$ Permanent.Other+YouCtrl+Legendary | AddKeyword$ Indestructible | Description$ Other legendary permanents you control have indestructible.
|
||||||
|
DeckNeeds:Type$Legendary
|
||||||
|
Oracle:Indestructible\nOther legendary permanents you control have indestructible.
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
Name:Baithook Angler
|
||||||
|
ManaCost:1 U
|
||||||
|
Types:Creature Human Peasant
|
||||||
|
PT:2/1
|
||||||
|
K:Disturb:1 U
|
||||||
|
AlternateMode:DoubleFaced
|
||||||
|
Oracle:Disturb {1}{U} (You may cast this card from your graveyard transformed for its disturb cost.)
|
||||||
|
|
||||||
|
ALTERNATE
|
||||||
|
|
||||||
|
Name:Hook-Haunt Drifter
|
||||||
|
ManaCost:no cost
|
||||||
|
Types:Creature Spirit
|
||||||
|
Colors:blue
|
||||||
|
PT:1/2
|
||||||
|
K:Flying
|
||||||
|
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Graveyard | ReplaceWith$ Exile | Description$ If CARDNAME would be put into a graveyard from anywhere, exile it instead.
|
||||||
|
SVar:Exile:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Exile | Defined$ ReplacedCard
|
||||||
|
Oracle:Flying\nIf Hook-Haunt Drifter would be put into a graveyard from anywhere, exile it instead.
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
Name:Beloved Beggar
|
||||||
|
ManaCost:1 W
|
||||||
|
Types:Creature Human Peasant
|
||||||
|
PT:0/4
|
||||||
|
K:Disturb:4 W W
|
||||||
|
AlternateMode:DoubleFaced
|
||||||
|
Oracle:Disturb {4}{W}{W} (You may cast this card from your graveyard transformed for its disturb cost.)
|
||||||
|
|
||||||
|
ALTERNATE
|
||||||
|
|
||||||
|
Name:Generous Soul
|
||||||
|
ManaCost:no cost
|
||||||
|
Types:Creature Spirit
|
||||||
|
Colors:white
|
||||||
|
PT:4/4
|
||||||
|
K:Flying
|
||||||
|
K:Vigilance
|
||||||
|
R:Event$ Moved | ValidCard$ Card.Self | Destination$ Graveyard | ReplaceWith$ Exile | Description$ If CARDNAME would be put into a graveyard from anywhere, exile it instead.
|
||||||
|
SVar:Exile:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Exile | Defined$ ReplacedCard
|
||||||
|
Oracle:Flying, vigilance\nIf Generous Soul would be put into a graveyard from anywhere, exile it instead.
|
||||||
8
forge-gui/res/cardsfolder/upcoming/candlelit_cavalry.txt
Normal file
8
forge-gui/res/cardsfolder/upcoming/candlelit_cavalry.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Name:Candlelit Cavalry
|
||||||
|
ManaCost:4 G
|
||||||
|
Types:Creature Human Knight
|
||||||
|
PT:5/5
|
||||||
|
T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | TriggerZones$ Battlefield | CheckSVar$ X | SVarCompare$ GE3 | Execute$ TrigPump | TriggerDescription$ Coven – At the beginning of combat on your turn, if you control three or more creatures with different powers, CARDNAME gains trample until end of turn.
|
||||||
|
SVar:TrigPump:DB$ Pump | Defined$ Self | KW$ Trample
|
||||||
|
SVar:X:Count$DifferentPower_Creature.YouCtrl
|
||||||
|
Oracle:Coven — At the beginning of combat on your turn, if you control three or more creatures with different powers, Candlelit Cavalry gains trample until end of turn.
|
||||||
10
forge-gui/res/cardsfolder/upcoming/candletrap.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/candletrap.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Name:Candletrap
|
||||||
|
ManaCost:W
|
||||||
|
Types:Enchantment Aura
|
||||||
|
K:Enchant creature
|
||||||
|
A:SP$ Attach | Cost$ W | ValidTgts$ Creature | AILogic$ Curse
|
||||||
|
S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddKeyword$ Defender | Description$ Enchanted creature has defender.
|
||||||
|
R:Event$ DamageDone | Prevent$ True | IsCombat$ True | ValidSource$ Creature.EnchantedBy | Description$ Prevent all combat damage that would be dealt by enchanted creature.
|
||||||
|
A:AB$ ChangeZone | Cost$ 2 W Sac<1/CARDNAME> | Defined$ Enchanted | CheckSVar$ X | SVarCompare$ GE3 | Origin$ Battlefield | Destination$ Exile | PrecostDesc$ Coven — | SpellDescription$ Exile enchanted creature. Activate only if you control three or more creatures with different powers.
|
||||||
|
SVar:X:Count$DifferentPower_Creature.YouCtrl
|
||||||
|
Oracle:Enchant creature\nEnchanted creature has defender.\nPrevent all combat damage that would be dealt by enchanted creature.\nCoven — {2}{W}, Sacrifice Candletrap: Exile enchanted creature. Activate only if you control three or more creatures with different powers.
|
||||||
10
forge-gui/res/cardsfolder/upcoming/curse_of_obsession.txt
Normal file
10
forge-gui/res/cardsfolder/upcoming/curse_of_obsession.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Name:Curse of Obsession
|
||||||
|
ManaCost:4 R
|
||||||
|
Types:Enchantment Aura Curse
|
||||||
|
K:Enchant player
|
||||||
|
A:SP$ Attach | ValidTgts$ Player | AILogic$ Curse
|
||||||
|
T:Mode$ Phase | Phase$ Draw | ValidPlayer$ Player.EnchantedBy | TriggerZones$ Battlefield | Execute$ TrigDraw | TriggerDescription$ At the beginning of enchanted player's draw step, that player draws two additional cards.
|
||||||
|
SVar:TrigDraw:DB$ Draw | Defined$ TriggeredPlayer | NumCards$ 2
|
||||||
|
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ Player.EnchantedBy | TriggerZones$ Battlefield | Execute$ TrigDiscard | TriggerDescription$ At the beginning of enchanted player's end step, that player discards their hand.
|
||||||
|
SVar:TrigDiscard:DB$ Discard | Defined$ TriggeredPlayer | Mode$ Hand
|
||||||
|
Oracle:Enchant player\nAt the beginning of enchanted player's draw step, that player draws two additional cards.\nAt the beginning of enchanted player's end step, that player discards their hand.
|
||||||
5
forge-gui/res/cardsfolder/upcoming/defenestrate.txt
Normal file
5
forge-gui/res/cardsfolder/upcoming/defenestrate.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Name:Defenestrate
|
||||||
|
ManaCost:2 B
|
||||||
|
Types:Instant
|
||||||
|
A:SP$ Destroy | Cost$ 2 B | ValidTgts$ Creature.withoutFlying | TgtPrompt$ Select target creature without flying | SpellDescription$ Destroy target creature without flying.
|
||||||
|
Oracle:Destroy target creature without flying.
|
||||||
9
forge-gui/res/cardsfolder/upcoming/deserted_beach.txt
Normal file
9
forge-gui/res/cardsfolder/upcoming/deserted_beach.txt
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Name:Deserted Beach
|
||||||
|
ManaCost:no cost
|
||||||
|
Types:Land
|
||||||
|
A:AB$ Mana | Cost$ T | Produced$ W | SpellDescription$ Add {W}.
|
||||||
|
A:AB$ Mana | Cost$ T | Produced$ U | SpellDescription$ Add {U}.
|
||||||
|
K:ETBReplacement:Other:LandTapped
|
||||||
|
SVar:LandTapped:DB$ Tap | Defined$ Self | ETB$ True | ConditionCheckSVar$ ETBCheckSVar2 | ConditionSVarCompare$ LT2 | SpellDescription$ CARDNAME enters the battlefield tapped unless you control two or more other lands.
|
||||||
|
SVar:ETBCheckSVar2:Count$LastStateBattlefield Land.YouCtrl
|
||||||
|
Oracle:Deserted Beach enters the battlefield tapped unless you control two or more other lands.\n{T}: Add {W} or {U}.
|
||||||
8
forge-gui/res/cardsfolder/upcoming/festival_crasher.txt
Normal file
8
forge-gui/res/cardsfolder/upcoming/festival_crasher.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Name:Festival Crasher
|
||||||
|
ManaCost:1 R
|
||||||
|
Types:Creature Devil
|
||||||
|
PT:1/3
|
||||||
|
T:Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPump | TriggerDescription$ Whenever you cast an instant or sorcery spell, CARDNAME gets +2/+0 until end of turn.
|
||||||
|
SVar:TrigPump:DB$ Pump | Defined$ Self | NumAtt$ 2
|
||||||
|
DeckHints:Type$Instant|Sorcery
|
||||||
|
Oracle:Whenever you cast an instant or sorcery spell, Festival Crasher gets +2/+0 until end of turn.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
Name:Galvanic Iteration
|
||||||
|
ManaCost:U R
|
||||||
|
Types:Instant
|
||||||
|
K:Flashback:1 U R
|
||||||
|
A:SP$ DelayedTrigger | Cost$ U R | AILogic$ SpellCopy | Execute$ EffTrigCopy | ThisTurn$ True | Mode$ SpellCast | ValidCard$ Instant,Sorcery | ValidActivatingPlayer$ You | SpellDescription$ When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.
|
||||||
|
SVar:EffTrigCopy:DB$ CopySpellAbility | Defined$ TriggeredSpellAbility | MayChooseTarget$ True
|
||||||
|
SVar:AIPriorityModifier:9
|
||||||
|
Oracle:When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.\nFlashback {1}{U}{R} (You may cast this card from your graveyard for its flashback cost. Then exile it.)
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
Name:Gisa, Glorious Resurrector
|
||||||
|
ManaCost:2 B B
|
||||||
|
Types:Legendary Creature Human Wizard
|
||||||
|
PT:4/4
|
||||||
|
R:Event$ Moved | ActiveZones$ Battlefield | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.OppCtrl | ReplaceWith$ Exile | Description$ If a creature an opponent controls would die, exile it instead.
|
||||||
|
SVar:Exile:DB$ ChangeZone | Hidden$ True | Origin$ All | Destination$ Exile | Defined$ ReplacedCard
|
||||||
|
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | IsPresent$ Card.ExiledWithSource | PresentZone$ Exile | Execute$ TrigChange | TriggerDescription$ At the beginning of your upkeep, put all creature cards exiled with CARDNAME onto the battlefield under your control. They gain decayed. (A creature with decayed can't block. When it attacks, sacrifice it at end of combat.)
|
||||||
|
SVar:TrigChange:DB$ ChangeZoneAll | ChangeType$ Card.ExiledWithSource | Origin$ Exile | Destination$ Battlefield | GainControl$ True | RememberChanged$ True | SubAbility$ DBPump
|
||||||
|
SVar:DBPump:DB$ PumpAll | ValidCards$ Card.IsRemembered | KW$ Decayed | Duration$ Permanent | SubAbility$ DBCleanup
|
||||||
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
|
Oracle:If a creature an opponent controls would die, exile it instead.\nAt the beginning of your upkeep, put all creature cards exiled with Gisa, Glorious Resurrector onto the battlefield under your control. They gain decayed. (A creature with decayed can't block. When it attacks, sacrifice it at end of combat.)
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user