mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 18:28:00 +00:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -91,9 +91,6 @@ public class ComputerUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
source.setCastSA(sa);
|
|
||||||
sa.setLastStateBattlefield(game.getLastStateBattlefield());
|
|
||||||
sa.setLastStateGraveyard(game.getLastStateGraveyard());
|
|
||||||
sa.setHostCard(game.getAction().moveToStack(source, sa));
|
sa.setHostCard(game.getAction().moveToStack(source, sa));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,9 +216,6 @@ public class ComputerUtil {
|
|||||||
|
|
||||||
final Card source = sa.getHostCard();
|
final Card source = sa.getHostCard();
|
||||||
if (sa.isSpell() && !source.isCopiedSpell()) {
|
if (sa.isSpell() && !source.isCopiedSpell()) {
|
||||||
source.setCastSA(sa);
|
|
||||||
sa.setLastStateBattlefield(game.getLastStateBattlefield());
|
|
||||||
sa.setLastStateGraveyard(game.getLastStateGraveyard());
|
|
||||||
sa.setHostCard(game.getAction().moveToStack(source, sa));
|
sa.setHostCard(game.getAction().moveToStack(source, sa));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,9 +240,6 @@ public class ComputerUtil {
|
|||||||
|
|
||||||
final Card source = sa.getHostCard();
|
final Card source = sa.getHostCard();
|
||||||
if (sa.isSpell() && !source.isCopiedSpell()) {
|
if (sa.isSpell() && !source.isCopiedSpell()) {
|
||||||
source.setCastSA(sa);
|
|
||||||
sa.setLastStateBattlefield(game.getLastStateBattlefield());
|
|
||||||
sa.setLastStateGraveyard(game.getLastStateGraveyard());
|
|
||||||
sa.setHostCard(game.getAction().moveToStack(source, sa));
|
sa.setHostCard(game.getAction().moveToStack(source, sa));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,9 +258,6 @@ public class ComputerUtil {
|
|||||||
|
|
||||||
final Card source = newSA.getHostCard();
|
final Card source = newSA.getHostCard();
|
||||||
if (newSA.isSpell() && !source.isCopiedSpell()) {
|
if (newSA.isSpell() && !source.isCopiedSpell()) {
|
||||||
source.setCastSA(newSA);
|
|
||||||
sa.setLastStateBattlefield(game.getLastStateBattlefield());
|
|
||||||
sa.setLastStateGraveyard(game.getLastStateGraveyard());
|
|
||||||
newSA.setHostCard(game.getAction().moveToStack(source, sa));
|
newSA.setHostCard(game.getAction().moveToStack(source, sa));
|
||||||
|
|
||||||
if (newSA.getApi() == ApiType.Charm && !newSA.isWrapper()) {
|
if (newSA.getApi() == ApiType.Charm && !newSA.isWrapper()) {
|
||||||
@@ -290,9 +278,6 @@ public class ComputerUtil {
|
|||||||
if (ComputerUtilCost.canPayCost(sa, ai)) {
|
if (ComputerUtilCost.canPayCost(sa, ai)) {
|
||||||
final Card source = sa.getHostCard();
|
final Card source = sa.getHostCard();
|
||||||
if (sa.isSpell() && !source.isCopiedSpell()) {
|
if (sa.isSpell() && !source.isCopiedSpell()) {
|
||||||
source.setCastSA(sa);
|
|
||||||
sa.setLastStateBattlefield(game.getLastStateBattlefield());
|
|
||||||
sa.setLastStateGraveyard(game.getLastStateGraveyard());
|
|
||||||
sa.setHostCard(game.getAction().moveToStack(source, sa));
|
sa.setHostCard(game.getAction().moveToStack(source, sa));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,11 @@ public final class ImageKeys {
|
|||||||
}
|
}
|
||||||
//try fullborder...
|
//try fullborder...
|
||||||
if (filename.contains(".full")) {
|
if (filename.contains(".full")) {
|
||||||
file = findFile(dir, TextUtil.fastReplace(filename, ".full", ".fullborder"));
|
String fullborderFile = TextUtil.fastReplace(filename, ".full", ".fullborder");
|
||||||
|
file = findFile(dir, fullborderFile);
|
||||||
|
if (file != null) { return file; }
|
||||||
|
// if there's an art variant try without it
|
||||||
|
file = findFile(dir, TextUtil.fastReplace(fullborderFile, "1.fullborder", ".fullborder"));
|
||||||
if (file != null) { return file; }
|
if (file != null) { return file; }
|
||||||
}
|
}
|
||||||
//if an image, like phenomenon or planes is missing .full in their filenames but you have an existing images that have .full/.fullborder
|
//if an image, like phenomenon or planes is missing .full in their filenames but you have an existing images that have .full/.fullborder
|
||||||
|
|||||||
@@ -192,6 +192,7 @@ public final class CardEdition implements Comparable<CardEdition> { // immutable
|
|||||||
public boolean getSmallSetOverride() { return smallSetOverride; }
|
public boolean getSmallSetOverride() { return smallSetOverride; }
|
||||||
public String getBoosterMustContain() { return boosterMustContain; }
|
public String getBoosterMustContain() { return boosterMustContain; }
|
||||||
public CardInSet[] getCards() { return cards; }
|
public CardInSet[] getCards() { return cards; }
|
||||||
|
public boolean isModern() { return getDate().after(parseDate("2003-07-27")); } //8ED and above are modern except some promo cards and others
|
||||||
|
|
||||||
public Map<String, Integer> getTokens() { return tokenNormalized; }
|
public Map<String, Integer> getTokens() { return tokenNormalized; }
|
||||||
|
|
||||||
|
|||||||
@@ -222,7 +222,12 @@ public final class CardRules implements ICardCharacteristics {
|
|||||||
|
|
||||||
public boolean canBeBrawlCommander() {
|
public boolean canBeBrawlCommander() {
|
||||||
CardType type = mainPart.getType();
|
CardType type = mainPart.getType();
|
||||||
return (type.isLegendary() && type.isCreature()) || type.isPlaneswalker();
|
return type.isLegendary() && (type.isCreature() || type.isPlaneswalker());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canBeTinyLeadersCommander() {
|
||||||
|
CardType type = mainPart.getType();
|
||||||
|
return type.isLegendary() && (type.isCreature() || type.isPlaneswalker());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getMeldWith() {
|
public String getMeldWith() {
|
||||||
|
|||||||
@@ -594,8 +594,10 @@ public final class CardRulesPredicates {
|
|||||||
public static final Predicate<CardRules> IS_VANGUARD = CardRulesPredicates.coreType(true, CardType.CoreType.Vanguard);
|
public static final Predicate<CardRules> IS_VANGUARD = CardRulesPredicates.coreType(true, CardType.CoreType.Vanguard);
|
||||||
public static final Predicate<CardRules> IS_CONSPIRACY = CardRulesPredicates.coreType(true, CardType.CoreType.Conspiracy);
|
public static final Predicate<CardRules> IS_CONSPIRACY = CardRulesPredicates.coreType(true, CardType.CoreType.Conspiracy);
|
||||||
public static final Predicate<CardRules> IS_NON_LAND = CardRulesPredicates.coreType(false, CardType.CoreType.Land);
|
public static final Predicate<CardRules> IS_NON_LAND = CardRulesPredicates.coreType(false, CardType.CoreType.Land);
|
||||||
public static final Predicate<CardRules> CAN_BE_BRAWL_COMMANDER = Predicates.or(Presets.IS_PLANESWALKER,
|
public static final Predicate<CardRules> CAN_BE_BRAWL_COMMANDER = Predicates.and(Presets.IS_LEGENDARY,
|
||||||
Predicates.and(Presets.IS_CREATURE, Presets.IS_LEGENDARY));
|
Predicates.or(Presets.IS_CREATURE, Presets.IS_PLANESWALKER));
|
||||||
|
public static final Predicate<CardRules> CAN_BE_TINY_LEADERS_COMMANDER = Predicates.and(Presets.IS_LEGENDARY,
|
||||||
|
Predicates.or(Presets.IS_CREATURE, Presets.IS_PLANESWALKER));
|
||||||
|
|
||||||
/** The Constant IS_NON_CREATURE_SPELL. **/
|
/** The Constant IS_NON_CREATURE_SPELL. **/
|
||||||
public static final Predicate<CardRules> IS_NON_CREATURE_SPELL = com.google.common.base.Predicates
|
public static final Predicate<CardRules> IS_NON_CREATURE_SPELL = com.google.common.base.Predicates
|
||||||
|
|||||||
@@ -463,6 +463,9 @@ public enum DeckFormat {
|
|||||||
if (this.equals(DeckFormat.Brawl)) {
|
if (this.equals(DeckFormat.Brawl)) {
|
||||||
return rules.canBeBrawlCommander();
|
return rules.canBeBrawlCommander();
|
||||||
}
|
}
|
||||||
|
if (this.equals(DeckFormat.TinyLeaders)) {
|
||||||
|
return rules.canBeTinyLeadersCommander();
|
||||||
|
}
|
||||||
return rules.canBeCommander();
|
return rules.canBeCommander();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import forge.item.PaperCard;
|
|||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSortedMap;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -17,6 +19,22 @@ import java.util.Map.Entry;
|
|||||||
*/
|
*/
|
||||||
public class TextUtil {
|
public class TextUtil {
|
||||||
|
|
||||||
|
static ImmutableSortedMap<Integer,String> romanMap = ImmutableSortedMap.<Integer,String>naturalOrder()
|
||||||
|
.put(1000, "M").put(900, "CM")
|
||||||
|
.put(500, "D").put(400, "CD")
|
||||||
|
.put(100, "C").put(90, "XC")
|
||||||
|
.put(50, "L").put(40, "XL")
|
||||||
|
.put(10, "X").put(9, "IX")
|
||||||
|
.put(5, "V").put(4, "IV").put(1, "I").build();
|
||||||
|
|
||||||
|
public final static String toRoman(int number) {
|
||||||
|
if (number <= 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
int l = romanMap.floorKey(number);
|
||||||
|
return romanMap.get(l) + toRoman(number-l);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Safely converts an object to a String.
|
* Safely converts an object to a String.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -547,6 +547,13 @@ public class GameAction {
|
|||||||
c.setCastSA(null);
|
c.setCastSA(null);
|
||||||
} else if (zoneTo.is(ZoneType.Stack)) {
|
} else if (zoneTo.is(ZoneType.Stack)) {
|
||||||
c.setCastFrom(zoneFrom.getZoneType());
|
c.setCastFrom(zoneFrom.getZoneType());
|
||||||
|
if (cause != null && cause.isSpell() && c.equals(cause.getHostCard()) && !c.isCopiedSpell()) {
|
||||||
|
cause.setLastStateBattlefield(game.getLastStateBattlefield());
|
||||||
|
cause.setLastStateGraveyard(game.getLastStateGraveyard());
|
||||||
|
c.setCastSA(cause);
|
||||||
|
} else {
|
||||||
|
c.setCastSA(null);
|
||||||
|
}
|
||||||
} else if (!(zoneTo.is(ZoneType.Battlefield) && zoneFrom.is(ZoneType.Stack))) {
|
} else if (!(zoneTo.is(ZoneType.Battlefield) && zoneFrom.is(ZoneType.Stack))) {
|
||||||
c.setCastFrom(null);
|
c.setCastFrom(null);
|
||||||
c.setCastSA(null);
|
c.setCastSA(null);
|
||||||
|
|||||||
@@ -22,8 +22,10 @@ import com.google.common.collect.Iterables;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
|
import forge.card.MagicColor;
|
||||||
import forge.card.mana.ManaCost;
|
import forge.card.mana.ManaCost;
|
||||||
import forge.card.mana.ManaCostParser;
|
import forge.card.mana.ManaCostParser;
|
||||||
|
import forge.game.ability.AbilityFactory;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
import forge.game.ability.ApiType;
|
import forge.game.ability.ApiType;
|
||||||
import forge.game.card.*;
|
import forge.game.card.*;
|
||||||
@@ -32,9 +34,15 @@ import forge.game.cost.Cost;
|
|||||||
import forge.game.keyword.KeywordInterface;
|
import forge.game.keyword.KeywordInterface;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
import forge.game.player.PlayerController;
|
import forge.game.player.PlayerController;
|
||||||
|
import forge.game.replacement.ReplacementEffect;
|
||||||
|
import forge.game.replacement.ReplacementHandler;
|
||||||
|
import forge.game.replacement.ReplacementLayer;
|
||||||
import forge.game.spellability.*;
|
import forge.game.spellability.*;
|
||||||
import forge.game.trigger.Trigger;
|
import forge.game.trigger.Trigger;
|
||||||
|
import forge.game.trigger.TriggerHandler;
|
||||||
|
import forge.game.trigger.TriggerType;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
|
import forge.util.Lang;
|
||||||
import forge.util.TextUtil;
|
import forge.util.TextUtil;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@@ -363,10 +371,11 @@ public final class GameActionUtil {
|
|||||||
}
|
}
|
||||||
SpellAbility result = null;
|
SpellAbility result = null;
|
||||||
final Card host = sa.getHostCard();
|
final Card host = sa.getHostCard();
|
||||||
|
final Game game = host.getGame();
|
||||||
final Player activator = sa.getActivatingPlayer();
|
final Player activator = sa.getActivatingPlayer();
|
||||||
final PlayerController pc = activator.getController();
|
final PlayerController pc = activator.getController();
|
||||||
|
|
||||||
host.getGame().getAction().checkStaticAbilities(false);
|
game.getAction().checkStaticAbilities(false);
|
||||||
|
|
||||||
boolean reset = false;
|
boolean reset = false;
|
||||||
|
|
||||||
@@ -429,7 +438,60 @@ public final class GameActionUtil {
|
|||||||
int v = pc.chooseNumberForKeywordCost(sa, cost, ki, str, Integer.MAX_VALUE);
|
int v = pc.chooseNumberForKeywordCost(sa, cost, ki, str, Integer.MAX_VALUE);
|
||||||
|
|
||||||
if (v > 0) {
|
if (v > 0) {
|
||||||
host.addReplacementEffect(CardFactoryUtil.makeEtbCounter("etbCounter:P1P1:" + v, host, false));
|
|
||||||
|
final Card eff = new Card(game.nextCardId(), game);
|
||||||
|
eff.setTimestamp(game.getNextTimestamp());
|
||||||
|
eff.setName(c.getName() + "'s Effect");
|
||||||
|
eff.addType("Effect");
|
||||||
|
eff.setToken(true); // Set token to true, so when leaving play it gets nuked
|
||||||
|
eff.setOwner(activator);
|
||||||
|
|
||||||
|
eff.setImageKey(c.getImageKey());
|
||||||
|
eff.setColor(MagicColor.COLORLESS);
|
||||||
|
eff.setImmutable(true);
|
||||||
|
// try to get the SpellAbility from the mana ability
|
||||||
|
//eff.setEffectSource((SpellAbility)null);
|
||||||
|
|
||||||
|
eff.addRemembered(host);
|
||||||
|
|
||||||
|
String abStr = "DB$ PutCounter | Defined$ ReplacedCard | CounterType$ P1P1 | ETB$ True | CounterNum$ " + v;
|
||||||
|
|
||||||
|
SpellAbility saAb = AbilityFactory.getAbility(abStr, c);
|
||||||
|
|
||||||
|
CardFactoryUtil.setupETBReplacementAbility(saAb);
|
||||||
|
|
||||||
|
String desc = "It enters the battlefield with ";
|
||||||
|
desc += Lang.nounWithNumeral(v, CounterType.P1P1.getName() + " counter");
|
||||||
|
desc += " on it.";
|
||||||
|
|
||||||
|
String repeffstr = "Event$ Moved | ValidCard$ Card.IsRemembered | Destination$ Battlefield | Description$ " + desc;
|
||||||
|
|
||||||
|
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true);
|
||||||
|
re.setLayer(ReplacementLayer.Other);
|
||||||
|
re.setOverridingAbility(saAb);
|
||||||
|
|
||||||
|
eff.addReplacementEffect(re);
|
||||||
|
|
||||||
|
// Forgot Trigger
|
||||||
|
String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Stack | Destination$ Any | TriggerZones$ Command | Static$ True";
|
||||||
|
String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
|
||||||
|
String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
|
||||||
|
+ " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
|
||||||
|
|
||||||
|
SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, eff);
|
||||||
|
AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, eff);
|
||||||
|
saForget.setSubAbility(saExile);
|
||||||
|
|
||||||
|
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, eff, true);
|
||||||
|
parsedTrigger.setOverridingAbility(saForget);
|
||||||
|
eff.addTrigger(parsedTrigger);
|
||||||
|
eff.updateStateForView();
|
||||||
|
|
||||||
|
// TODO: Add targeting to the effect so it knows who it's dealing with
|
||||||
|
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||||
|
game.getAction().moveTo(ZoneType.Command, eff, null);
|
||||||
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
|
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = sa.copy();
|
result = sa.copy();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6353,6 +6353,10 @@ public class Card extends GameEntity implements Comparable<Card> {
|
|||||||
removeSVar("PayX"); // Temporary AI X announcement variable
|
removeSVar("PayX"); // Temporary AI X announcement variable
|
||||||
removeSVar("IsCastFromPlayEffect"); // Temporary SVar indicating that the spell is cast indirectly via AF Play
|
removeSVar("IsCastFromPlayEffect"); // Temporary SVar indicating that the spell is cast indirectly via AF Play
|
||||||
setSunburstValue(0); // Sunburst
|
setSunburstValue(0); // Sunburst
|
||||||
|
setXManaCostPaid(0);
|
||||||
|
setXManaCostPaidByColor(null);
|
||||||
|
setKickerMagnitude(0);
|
||||||
|
setPseudoMultiKickerMagnitude(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final int getFinalChapterNr() {
|
public final int getFinalChapterNr() {
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ package forge.game.card;
|
|||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Predicates;
|
import com.google.common.base.Predicates;
|
||||||
import com.google.common.base.Strings;
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
@@ -3010,24 +3009,43 @@ public class CardFactoryUtil {
|
|||||||
|
|
||||||
inst.addTrigger(parsedTrigger);
|
inst.addTrigger(parsedTrigger);
|
||||||
} else if (keyword.startsWith("Saga")) {
|
} else if (keyword.startsWith("Saga")) {
|
||||||
// Saga there doesn't need Max value anymore?
|
|
||||||
final String[] k = keyword.split(":");
|
final String[] k = keyword.split(":");
|
||||||
final String[] abs = k[2].split(",");
|
final List<String> abs = Arrays.asList(k[2].split(","));
|
||||||
|
if (abs.size() != Integer.valueOf(k[1])) {
|
||||||
|
throw new RuntimeException("Saga max differ from Ability amount");
|
||||||
|
}
|
||||||
|
|
||||||
int i = 1;
|
int idx = 0;
|
||||||
for (String ab : abs) {
|
int skipId = 0;
|
||||||
|
for(String ab : abs) {
|
||||||
|
idx += 1;
|
||||||
|
if (idx <= skipId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
skipId = idx + abs.subList(idx - 1, abs.size()).lastIndexOf(ab);
|
||||||
|
StringBuilder desc = new StringBuilder();
|
||||||
|
for (int i = idx; i <= skipId; i++) {
|
||||||
|
if (i != idx) {
|
||||||
|
desc.append(", ");
|
||||||
|
}
|
||||||
|
desc.append(TextUtil.toRoman(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = idx; i <= skipId; i++) {
|
||||||
SpellAbility sa = AbilityFactory.getAbility(card, ab);
|
SpellAbility sa = AbilityFactory.getAbility(card, ab);
|
||||||
sa.setChapter(i);
|
sa.setChapter(i);
|
||||||
|
|
||||||
// TODO better logic for Roman numbers
|
StringBuilder trigStr = new StringBuilder("Mode$ CounterAdded | ValidCard$ Card.Self | TriggerZones$ Battlefield");
|
||||||
// In the Description try to merge Chapter trigger with the Same Effect
|
trigStr.append("| CounterType$ LORE | CounterAmount$ EQ").append(i);
|
||||||
String trigStr = "Mode$ CounterAdded | ValidCard$ Card.Self | TriggerZones$ Battlefield"
|
if (i != idx) {
|
||||||
+ "| CounterType$ LORE | CounterAmount$ EQ" + i
|
trigStr.append(" | Secondary$ True");
|
||||||
+ "| TriggerDescription$ " + Strings.repeat("I", i) + " - " + sa.getDescription();
|
}
|
||||||
final Trigger t = TriggerHandler.parseTrigger(trigStr, card, intrinsic);
|
trigStr.append("| TriggerDescription$ ").append(desc).append(" — ").append(sa.getDescription());
|
||||||
|
final Trigger t = TriggerHandler.parseTrigger(trigStr.toString(), card, intrinsic);
|
||||||
t.setOverridingAbility(sa);
|
t.setOverridingAbility(sa);
|
||||||
inst.addTrigger(t);
|
inst.addTrigger(t);
|
||||||
++i;
|
}
|
||||||
}
|
}
|
||||||
} else if (keyword.equals("Soulbond")) {
|
} else if (keyword.equals("Soulbond")) {
|
||||||
// Setup ETB trigger for card with Soulbond keyword
|
// Setup ETB trigger for card with Soulbond keyword
|
||||||
|
|||||||
@@ -882,6 +882,10 @@ public class Combat {
|
|||||||
return true; // is blocking something at the moment
|
return true; // is blocking something at the moment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!blocker.isLKI()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
CombatLki lki = lkiCache.get(blocker);
|
CombatLki lki = lkiCache.get(blocker);
|
||||||
return null != lki && !lki.isAttacker; // was blocking something anyway
|
return null != lki && !lki.isAttacker; // was blocking something anyway
|
||||||
}
|
}
|
||||||
@@ -893,6 +897,10 @@ public class Combat {
|
|||||||
return true; // is blocking the attacker's band at the moment
|
return true; // is blocking the attacker's band at the moment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!blocker.isLKI()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
CombatLki lki = lkiCache.get(blocker);
|
CombatLki lki = lkiCache.get(blocker);
|
||||||
return null != lki && !lki.isAttacker && lki.relatedBands.contains(ab); // was blocking that very band
|
return null != lki && !lki.isAttacker && lki.relatedBands.contains(ab); // was blocking that very band
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ public class ManaPool extends ManaConversionMatrix implements Iterable<Mana> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mana.addsCounters(sa)) {
|
if (mana.addsCounters(sa)) {
|
||||||
mana.getManaAbility().createETBCounters(host);
|
mana.getManaAbility().createETBCounters(host, this.owner);
|
||||||
}
|
}
|
||||||
if (mana.triggersWhenSpent()) {
|
if (mana.triggersWhenSpent()) {
|
||||||
mana.getManaAbility().addTriggersWhenSpent(sa, host);
|
mana.getManaAbility().addTriggersWhenSpent(sa, host);
|
||||||
|
|||||||
@@ -19,9 +19,11 @@ package forge.game.spellability;
|
|||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
import forge.card.ColorSet;
|
import forge.card.ColorSet;
|
||||||
import forge.card.MagicColor;
|
import forge.card.MagicColor;
|
||||||
import forge.card.mana.ManaAtom;
|
import forge.card.mana.ManaAtom;
|
||||||
|
import forge.game.Game;
|
||||||
import forge.game.ability.AbilityFactory;
|
import forge.game.ability.AbilityFactory;
|
||||||
import forge.game.ability.AbilityKey;
|
import forge.game.ability.AbilityKey;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
@@ -34,6 +36,8 @@ import forge.game.replacement.*;
|
|||||||
import forge.game.trigger.Trigger;
|
import forge.game.trigger.Trigger;
|
||||||
import forge.game.trigger.TriggerHandler;
|
import forge.game.trigger.TriggerHandler;
|
||||||
import forge.game.trigger.TriggerType;
|
import forge.game.trigger.TriggerType;
|
||||||
|
import forge.game.zone.ZoneType;
|
||||||
|
import forge.util.Lang;
|
||||||
import forge.util.TextUtil;
|
import forge.util.TextUtil;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@@ -227,10 +231,26 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
/**
|
/**
|
||||||
* createETBCounters
|
* createETBCounters
|
||||||
*/
|
*/
|
||||||
public void createETBCounters(Card c) {
|
public void createETBCounters(Card c, Player controller) {
|
||||||
String[] parse = this.addsCounters.split("_");
|
String[] parse = this.addsCounters.split("_");
|
||||||
// Convert random SVars if there are other cards with this effect
|
// Convert random SVars if there are other cards with this effect
|
||||||
if (c.isValid(parse[0], c.getController(), c, null)) {
|
if (c.isValid(parse[0], c.getController(), c, null)) {
|
||||||
|
final Game game = this.sourceCard.getGame();
|
||||||
|
final Card eff = new Card(game.nextCardId(), game);
|
||||||
|
eff.setTimestamp(game.getNextTimestamp());
|
||||||
|
eff.setName(sourceCard.getName() + "'s Effect");
|
||||||
|
eff.addType("Effect");
|
||||||
|
eff.setToken(true); // Set token to true, so when leaving play it gets nuked
|
||||||
|
eff.setOwner(controller);
|
||||||
|
|
||||||
|
eff.setImageKey(sourceCard.getImageKey());
|
||||||
|
eff.setColor(MagicColor.COLORLESS);
|
||||||
|
eff.setImmutable(true);
|
||||||
|
// try to get the SpellAbility from the mana ability
|
||||||
|
//eff.setEffectSource((SpellAbility)null);
|
||||||
|
|
||||||
|
eff.addRemembered(c);
|
||||||
|
|
||||||
String abStr = "DB$ PutCounter | Defined$ ReplacedCard | CounterType$ " + parse[1]
|
String abStr = "DB$ PutCounter | Defined$ ReplacedCard | CounterType$ " + parse[1]
|
||||||
+ " | ETB$ True | CounterNum$ " + parse[2];
|
+ " | ETB$ True | CounterNum$ " + parse[2];
|
||||||
|
|
||||||
@@ -240,15 +260,37 @@ public class AbilityManaPart implements java.io.Serializable {
|
|||||||
}
|
}
|
||||||
CardFactoryUtil.setupETBReplacementAbility(sa);
|
CardFactoryUtil.setupETBReplacementAbility(sa);
|
||||||
|
|
||||||
String repeffstr = "Event$ Moved | ValidCard$ Card.Self | Destination$ Battlefield "
|
String desc = "It enters the battlefield with ";
|
||||||
+ " | Secondary$ True | Description$ CARDNAME"
|
desc += Lang.nounWithNumeral(parse[2], CounterType.valueOf(parse[1]).getName() + " counter");
|
||||||
+ " enters the battlefield with " + CounterType.valueOf(parse[1]).getName() + " counters.";
|
desc += " on it.";
|
||||||
|
|
||||||
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, c, false);
|
String repeffstr = "Event$ Moved | ValidCard$ Card.IsRemembered | Destination$ Battlefield | Description$ " + desc;
|
||||||
|
|
||||||
|
ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, eff, true);
|
||||||
re.setLayer(ReplacementLayer.Other);
|
re.setLayer(ReplacementLayer.Other);
|
||||||
re.setOverridingAbility(sa);
|
re.setOverridingAbility(sa);
|
||||||
|
|
||||||
c.addReplacementEffect(re);
|
eff.addReplacementEffect(re);
|
||||||
|
|
||||||
|
// Forgot Trigger
|
||||||
|
String trig = "Mode$ ChangesZone | ValidCard$ Card.IsRemembered | Origin$ Stack | Destination$ Any | TriggerZones$ Command | Static$ True";
|
||||||
|
String forgetEffect = "DB$ Pump | ForgetObjects$ TriggeredCard";
|
||||||
|
String exileEffect = "DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile"
|
||||||
|
+ " | ConditionDefined$ Remembered | ConditionPresent$ Card | ConditionCompare$ EQ0";
|
||||||
|
|
||||||
|
SpellAbility saForget = AbilityFactory.getAbility(forgetEffect, eff);
|
||||||
|
AbilitySub saExile = (AbilitySub) AbilityFactory.getAbility(exileEffect, eff);
|
||||||
|
saForget.setSubAbility(saExile);
|
||||||
|
|
||||||
|
final Trigger parsedTrigger = TriggerHandler.parseTrigger(trig, eff, true);
|
||||||
|
parsedTrigger.setOverridingAbility(saForget);
|
||||||
|
eff.addTrigger(parsedTrigger);
|
||||||
|
eff.updateStateForView();
|
||||||
|
|
||||||
|
// TODO: Add targeting to the effect so it knows who it's dealing with
|
||||||
|
game.getTriggerHandler().suppressMode(TriggerType.ChangesZone);
|
||||||
|
game.getAction().moveTo(ZoneType.Command, eff, null);
|
||||||
|
game.getTriggerHandler().clearSuppression(TriggerType.ChangesZone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1299,6 +1299,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
String announce = getParam("Announce");
|
String announce = getParam("Announce");
|
||||||
if (StringUtils.isBlank(announce)) {
|
if (StringUtils.isBlank(announce)) {
|
||||||
mapParams.put("Announce", variable);
|
mapParams.put("Announce", variable);
|
||||||
|
originalMapParams.put("Announce", variable);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String[] announcedOnes = TextUtil.split(announce, ',');
|
String[] announcedOnes = TextUtil.split(announce, ',');
|
||||||
@@ -1308,6 +1309,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mapParams.put("Announce", announce + ";" + variable);
|
mapParams.put("Announce", announce + ";" + variable);
|
||||||
|
originalMapParams.put("Announce", announce + ";" + variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isXCost() {
|
public boolean isXCost() {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="19"
|
android:minSdkVersion="19"
|
||||||
android:targetSdkVersion="21" />
|
android:targetSdkVersion="26" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- This one needs Android Runtime Permission for Android 6+ -->
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- This one needs Android Runtime Permission for Android 6+ -->
|
||||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
|||||||
@@ -142,7 +142,7 @@
|
|||||||
<debug>true</debug>
|
<debug>true</debug>
|
||||||
</sign>
|
</sign>
|
||||||
<sdk>
|
<sdk>
|
||||||
<platform>25</platform>
|
<platform>26</platform>
|
||||||
</sdk>
|
</sdk>
|
||||||
<dexForceJumbo>true</dexForceJumbo>
|
<dexForceJumbo>true</dexForceJumbo>
|
||||||
<androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile>
|
<androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile>
|
||||||
@@ -183,7 +183,7 @@
|
|||||||
<debug>false</debug>
|
<debug>false</debug>
|
||||||
</sign>
|
</sign>
|
||||||
<sdk>
|
<sdk>
|
||||||
<platform>25</platform>
|
<platform>26</platform>
|
||||||
</sdk>
|
</sdk>
|
||||||
<zipalign>
|
<zipalign>
|
||||||
<verbose>false</verbose>
|
<verbose>false</verbose>
|
||||||
|
|||||||
@@ -9,4 +9,4 @@
|
|||||||
|
|
||||||
# Project target.
|
# Project target.
|
||||||
project.type=0
|
project.type=0
|
||||||
target=android-20
|
target=android-26
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ public final class CEditorConstructed extends CDeckEditor<Deck> {
|
|||||||
case TinyLeaders:
|
case TinyLeaders:
|
||||||
allSections.add(DeckSection.Commander);
|
allSections.add(DeckSection.Commander);
|
||||||
|
|
||||||
commanderFilter = CardRulesPredicates.Presets.CAN_BE_COMMANDER;
|
commanderFilter = CardRulesPredicates.Presets.CAN_BE_TINY_LEADERS_COMMANDER;
|
||||||
commanderPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(Predicates.compose(commanderFilter, PaperCard.FN_GET_RULES)), PaperCard.class);
|
commanderPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(Predicates.compose(commanderFilter, PaperCard.FN_GET_RULES)), PaperCard.class);
|
||||||
normalPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(), PaperCard.class);
|
normalPool = ItemPool.createFrom(FModel.getMagicDb().getCommonCards().getAllCards(), PaperCard.class);
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ import org.apache.commons.lang3.StringUtils;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static forge.card.CardRenderer.CROP_MULTIPLIER;
|
||||||
|
import static forge.card.CardRenderer.isModernFrame;
|
||||||
|
|
||||||
public class CardImageRenderer {
|
public class CardImageRenderer {
|
||||||
private static final float BASE_IMAGE_WIDTH = 360;
|
private static final float BASE_IMAGE_WIDTH = 360;
|
||||||
private static final float BASE_IMAGE_HEIGHT = 504;
|
private static final float BASE_IMAGE_HEIGHT = 504;
|
||||||
@@ -357,13 +360,19 @@ public class CardImageRenderer {
|
|||||||
float new_yRotate = (dispH - new_w) /2;
|
float new_yRotate = (dispH - new_w) /2;
|
||||||
boolean rotateSplit = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_SPLIT_CARDS);
|
boolean rotateSplit = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_SPLIT_CARDS);
|
||||||
boolean rotatePlane = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON);
|
boolean rotatePlane = FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_ROTATE_PLANE_OR_PHENOMENON);
|
||||||
|
float croppedArea = isModernFrame(card) ? CROP_MULTIPLIER : 0.97f;
|
||||||
|
float minusxy = isModernFrame(card) ? 0.0f : 0.13f*radius;
|
||||||
|
if (card.getCurrentState().getSetCode().equals("LEA")||card.getCurrentState().getSetCode().equals("LEB")) {
|
||||||
|
croppedArea = 0.975f;
|
||||||
|
minusxy = 0.135f*radius;
|
||||||
|
}
|
||||||
if (rotatePlane && (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane())) {
|
if (rotatePlane && (card.getCurrentState().isPhenomenon() || card.getCurrentState().isPlane())) {
|
||||||
if (Forge.enableUIMask){
|
if (Forge.enableUIMask){
|
||||||
if (ImageCache.isExtendedArt(card))
|
if (ImageCache.isExtendedArt(card))
|
||||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
||||||
else {
|
else {
|
||||||
g.drawRotatedImage(FSkin.getBorders().get(0), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
g.drawRotatedImage(FSkin.getBorders().get(0), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
||||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), new_x+radius/2, new_y+radius/2, new_w*0.96f, new_h*0.96f, (new_x+radius/2) + (new_w*0.96f) / 2, (new_y+radius/2) + (new_h*0.96f) / 2, -90);
|
g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), new_x+radius/2-minusxy, new_y+radius/2-minusxy, new_w*croppedArea, new_h*croppedArea, (new_x+radius/2-minusxy) + (new_w*croppedArea) / 2, (new_y+radius/2-minusxy) + (new_h*croppedArea) / 2, -90);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, -90);
|
||||||
@@ -374,7 +383,7 @@ public class CardImageRenderer {
|
|||||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||||
else {
|
else {
|
||||||
g.drawRotatedImage(FSkin.getBorders().get(ImageCache.getFSkinBorders(card)), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
g.drawRotatedImage(FSkin.getBorders().get(ImageCache.getFSkinBorders(card)), new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), new_x + radius / 2, new_y + radius / 2, new_w * 0.96f, new_h * 0.96f, (new_x + radius / 2) + (new_w * 0.96f) / 2, (new_y + radius / 2) + (new_h * 0.96f) / 2, isAftermath ? 90 : -90);
|
g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), new_x + radius / 2-minusxy, new_y + radius / 2-minusxy, new_w * croppedArea, new_h * croppedArea, (new_x + radius / 2-minusxy) + (new_w * croppedArea) / 2, (new_y + radius / 2-minusxy) + (new_h * croppedArea) / 2, isAftermath ? 90 : -90);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
g.drawRotatedImage(image, new_x, new_y, new_w, new_h, new_x + new_w / 2, new_y + new_h / 2, isAftermath ? 90 : -90);
|
||||||
@@ -384,7 +393,7 @@ public class CardImageRenderer {
|
|||||||
g.drawImage(image, x, y, w, h);
|
g.drawImage(image, x, y, w, h);
|
||||||
else {
|
else {
|
||||||
g.drawImage(ImageCache.getBorderImage(card, canshow), x, y, w, h);
|
g.drawImage(ImageCache.getBorderImage(card, canshow), x, y, w, h);
|
||||||
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f, y + radius / 2, w * 0.96f, h * 0.96f);
|
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (canshow && !ImageKeys.getTokenKey(ImageKeys.MORPH_IMAGE).equals(card.getState(altState).getImageKey()))
|
if (canshow && !ImageKeys.getTokenKey(ImageKeys.MORPH_IMAGE).equals(card.getState(altState).getImageKey()))
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ public class CardRenderer {
|
|||||||
private static final float NAME_COST_THRESHOLD = Utils.scale(200);
|
private static final float NAME_COST_THRESHOLD = Utils.scale(200);
|
||||||
private static final float BORDER_THICKNESS = Utils.scale(1);
|
private static final float BORDER_THICKNESS = Utils.scale(1);
|
||||||
public static final float PADDING_MULTIPLIER = 0.021f;
|
public static final float PADDING_MULTIPLIER = 0.021f;
|
||||||
|
public static final float CROP_MULTIPLIER = 0.96f;
|
||||||
|
|
||||||
private static Map<Integer, BitmapFont> counterFonts = new HashMap<>();
|
private static Map<Integer, BitmapFont> counterFonts = new HashMap<>();
|
||||||
private static final Color counterBackgroundColor = new Color(0f, 0f, 0f, 0.9f);
|
private static final Color counterBackgroundColor = new Color(0f, 0f, 0f, 0.9f);
|
||||||
@@ -142,6 +143,49 @@ public class CardRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isModernFrame(IPaperCard c) {
|
||||||
|
if (c == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CardEdition ed = FModel.getMagicDb().getEditions().get(c.getEdition());
|
||||||
|
if (ed != null) {
|
||||||
|
switch (ed.getCode()) {
|
||||||
|
case "MED":
|
||||||
|
case "ME2":
|
||||||
|
case "ME3":
|
||||||
|
case "ME4":
|
||||||
|
case "TSB":
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return ed.isModern();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isModernFrame(CardView c) {
|
||||||
|
if (c == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CardView.CardStateView state = c.getCurrentState();
|
||||||
|
CardEdition ed = FModel.getMagicDb().getEditions().get(state.getSetCode());
|
||||||
|
if (ed != null) {
|
||||||
|
switch (ed.getCode()) {
|
||||||
|
case "MED":
|
||||||
|
case "ME2":
|
||||||
|
case "ME3":
|
||||||
|
case "ME4":
|
||||||
|
case "TSB":
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return ed.isModern();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static float getCardListItemHeight(boolean compactMode) {
|
public static float getCardListItemHeight(boolean compactMode) {
|
||||||
if (compactMode) {
|
if (compactMode) {
|
||||||
return MANA_SYMBOL_SIZE + 2 * FList.PADDING;
|
return MANA_SYMBOL_SIZE + 2 * FList.PADDING;
|
||||||
@@ -402,7 +446,12 @@ public class CardRenderer {
|
|||||||
public static void drawCard(Graphics g, IPaperCard pc, float x, float y, float w, float h, CardStackPosition pos) {
|
public static void drawCard(Graphics g, IPaperCard pc, float x, float y, float w, float h, CardStackPosition pos) {
|
||||||
Texture image = new RendererCachedCardImage(pc, false).getImage();
|
Texture image = new RendererCachedCardImage(pc, false).getImage();
|
||||||
float radius = (h - w)/8;
|
float radius = (h - w)/8;
|
||||||
|
float croppedArea = isModernFrame(pc) ? CROP_MULTIPLIER : 0.97f;
|
||||||
|
float minusxy = isModernFrame(pc) ? 0.0f : 0.13f*radius;
|
||||||
|
if (pc.getEdition().equals("LEA")||pc.getEdition().equals("LEB")) {
|
||||||
|
croppedArea = 0.975f;
|
||||||
|
minusxy = 0.135f*radius;
|
||||||
|
}
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
if (image == ImageCache.defaultImage) {
|
if (image == ImageCache.defaultImage) {
|
||||||
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(pc), false, x, y, w, h, pos);
|
CardImageRenderer.drawCardImage(g, CardView.getCardForUi(pc), false, x, y, w, h, pos);
|
||||||
@@ -413,7 +462,7 @@ public class CardRenderer {
|
|||||||
g.drawImage(image, x, y, w, h);
|
g.drawImage(image, x, y, w, h);
|
||||||
else {
|
else {
|
||||||
g.drawImage(ImageCache.getBorderImage(pc), x, y, w, h);
|
g.drawImage(ImageCache.getBorderImage(pc), x, y, w, h);
|
||||||
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f, y + radius / 2, w * 0.96f, h * 0.96f);
|
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
g.drawImage(image, x, y, w, h);
|
g.drawImage(image, x, y, w, h);
|
||||||
@@ -437,7 +486,12 @@ public class CardRenderer {
|
|||||||
Texture image = new RendererCachedCardImage(card, false).getImage();
|
Texture image = new RendererCachedCardImage(card, false).getImage();
|
||||||
FImage sleeves = MatchController.getPlayerSleeve(card.getOwner());
|
FImage sleeves = MatchController.getPlayerSleeve(card.getOwner());
|
||||||
float radius = (h - w)/8;
|
float radius = (h - w)/8;
|
||||||
|
float croppedArea = isModernFrame(card) ? CROP_MULTIPLIER : 0.97f;
|
||||||
|
float minusxy = isModernFrame(card) ? 0.0f : 0.13f*radius;
|
||||||
|
if (card.getCurrentState().getSetCode().equals("LEA")||card.getCurrentState().getSetCode().equals("LEB")) {
|
||||||
|
croppedArea = 0.975f;
|
||||||
|
minusxy = 0.135f*radius;
|
||||||
|
}
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
if (image == ImageCache.defaultImage) {
|
if (image == ImageCache.defaultImage) {
|
||||||
CardImageRenderer.drawCardImage(g, card, false, x, y, w, h, pos);
|
CardImageRenderer.drawCardImage(g, card, false, x, y, w, h, pos);
|
||||||
@@ -450,7 +504,7 @@ public class CardRenderer {
|
|||||||
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
|
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
|
||||||
else {
|
else {
|
||||||
g.drawRotatedImage(FSkin.getBorders().get(0), x, y, w, h, x + w / 2, y + h / 2, -90);
|
g.drawRotatedImage(FSkin.getBorders().get(0), x, y, w, h, x + w / 2, y + h / 2, -90);
|
||||||
g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), x+radius/2.3f, y+radius/2, w*0.96f, h*0.96f, (x+radius/2.3f) + (w*0.96f) / 2, (y+radius/2) + (h*0.96f) / 2, -90);
|
g.drawRotatedImage(ImageCache.croppedBorderImage(image, fullborder), x+radius/2.3f-minusxy, y+radius/2-minusxy, w*croppedArea, h*croppedArea, (x+radius/2.3f-minusxy) + (w*croppedArea) / 2, (y+radius/2-minusxy) + (h*croppedArea) / 2, -90);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
|
g.drawRotatedImage(image, x, y, w, h, x + w / 2, y + h / 2, -90);
|
||||||
@@ -461,7 +515,7 @@ public class CardRenderer {
|
|||||||
else {
|
else {
|
||||||
boolean t = (card.getCurrentState().getOriginalColors() != card.getCurrentState().getColors()) || card.getCurrentState().hasChangeColors();
|
boolean t = (card.getCurrentState().getOriginalColors() != card.getCurrentState().getColors()) || card.getCurrentState().hasChangeColors();
|
||||||
g.drawBorderImage(ImageCache.getBorderImage(card, canshow), ImageCache.getTint(card), x, y, w, h, t); //tint check for changed colors
|
g.drawBorderImage(ImageCache.getBorderImage(card, canshow), ImageCache.getTint(card), x, y, w, h, t); //tint check for changed colors
|
||||||
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f, y + radius / 2, w * 0.96f, h * 0.96f);
|
g.drawImage(ImageCache.croppedBorderImage(image, fullborder), x + radius / 2.4f-minusxy, y + radius / 2-minusxy, w * croppedArea, h * croppedArea);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (canshow)
|
if (canshow)
|
||||||
@@ -1119,8 +1173,14 @@ public class CardRenderer {
|
|||||||
|
|
||||||
public static void drawFoilEffect(Graphics g, CardView card, float x, float y, float w, float h, boolean inZoomer) {
|
public static void drawFoilEffect(Graphics g, CardView card, float x, float y, float w, float h, boolean inZoomer) {
|
||||||
float new_x = x; float new_y = y; float new_w = w; float new_h = h; float radius = (h - w)/8;
|
float new_x = x; float new_y = y; float new_w = w; float new_h = h; float radius = (h - w)/8;
|
||||||
|
float croppedArea = isModernFrame(card) ? CROP_MULTIPLIER : 0.97f;
|
||||||
|
float minusxy = isModernFrame(card) ? 0.0f : 0.13f*radius;
|
||||||
|
if (card.getCurrentState().getSetCode().equals("LEA")||card.getCurrentState().getSetCode().equals("LEB")) {
|
||||||
|
croppedArea = 0.975f;
|
||||||
|
minusxy = 0.135f*radius;
|
||||||
|
}
|
||||||
if (Forge.enableUIMask) {
|
if (Forge.enableUIMask) {
|
||||||
new_x += radius/2.4f; new_y += radius/2; new_w = w * 0.96f; new_h = h * 0.96f;
|
new_x += radius/2.4f-minusxy; new_y += radius/2-minusxy; new_w = w * croppedArea; new_h = h * croppedArea;
|
||||||
}
|
}
|
||||||
if (isPreferenceEnabled(FPref.UI_OVERLAY_FOIL_EFFECT) && MatchController.instance.mayView(card)) {
|
if (isPreferenceEnabled(FPref.UI_OVERLAY_FOIL_EFFECT) && MatchController.instance.mayView(card)) {
|
||||||
boolean rotateSplit = isPreferenceEnabled(FPref.UI_ROTATE_SPLIT_CARDS) && card.isSplitCard() && inZoomer;
|
boolean rotateSplit = isPreferenceEnabled(FPref.UI_ROTATE_SPLIT_CARDS) && card.isSplitCard() && inZoomer;
|
||||||
|
|||||||
@@ -219,7 +219,22 @@ public class CardZoom extends FOverlay {
|
|||||||
float w = getWidth();
|
float w = getWidth();
|
||||||
float h = getHeight();
|
float h = getHeight();
|
||||||
float messageHeight = FDialog.MSG_HEIGHT;
|
float messageHeight = FDialog.MSG_HEIGHT;
|
||||||
float maxCardHeight = h - 2 * messageHeight;
|
float AspectRatioMultiplier = 2;
|
||||||
|
switch (Forge.extrawide) {
|
||||||
|
case "default":
|
||||||
|
AspectRatioMultiplier = 3; //good for tablets with 16:10 or similar
|
||||||
|
break;
|
||||||
|
case "wide":
|
||||||
|
AspectRatioMultiplier = 2.5f;
|
||||||
|
break;
|
||||||
|
case "extrawide":
|
||||||
|
AspectRatioMultiplier = 2; //good for tall phones with 21:9 or similar
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
AspectRatioMultiplier = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
float maxCardHeight = h - AspectRatioMultiplier * messageHeight; //maxheight of currently zoomed card
|
||||||
|
|
||||||
float cardWidth, cardHeight, y;
|
float cardWidth, cardHeight, y;
|
||||||
|
|
||||||
|
|||||||
@@ -856,6 +856,9 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
|
|||||||
case Brawl:
|
case Brawl:
|
||||||
isLegalCommander = card.getRules().canBeBrawlCommander();
|
isLegalCommander = card.getRules().canBeBrawlCommander();
|
||||||
break;
|
break;
|
||||||
|
case TinyLeaders:
|
||||||
|
isLegalCommander = card.getRules().canBeTinyLeadersCommander();
|
||||||
|
break;
|
||||||
case Oathbreaker:
|
case Oathbreaker:
|
||||||
isLegalCommander = card.getRules().canBeOathbreaker();
|
isLegalCommander = card.getRules().canBeOathbreaker();
|
||||||
captionSuffix = localizer.getMessage("lblOathbreaker");
|
captionSuffix = localizer.getMessage("lblOathbreaker");
|
||||||
|
|||||||
@@ -84,4 +84,4 @@ Modern Horizons, 3/6/WAR, MH1
|
|||||||
Core Set 2020, 3/6/M20, M20
|
Core Set 2020, 3/6/M20, M20
|
||||||
Throne of Eldraine, 3/6/ELD, ELD
|
Throne of Eldraine, 3/6/ELD, ELD
|
||||||
Theros Beyond Death, 3/6/THB, THB
|
Theros Beyond Death, 3/6/THB, THB
|
||||||
Mystery Booster, 3/6/MB1, MB1
|
Mystery Booster, 3/6/THB, MB1
|
||||||
@@ -4,8 +4,9 @@ Types:Creature Elemental Knight
|
|||||||
PT:4/6
|
PT:4/6
|
||||||
K:Vigilance
|
K:Vigilance
|
||||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDestroy | TriggerDescription$ When CARDNAME enters the battlefield, destroy up to one target nonland permanent. Its controller creates a 3/3 colorless Golem artifact creature token.
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDestroy | TriggerDescription$ When CARDNAME enters the battlefield, destroy up to one target nonland permanent. Its controller creates a 3/3 colorless Golem artifact creature token.
|
||||||
SVar:TrigDestroy:DB$ Destroy | TargetMin$ 0 | TargetMax$ 1 | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | SubAbility$ DBToken
|
SVar:TrigDestroy:DB$ Destroy | TargetMin$ 0 | TargetMax$ 1 | ValidTgts$ Permanent.nonLand | TgtPrompt$ Select target nonland permanent | RememberLKI$ True | SubAbility$ DBToken
|
||||||
SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_3_3_a_golem | TokenOwner$ TargetedController | LegacyImage$ c 3 3 a golem m20
|
SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_3_3_a_golem | TokenOwner$ RememberedController | LegacyImage$ c 3 3 a golem m20 | SubAbility$ DBCleanup
|
||||||
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigChangeZone | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, return target artifact or enchantment card from your graveyard to your hand.
|
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigChangeZone | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, return target artifact or enchantment card from your graveyard to your hand.
|
||||||
SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | ValidTgts$ Artifact.YouCtrl,Enchantment.YouCtrl
|
SVar:TrigChangeZone:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | ValidTgts$ Artifact.YouCtrl,Enchantment.YouCtrl
|
||||||
Oracle:Vigilance\nWhen Cavalier of Dawn enters the battlefield, destroy up to one target nonland permanent. Its controller creates a 3/3 colorless Golem artifact creature token.\nWhen Cavalier of Dawn dies, return target artifact or enchantment card from your graveyard to your hand.
|
Oracle:Vigilance\nWhen Cavalier of Dawn enters the battlefield, destroy up to one target nonland permanent. Its controller creates a 3/3 colorless Golem artifact creature token.\nWhen Cavalier of Dawn dies, return target artifact or enchantment card from your graveyard to your hand.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Name:Ghastly Demise
|
Name:Ghastly Demise
|
||||||
ManaCost:B
|
ManaCost:B
|
||||||
Types:Instant
|
Types:Instant
|
||||||
A:SP$ Destroy | Cost$ B | ValidTgts$ Creature.nonBlack+toughnessLEX | TgtPrompt$ Select target nonblack creature with toughness less than or equal to the number of cards in your graveyard. | References$ X | SpellDescription$ Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard.
|
A:SP$ Destroy | Cost$ B | ValidTgts$ Creature.nonBlack | TgtPrompt$ Select target nonblack creature | ConditionCheckSVar$ Y | ConditionSVarCompare$ LEX | References$ X,Y | StackDescription$ SpellDescription | SpellDescription$ Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard.
|
||||||
|
SVar:Y:Targeted$CardToughness
|
||||||
SVar:X:Count$InYourYard
|
SVar:X:Count$InYourYard
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/ghastly_demise.jpg
|
|
||||||
Oracle:Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard.
|
Oracle:Destroy target nonblack creature if its toughness is less than or equal to the number of cards in your graveyard.
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
Name:Nissa's Pilgrimage
|
Name:Nissa's Pilgrimage
|
||||||
ManaCost:2 G
|
ManaCost:2 G
|
||||||
Types:Sorcery
|
Types:Sorcery
|
||||||
A:SP$ ChangeZone | Cost$ 2 G | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Basic+Forest | ChangeNum$ 1 | SubAbility$ DBChangeZone1 | NoShuffle$ True | SpellDescription$ Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library. Spell mastery — If there are two or more instant or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two.
|
A:SP$ ChangeZone | Cost$ 2 G | Origin$ Library | Destination$ Library | ChangeType$ Land.Basic+Forest | ChangeNum$ X | References$ X,Y | RememberChanged$ True | SubAbility$ DBBattlefield | Shuffle$ False | StackDescription$ SpellDescription | SpellDescription$ Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library. Spell mastery — If there are two or more instant or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two.
|
||||||
SVar:DBChangeZone1:DB$ChangeZone | Origin$ Library | Destination$ Hand | SubAbility$ DBChangeZone2 | ChangeType$ Land.Basic+Forest | ChangeNum$ 1 | ConditionCheckSVar$ X | ConditionSVarCompare$ LT2 | References$ X
|
SVar:DBBattlefield:DB$ ChangeZone | Origin$ Library | Destination$ Battlefield | Tapped$ True | SubAbility$ DBHand | ChangeType$ Card.IsRemembered | ChangeNum$ 1 | Mandatory$ True | NoLooking$ True | SelectPrompt$ Select a card to go to the battlefield | Shuffle$ False | StackDescription$ None
|
||||||
SVar:DBChangeZone2:DB$ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Land.Basic+Forest | ChangeNum$ 2 | ConditionCheckSVar$ X | ConditionSVarCompare$ GE2 | References$ X
|
SVar:DBHand:DB$ ChangeZone | Origin$ Library | Destination$ Hand | Defined$ Remembered | NoLooking$ True | StackDescription$ None | SubAbility$ DBCleanup
|
||||||
SVar:X:Count$ValidGraveyard Instant.YouOwn,Sorcery.YouOwn
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/nissas_pilgrimage.jpg
|
SVar:X:Count$Compare Y GE2.3.2
|
||||||
|
SVar:Y:Count$ValidGraveyard Instant.YouOwn,Sorcery.YouOwn
|
||||||
Oracle:Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library.\nSpell mastery — If there are two or more instant or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two.
|
Oracle:Search your library for up to two basic Forest cards, reveal those cards, and put one onto the battlefield tapped and the rest into your hand. Then shuffle your library.\nSpell mastery — If there are two or more instant or sorcery cards in your graveyard, search your library for up to three basic Forest cards instead of two.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Name:Settle the Wreckage
|
|||||||
ManaCost:2 W W
|
ManaCost:2 W W
|
||||||
Types:Instant
|
Types:Instant
|
||||||
A:SP$ ChangeZoneAll | Cost$ 2 W W | ValidTgts$ Player | ChangeType$ Creature.attacking | TgtPrompt$ Select target player | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | SubAbility$ DBGetLands | SpellDescription$ Exile all attacking creatures target player controls. That player may search their library for that many basic lands, put those cards onto the battlefield tapped, then shuffle their library.
|
A:SP$ ChangeZoneAll | Cost$ 2 W W | ValidTgts$ Player | ChangeType$ Creature.attacking | TgtPrompt$ Select target player | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | SubAbility$ DBGetLands | SpellDescription$ Exile all attacking creatures target player controls. That player may search their library for that many basic lands, put those cards onto the battlefield tapped, then shuffle their library.
|
||||||
SVar:DBGetLands:DB$ ChangeZone | Optional$ True | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Basic | ChangeNum$ X | References$ X | DefinedPlayer$ RememberedController | ShuffleNonMandatory$ True | SubAbility$ DBCleanup
|
SVar:DBGetLands:DB$ ChangeZone | Optional$ True | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Basic | ChangeNum$ X | References$ X | DefinedPlayer$ TargetedPlayer | ShuffleNonMandatory$ True | SubAbility$ DBCleanup
|
||||||
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
|
||||||
SVar:X:Count$RememberedSize
|
SVar:X:Count$RememberedSize
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/settle_the_wreckage.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/settle_the_wreckage.jpg
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ ManaCost:1 W
|
|||||||
Types:Enchantment Saga
|
Types:Enchantment Saga
|
||||||
K:Saga:3:TrigChange,TrigToken,TrigGainLife
|
K:Saga:3:TrigChange,TrigToken,TrigGainLife
|
||||||
SVar:TrigChange:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Land.Plains+Basic | ChangeNum$ 1 | SpellDescription$ Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle your library.
|
SVar:TrigChange:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Land.Plains+Basic | ChangeNum$ 1 | SpellDescription$ Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle your library.
|
||||||
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_0_4_wall_defender | TokenOwner$ You | LegacyImage$ c 0 4 wall defender thb | SpellDescription$ Create a 0/4 colorless Wall artifact creature token with defender.
|
SVar:TrigToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_0_4_a_wall_defender | TokenOwner$ You | LegacyImage$ c 0 4 wall defender thb | SpellDescription$ Create a 0/4 colorless Wall artifact creature token with defender.
|
||||||
SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 2 | SpellDescription$ You gain 2 life.
|
SVar:TrigGainLife:DB$ GainLife | Defined$ You | LifeAmount$ 2 | SpellDescription$ You gain 2 life.
|
||||||
DeckHas:Ability$LifeGain & Ability$Token
|
DeckHas:Ability$LifeGain & Ability$Token
|
||||||
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI - Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle your library.\nII - Create a 0/4 colorless Wall artifact creature token with defender.\nIII - You gain 2 life.
|
Oracle:(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)\nI - Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle your library.\nII - Create a 0/4 colorless Wall artifact creature token with defender.\nIII - You gain 2 life.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Name:The Triumph of Anax
|
Name:The Triumph of Anax
|
||||||
ManaCost:2 R
|
ManaCost:2 R
|
||||||
Types:Enchantment Saga
|
Types:Enchantment Saga
|
||||||
K:Saga:3:DBPump,DBPump,DBPump,DBPick
|
K:Saga:4:DBPump,DBPump,DBPump,DBPick
|
||||||
SVar:DBPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ +X | References$ X | KW$ Trample | SpellDescription$ Until end of turn, target creature gains trample and gets +X/+0, where X is the number of lore counters on CARDNAME.
|
SVar:DBPump:DB$ Pump | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumAtt$ +X | References$ X | KW$ Trample | SpellDescription$ Until end of turn, target creature gains trample and gets +X/+0, where X is the number of lore counters on CARDNAME.
|
||||||
SVar:X:Count$CardCounters.LORE
|
SVar:X:Count$CardCounters.LORE
|
||||||
SVar:PlayMain1:TRUE
|
SVar:PlayMain1:TRUE
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ Prerelease=6 Boosters, 1 RareMythic+
|
|||||||
|
|
||||||
[tokens]
|
[tokens]
|
||||||
b_2_2_zombie
|
b_2_2_zombie
|
||||||
c_0_4_wall_defender
|
c_0_4_a_wall_defender
|
||||||
g_1_2_spider_reach
|
g_1_2_spider_reach
|
||||||
g_2_2_wolf
|
g_2_2_wolf
|
||||||
r_x_1_elemental_trample_haste
|
r_x_1_elemental_trample_haste
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ Order:101
|
|||||||
Type:Casual
|
Type:Casual
|
||||||
Subtype:Commander
|
Subtype:Commander
|
||||||
Sets:GRN, RNA, WAR, M20, ELD, THB
|
Sets:GRN, RNA, WAR, M20, ELD, THB
|
||||||
Banned:Sorcerous Spyglass;Oko, Thief of Crowns
|
Banned:Golos, Tireless Pilgrim; Oko, Thief of Crowns; Sorcerous Spyglass
|
||||||
|
|||||||
@@ -3,4 +3,4 @@ Name:Legacy
|
|||||||
Order:105
|
Order:105
|
||||||
Subtype:Legacy
|
Subtype:Legacy
|
||||||
Type:Sanctioned
|
Type:Sanctioned
|
||||||
Banned:Adriana's Valor; Advantageous Proclamation; Assemble the Rank and Vile; Backup Plan; Brago's Favor; Deathrite Shaman; Double Stroke; Echoing Boon; Emissary's Ploy; Gitaxian Probe; Hired Heist; Hold the Perimeter; Hymn of the Wilds; Immediate Action; Incendiary Dissent; Iterative Analysis; Muzzio's Preparations; Natural Unity; Power Play; Secret Summoning; Secrets of Paradise; Sentinel Dispatch; Sovereign's Realm; Summoner's Bond; Unexpected Potential; Weight Advantage; Worldknit; Amulet of Quoz; Bronze Tablet; Contract from Below; Darkpact; Demonic Attorney; Jeweled Bird; Rebirth; Tempest Efreet; Timmerian Fiends; Ancestral Recall; Balance; Bazaar of Baghdad; Black Lotus; Channel; Chaos Orb; Demonic Consultation; Demonic Tutor; Dig Through Time; Earthcraft; Falling Star; Fastbond; Flash; Frantic Search; Goblin Recruiter; Gush; Hermit Druid; Imperial Seal; Library of Alexandria; Mana Crypt; Mana Drain; Mana Vault; Memory Jar; Mental Misstep; Mind Twist; Mind's Desire; Mishra's Workshop; Mox Emerald; Mox Jet; Mox Pearl; Mox Ruby; Mox Sapphire; Mystical Tutor; Necropotence; Oath of Druids; Sensei's Divining Top; Shahrazad; Skullclamp; Sol Ring; Strip Mine; Survival of the Fittest; Time Vault; Time Walk; Timetwister; Tinker; Tolarian Academy; Treasure Cruise; Vampiric Tutor; Wheel of Fortune; Windfall; Wrenn and Six; Yawgmoth's Bargain; Yawgmoth's Will
|
Banned:Adriana's Valor; Advantageous Proclamation; Assemble the Rank and Vile; Backup Plan; Brago's Favor; Deathrite Shaman; Double Stroke; Echoing Boon; Emissary's Ploy; Gitaxian Probe; Hired Heist; Hold the Perimeter; Hymn of the Wilds; Immediate Action; Incendiary Dissent; Iterative Analysis; Muzzio's Preparations; Natural Unity; Power Play; Secret Summoning; Secrets of Paradise; Sentinel Dispatch; Sovereign's Realm; Summoner's Bond; Underworld Breach; Unexpected Potential; Weight Advantage; Worldknit; Amulet of Quoz; Bronze Tablet; Contract from Below; Darkpact; Demonic Attorney; Jeweled Bird; Rebirth; Tempest Efreet; Timmerian Fiends; Ancestral Recall; Balance; Bazaar of Baghdad; Black Lotus; Channel; Chaos Orb; Demonic Consultation; Demonic Tutor; Dig Through Time; Earthcraft; Falling Star; Fastbond; Flash; Frantic Search; Goblin Recruiter; Gush; Hermit Druid; Imperial Seal; Library of Alexandria; Mana Crypt; Mana Drain; Mana Vault; Memory Jar; Mental Misstep; Mind Twist; Mind's Desire; Mishra's Workshop; Mox Emerald; Mox Jet; Mox Pearl; Mox Ruby; Mox Sapphire; Mystical Tutor; Necropotence; Oath of Druids; Sensei's Divining Top; Shahrazad; Skullclamp; Sol Ring; Strip Mine; Survival of the Fittest; Time Vault; Time Walk; Timetwister; Tinker; Tolarian Academy; Treasure Cruise; Vampiric Tutor; Wheel of Fortune; Windfall; Wrenn and Six; Yawgmoth's Bargain; Yawgmoth's Will
|
||||||
|
|||||||
@@ -4,4 +4,4 @@ Order:103
|
|||||||
Subtype:Modern
|
Subtype:Modern
|
||||||
Type:Sanctioned
|
Type:Sanctioned
|
||||||
Sets:8ED, MRD, DST, 5DN, CHK, BOK, SOK, 9ED, RAV, GPT, DIS, CSP, TSP, TSB, PLC, FUT, 10E, LRW, EVE, SHM, MOR, ALA, CFX, ARB, M10, ZEN, WWK, ROE, M11, SOM, MBS, NPH, M12, ISD, DKA, AVR, M13, RTR, GTC, DGM, M14, THS, BNG, JOU, M15, KTK, FRF, DTK, MM2, ORI, BFZ, OGW, SOI, EMN, KLD, AER, AKH, W17, HOU, XLN, RIX, DOM, M19, G18, GRN, RNA, WAR, MH1, M20, ELD, THB
|
Sets:8ED, MRD, DST, 5DN, CHK, BOK, SOK, 9ED, RAV, GPT, DIS, CSP, TSP, TSB, PLC, FUT, 10E, LRW, EVE, SHM, MOR, ALA, CFX, ARB, M10, ZEN, WWK, ROE, M11, SOM, MBS, NPH, M12, ISD, DKA, AVR, M13, RTR, GTC, DGM, M14, THS, BNG, JOU, M15, KTK, FRF, DTK, MM2, ORI, BFZ, OGW, SOI, EMN, KLD, AER, AKH, W17, HOU, XLN, RIX, DOM, M19, G18, GRN, RNA, WAR, MH1, M20, ELD, THB
|
||||||
Banned:Ancient Den; Birthing Pod; Blazing Shoal; Bridge from Below; Chrome Mox; Cloudpost; Dark Depths; Deathrite Shaman; Dig Through Time; Dread Return; Eye of Ugin; Faithless Looting; Gitaxian Probe; Glimpse of Nature; Golgari Grave-Troll; Great Furnace; Green Sun's Zenith; Hogaak, Arisen Necropolis; Hypergenesis; Krark-Clan Ironworks; Mental Misstep; Mox Opal; Mycosynth Lattice; Oko, Thief of Crowns; Ponder; Preordain; Punishing Fire; Rite of Flame; Seat of the Synod; Second Sunrise; Seething Song; Sensei's Divining Top; Skullclamp; Splinter Twin; Summer Bloom; Treasure Cruise; Tree of Tales; Umezawa's Jitte; Vault of Whispers
|
Banned:Ancient Den; Birthing Pod; Blazing Shoal; Bridge from Below; Chrome Mox; Cloudpost; Dark Depths; Deathrite Shaman; Dig Through Time; Dread Return; Eye of Ugin; Faithless Looting; Gitaxian Probe; Glimpse of Nature; Golgari Grave-Troll; Great Furnace; Green Sun's Zenith; Hogaak, Arisen Necropolis; Hypergenesis; Krark-Clan Ironworks; Mental Misstep; Mox Opal; Mycosynth Lattice; Oko, Thief of Crowns; Once Upon A Time; Ponder; Preordain; Punishing Fire; Rite of Flame; Seat of the Synod; Second Sunrise; Seething Song; Sensei's Divining Top; Skullclamp; Splinter Twin; Summer Bloom; Treasure Cruise; Tree of Tales; Umezawa's Jitte; Vault of Whispers
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ btnResetJavaFutureCompatibilityWarnings=Restablecer las advertencias de compatib
|
|||||||
btnClearImageCache=Limpiar Caché de Imágenes
|
btnClearImageCache=Limpiar Caché de Imágenes
|
||||||
btnTokenPreviewer=Previsualizador de Fichas (Token)
|
btnTokenPreviewer=Previsualizador de Fichas (Token)
|
||||||
btnCopyToClipboard=Copiar al portapapeles
|
btnCopyToClipboard=Copiar al portapapeles
|
||||||
cbpAutoUpdater=Auto updater
|
cbpAutoUpdater=Actualizar Forge
|
||||||
nlAutoUpdater=Select the release channel to use for updating Forge
|
nlAutoUpdater=Selecciona la versión a utilizar para actualizar Forge
|
||||||
cbpSelectLanguage=Idioma
|
cbpSelectLanguage=Idioma
|
||||||
nlSelectLanguage=Seleccionar idioma (excepto partida). Todavía un trabajo en progreso) (Es necesario reiniciar Forge)
|
nlSelectLanguage=Seleccionar idioma (excepto partida). Todavía un trabajo en progreso) (Es necesario reiniciar Forge)
|
||||||
cbRemoveSmall=Eliminar Pequeñas Criaturas
|
cbRemoveSmall=Eliminar Pequeñas Criaturas
|
||||||
@@ -184,7 +184,7 @@ KeyboardShortcuts=Atajos de teclado
|
|||||||
#VSubmenuAchievements.java
|
#VSubmenuAchievements.java
|
||||||
lblAchievements=Logros
|
lblAchievements=Logros
|
||||||
#VSubmenuDownloaders.java
|
#VSubmenuDownloaders.java
|
||||||
btnCheckForUpdates=Check for Updates
|
btnCheckForUpdates=Comprobar Actualizaciones
|
||||||
btnDownloadSetPics=Descargar todas las Ediciones de Cartas
|
btnDownloadSetPics=Descargar todas las Ediciones de Cartas
|
||||||
btnDownloadPics=Descargar todas las Cartas
|
btnDownloadPics=Descargar todas las Cartas
|
||||||
btnDownloadPicsHQ=Descargar todas las Cartas en calidad alta (Muy lento!)
|
btnDownloadPicsHQ=Descargar todas las Cartas en calidad alta (Muy lento!)
|
||||||
@@ -197,7 +197,7 @@ btnImportPictures=Importar Datos
|
|||||||
btnHowToPlay=Cómo jugar (Inglés)
|
btnHowToPlay=Cómo jugar (Inglés)
|
||||||
btnDownloadPrices=Descargar los precios de las cartas
|
btnDownloadPrices=Descargar los precios de las cartas
|
||||||
btnLicensing=Detalles de la licencia
|
btnLicensing=Detalles de la licencia
|
||||||
lblCheckForUpdates=Check Forge server to see if there''s a more recent release
|
lblCheckForUpdates=Comprueba si en el servidor de Forge existe alguna versión más reciente
|
||||||
lblDownloadPics=Descargar la imagen de la carta por defecto para cada carta.
|
lblDownloadPics=Descargar la imagen de la carta por defecto para cada carta.
|
||||||
lblDownloadPicsHQ=Descargar la imagen en calidad alta de la carta por defecto para cada carta.
|
lblDownloadPicsHQ=Descargar la imagen en calidad alta de la carta por defecto para cada carta.
|
||||||
lblDownloadSetPics=Descargue todas las imágenes de cada carta (una por cada edición donde apareció la carta)
|
lblDownloadSetPics=Descargue todas las imágenes de cada carta (una por cada edición donde apareció la carta)
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ btnResetJavaFutureCompatibilityWarnings=重置Java兼容性警告
|
|||||||
btnClearImageCache=清除图片缓存
|
btnClearImageCache=清除图片缓存
|
||||||
btnTokenPreviewer=衍生物预览器
|
btnTokenPreviewer=衍生物预览器
|
||||||
btnCopyToClipboard=复制到剪切板
|
btnCopyToClipboard=复制到剪切板
|
||||||
|
cbpAutoUpdater=Auto updater
|
||||||
|
nlAutoUpdater=Select the release channel to use for updating Forge
|
||||||
cbpSelectLanguage=语言
|
cbpSelectLanguage=语言
|
||||||
cbpAutoUpdater=自动更新
|
cbpAutoUpdater=自动更新
|
||||||
nlAutoUpdater=选择用于更新Forge的发布渠道
|
nlAutoUpdater=选择用于更新Forge的发布渠道
|
||||||
@@ -197,7 +199,7 @@ btnImportPictures=导入数据
|
|||||||
btnHowToPlay=如何玩
|
btnHowToPlay=如何玩
|
||||||
btnDownloadPrices=下载卡牌价格
|
btnDownloadPrices=下载卡牌价格
|
||||||
btnLicensing=许可证详情
|
btnLicensing=许可证详情
|
||||||
lblCheckForUpdates=检查Forge服务器,查看是否有新的版本
|
lblCheckForUpdates=查看是否有新的版本
|
||||||
lblDownloadPics=下载缺省牌的图片
|
lblDownloadPics=下载缺省牌的图片
|
||||||
lblDownloadPicsHQ=下载缺省牌的高清图片
|
lblDownloadPicsHQ=下载缺省牌的高清图片
|
||||||
lblDownloadSetPics=下载每张牌的图片(每张牌出现一次)
|
lblDownloadSetPics=下载每张牌的图片(每张牌出现一次)
|
||||||
|
|||||||
@@ -12,6 +12,5 @@ turn=1
|
|||||||
activeplayer=ai
|
activeplayer=ai
|
||||||
activephase=MAIN1
|
activephase=MAIN1
|
||||||
humanhand=Lazotep Plating;Slaying Fire;So Tiny;Shock;Gideon's Triumph;Aspect of Manticore
|
humanhand=Lazotep Plating;Slaying Fire;So Tiny;Shock;Gideon's Triumph;Aspect of Manticore
|
||||||
humanbattlefield=The Akroan War|Counters:LORE=2|Id:2;Blood Aspirant;Flux Channeler;Naiad of Hidden Coves;Temple of Enlightenment|NoETBTrigs;Temple of Enlightenment|NoETBTrigs;Sacred Foundry|NoETBTrigs;Sacred Foundry|NoETBTrigs
|
humanbattlefield=The Akroan War|Counters:LORE=2|ExecuteScript:DBGainControl->1;Blood Aspirant;Flux Channeler;Naiad of Hidden Coves;Temple of Enlightenment|NoETBTrigs;Temple of Enlightenment|NoETBTrigs;Sacred Foundry|NoETBTrigs;Sacred Foundry|NoETBTrigs
|
||||||
aibattlefield=Underworld Dreams;Underworld Dreams;Underworld Dreams;Ferocity of the Wilds;Goblin Assault Team;Temple Thief;Mire Triton;Dreadhorde Butcher|Id:1
|
aibattlefield=Underworld Dreams;Underworld Dreams;Underworld Dreams;Ferocity of the Wilds;Goblin Assault Team;Temple Thief;Mire Triton;Dreadhorde Butcher|Id:1
|
||||||
humanprecast=2:DBGainControl->1
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 14 KiB |
@@ -1,6 +1,6 @@
|
|||||||
Name:Wall
|
Name:Wall
|
||||||
ManaCost:no cost
|
ManaCost:no cost
|
||||||
Types:Creature Wall
|
Types:Artifact Creature Wall
|
||||||
PT:0/4
|
PT:0/4
|
||||||
K:Defender
|
K:Defender
|
||||||
Oracle:Defender
|
Oracle:Defender
|
||||||
@@ -105,10 +105,7 @@ public class HumanPlaySpellAbility {
|
|||||||
if (ability.isSpell() && !ability.isCastFaceDown() && fromState == CardStateName.FaceDown) {
|
if (ability.isSpell() && !ability.isCastFaceDown() && fromState == CardStateName.FaceDown) {
|
||||||
c.turnFaceUp();
|
c.turnFaceUp();
|
||||||
}
|
}
|
||||||
c.setCastSA(ability);
|
ability.setHostCard(game.getAction().moveToStack(c, ability));
|
||||||
ability.setLastStateBattlefield(game.getLastStateBattlefield());
|
|
||||||
ability.setLastStateGraveyard(game.getLastStateGraveyard());
|
|
||||||
ability.setHostCard(game.getAction().moveToStack(c, null));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ability.isCopied()) {
|
if (!ability.isCopied()) {
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import java.util.HashMap;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import forge.FThreads;
|
import forge.FThreads;
|
||||||
import forge.ImageKeys;
|
import forge.ImageKeys;
|
||||||
@@ -50,7 +52,14 @@ public abstract class ImageFetcher {
|
|||||||
setDownload.append(ImageUtil.getDownloadUrl(paperCard, backFace));
|
setDownload.append(ImageUtil.getDownloadUrl(paperCard, backFace));
|
||||||
downloadUrls.add(setDownload.toString());
|
downloadUrls.add(setDownload.toString());
|
||||||
|
|
||||||
int artIndex = Integer.parseInt(imageKey.split("\\|")[2]);
|
int artIndex = 1;
|
||||||
|
final Pattern pattern = Pattern.compile(
|
||||||
|
"^.:([^|]*\\|){2}(\\d+).*$"
|
||||||
|
);
|
||||||
|
Matcher matcher = pattern.matcher(imageKey);
|
||||||
|
if (matcher.matches()) {
|
||||||
|
artIndex = Integer.parseInt(matcher.group(2));
|
||||||
|
}
|
||||||
final StaticData data = StaticData.instance();
|
final StaticData data = StaticData.instance();
|
||||||
final String cardNum = data.getCommonCards().getCardCollectorNumber(paperCard.getName(), paperCard.getEdition(), artIndex);
|
final String cardNum = data.getCommonCards().getCardCollectorNumber(paperCard.getName(), paperCard.getEdition(), artIndex);
|
||||||
if (cardNum != null) {
|
if (cardNum != null) {
|
||||||
|
|||||||
Reference in New Issue
Block a user