diff --git a/forge-ai/pom.xml b/forge-ai/pom.xml index f55c04c62db..096751cb7d0 100644 --- a/forge-ai/pom.xml +++ b/forge-ai/pom.xml @@ -6,7 +6,7 @@ forge forge - 1.6.30-SNAPSHOT + 1.6.31-SNAPSHOT forge-ai diff --git a/forge-ai/src/main/java/forge/ai/AiBlockController.java b/forge-ai/src/main/java/forge/ai/AiBlockController.java index fd365f9ddbc..bef6eaa8961 100644 --- a/forge-ai/src/main/java/forge/ai/AiBlockController.java +++ b/forge-ai/src/main/java/forge/ai/AiBlockController.java @@ -1281,7 +1281,8 @@ public class AiBlockController { oppCreatureCount = ComputerUtil.countUsefulCreatures(attackersLeft.get(0).getController()); } - if (attacker.getOwner().equals(ai) && "6".equals(attacker.getSVar("SacMe"))) { + if (attacker != null && attacker.getOwner() != null) + if (attacker.getOwner().equals(ai) && "6".equals(attacker.getSVar("SacMe"))) { // Temporarily controlled object - don't trade with it // TODO: find a more reliable way to figure out that control will be reestablished next turn return false; diff --git a/forge-ai/src/main/java/forge/ai/AiController.java b/forge-ai/src/main/java/forge/ai/AiController.java index 4add78baf31..b4b3293d108 100644 --- a/forge-ai/src/main/java/forge/ai/AiController.java +++ b/forge-ai/src/main/java/forge/ai/AiController.java @@ -59,6 +59,7 @@ import forge.item.PaperCard; import forge.util.Aggregates; import forge.util.Expressions; import forge.util.MyRandom; +import forge.util.ComparatorUtil; import forge.util.collect.FCollectionView; import io.sentry.Sentry; import io.sentry.event.BreadcrumbBuilder; @@ -609,7 +610,15 @@ public class AiController { ComputerUtilAbility.getAvailableCards(game, player); List all = ComputerUtilAbility.getSpellAbilities(cards, player); - Collections.sort(all, saComparator); // put best spells first + + try { + Collections.sort(all, saComparator); // put best spells first + } + catch (IllegalArgumentException ex) { + System.err.println(ex.getMessage()); + String assertex = ComparatorUtil.verifyTransitivity(saComparator, all); + Sentry.capture(ex.getMessage() + "\nAssertionError [verifyTransitivity]: " + assertex); + } for (final SpellAbility sa : ComputerUtilAbility.getOriginalAndAltCostAbilities(all, player)) { ApiType saApi = sa.getApi(); @@ -1572,8 +1581,15 @@ public class AiController { if (all == null || all.isEmpty()) return null; - Collections.sort(all, saComparator); // put best spells first - + try { + Collections.sort(all, saComparator); // put best spells first + } + catch (IllegalArgumentException ex) { + System.err.println(ex.getMessage()); + String assertex = ComparatorUtil.verifyTransitivity(saComparator, all); + Sentry.capture(ex.getMessage() + "\nAssertionError [verifyTransitivity]: " + assertex); + } + for (final SpellAbility sa : ComputerUtilAbility.getOriginalAndAltCostAbilities(all, player)) { // Don't add Counterspells to the "normal" playcard lookups if (skipCounter && sa.getApi() == ApiType.Counter) { @@ -1830,7 +1846,7 @@ public class AiController { // Special case for Bow to My Command which simulates a complex tap cost via ChooseCard // TODO: consider enhancing support for tapXType in UnlessCost to get rid of this hack if ("BowToMyCommand".equals(sa.getParam("AILogic"))) { - if (!sa.getHostCard().getZone().is(ZoneType.Command)) { + if (!sa.getHostCard().isInZone(ZoneType.Command)) { // Make sure that other opponents do not tap for an already abandoned scheme result.clear(); break; @@ -2079,8 +2095,7 @@ public class AiController { return true; } - public ReplacementEffect chooseSingleReplacementEffect(List list, - Map runParams) { + public ReplacementEffect chooseSingleReplacementEffect(List list) { // no need to choose anything if (list.size() <= 1) { return Iterables.getFirst(list, null); diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtil.java b/forge-ai/src/main/java/forge/ai/ComputerUtil.java index fd96b4a1bfb..f874561aaa1 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtil.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtil.java @@ -29,6 +29,7 @@ import forge.card.MagicColor; import forge.card.mana.ManaCostShard; import forge.game.*; import forge.game.ability.AbilityFactory; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; import forge.game.ability.effects.CharmEffect; @@ -2402,7 +2403,7 @@ public class ComputerUtil { } // if source is not on the battlefield anymore, choose +1/+1 // ones - if (!game.getCardState(source).getZone().is(ZoneType.Battlefield)) { + if (!game.getCardState(source).isInZone(ZoneType.Battlefield)) { return opponent ? "Feather" : "Quill"; } // if no hand cards, try to mill opponent @@ -2434,7 +2435,7 @@ public class ComputerUtil { } // if source is not on the battlefield anymore - if (!game.getCardState(source).getZone().is(ZoneType.Battlefield)) { + if (!game.getCardState(source).isInZone(ZoneType.Battlefield)) { return opponent ? "Strength" : "Numbers"; } @@ -2483,7 +2484,7 @@ public class ComputerUtil { } // if source is not on the battlefield anymore - if (!game.getCardState(source).getZone().is(ZoneType.Battlefield)) { + if (!game.getCardState(source).isInZone(ZoneType.Battlefield)) { return opponent ? "Sprout" : "Harvest"; } // TODO add Lifegain to +1/+1 counters trigger @@ -2849,10 +2850,9 @@ public class ComputerUtil { } // Run any applicable replacement effects. - final Map repParams = Maps.newHashMap(); - repParams.put("Affected", player); - repParams.put("LifeGained", 1); - repParams.put("Source", source); + final Map repParams = AbilityKey.mapFromAffected(player); + repParams.put(AbilityKey.LifeGained, 1); + repParams.put(AbilityKey.Source, source); List list = player.getGame().getReplacementHandler().getReplacementList( ReplacementType.GainLife, @@ -2880,15 +2880,15 @@ public class ComputerUtil { } // Run any applicable replacement effects. - final Map repParams = Maps.newHashMap(); - repParams.put("Affected", player); - repParams.put("LifeGained", n); - repParams.put("Source", source); + final Map repParams = AbilityKey.mapFromAffected(player); + repParams.put(AbilityKey.LifeGained, n); + repParams.put(AbilityKey.Source, source); List list = player.getGame().getReplacementHandler().getReplacementList( - ReplacementType.GainLife, - repParams, - ReplacementLayer.Other); + ReplacementType.GainLife, + repParams, + ReplacementLayer.Other + ); if (Iterables.any(list, CardTraitPredicates.hasParam("AiLogic", "NoLife"))) { // no life gain is not negative diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java index 2dbce19187d..13e558ea7a9 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java @@ -1294,7 +1294,7 @@ public class ComputerUtilCard { // cast it during Declare Blockers, thus ruining its attacker if (holdCombatTricks && sa.getApi() == ApiType.Pump && sa.hasParam("NumAtt") && sa.getHostCard() != null - && sa.getHostCard().getZone() != null && sa.getHostCard().getZone().is(ZoneType.Hand) + && sa.getHostCard().isInZone(ZoneType.Hand) && c.getNetPower() > 0 // too obvious if attacking with a 0-power creature && sa.getHostCard().isInstant() // only do it for instant speed spells in hand && ComputerUtilMana.hasEnoughManaSourcesToCast(sa, ai)) { diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java index 466fa89bec6..e79a5ce641c 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCombat.java @@ -29,6 +29,7 @@ import forge.game.CardTraitBase; import forge.game.Game; import forge.game.GameEntity; import forge.game.ability.AbilityFactory; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; import forge.game.card.*; @@ -2580,13 +2581,11 @@ public class ComputerUtilCombat { final Game game = attacker.getGame(); // first try to replace the damage - final Map repParams = Maps.newHashMap(); - repParams.put("Affected", target); - repParams.put("DamageSource", attacker); - repParams.put("DamageAmount", damage); - repParams.put("IsCombat", true); - repParams.put("Prevention", true); - // repParams.put("PreventMap", preventMap); + final Map repParams = AbilityKey.mapFromAffected(target); + repParams.put(AbilityKey.DamageSource, attacker); + repParams.put(AbilityKey.DamageAmount, damage); + repParams.put(AbilityKey.IsCombat, true); + repParams.put(AbilityKey.Prevention, true); List list = game.getReplacementHandler().getReplacementList( ReplacementType.DamageDone, repParams, ReplacementLayer.Other); diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java index 9c724737a83..4102df2fefb 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilMana.java @@ -13,6 +13,7 @@ import forge.card.mana.ManaCostParser; import forge.card.mana.ManaCostShard; import forge.game.Game; import forge.game.GameActionUtil; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; import forge.game.card.*; @@ -1408,11 +1409,11 @@ public class ComputerUtilMana { AbilityManaPart mp = m.getManaPart(); // setup produce mana replacement effects - final Map repParams = new HashMap<>(); - repParams.put("Mana", mp.getOrigProduced()); - repParams.put("Affected", sourceCard); - repParams.put("Player", ai); - repParams.put("AbilityMana", m); + final Map repParams = AbilityKey.newMap(); + repParams.put(AbilityKey.Mana, mp.getOrigProduced()); + repParams.put(AbilityKey.Affected, sourceCard); + repParams.put(AbilityKey.Player, ai); + repParams.put(AbilityKey.AbilityMana, m); for (final ReplacementEffect replacementEffect : replacementEffects) { if (replacementEffect.canReplace(repParams)) { diff --git a/forge-ai/src/main/java/forge/ai/GameState.java b/forge-ai/src/main/java/forge/ai/GameState.java index 653a31a799e..3d0c81eda1c 100644 --- a/forge-ai/src/main/java/forge/ai/GameState.java +++ b/forge-ai/src/main/java/forge/ai/GameState.java @@ -11,10 +11,7 @@ import forge.game.Game; import forge.game.GameEntity; import forge.game.ability.AbilityFactory; import forge.game.ability.effects.DetachedCardEffect; -import forge.game.card.Card; -import forge.game.card.CardCollection; -import forge.game.card.CardCollectionView; -import forge.game.card.CounterType; +import forge.game.card.*; import forge.game.card.token.TokenInfo; import forge.game.combat.Combat; import forge.game.combat.CombatUtil; @@ -24,6 +21,7 @@ import forge.game.mana.ManaPool; import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.spellability.AbilityManaPart; +import forge.game.spellability.AbilitySub; import forge.game.spellability.SpellAbility; import forge.game.ability.AbilityKey; import forge.game.trigger.TriggerType; @@ -362,6 +360,12 @@ public abstract class GameState { if (c.isFaceDown()) { newText.append("|FaceDown"); // Exiled face down } + if (c.isAdventureCard() && c.getZone().is(ZoneType.Exile)) { + // TODO: this will basically default all exiled cards with Adventure to being "On Adventure". + // Need to figure out a better way to detect if it's actually on adventure. + newText.append("|OnAdventure"); + } + } if (zoneType == ZoneType.Battlefield || zoneType == ZoneType.Exile) { @@ -1202,6 +1206,16 @@ public abstract class GameState { c.setState(CardStateName.Flipped, true); } else if (info.startsWith("Meld")) { c.setState(CardStateName.Meld, true); + } else if (info.startsWith("OnAdventure")) { + String abAdventure = "DB$ Effect | RememberObjects$ Self | StaticAbilities$ Play | ExileOnMoved$ Exile | Duration$ Permanent | ConditionDefined$ Self | ConditionPresent$ Card.nonCopiedSpell"; + AbilitySub saAdventure = (AbilitySub)AbilityFactory.getAbility(abAdventure, c); + StringBuilder sbPlay = new StringBuilder(); + sbPlay.append("Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonAdventure"); + sbPlay.append(" | AffectedZone$ Exile | Description$ You may cast the card."); + saAdventure.setSVar("Play", sbPlay.toString()); + saAdventure.setActivatingPlayer(c.getOwner()); + saAdventure.resolve(); + c.setExiledWith(c); // This seems to be the way it's set up internally. Potentially not needed here? } else if (info.startsWith("IsCommander")) { // TODO: This doesn't seem to properly restore the ability to play the commander. Why? c.setCommander(true); diff --git a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java index 3f461395650..f0d1250cb58 100644 --- a/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java +++ b/forge-ai/src/main/java/forge/ai/PlayerControllerAi.java @@ -729,7 +729,7 @@ public class PlayerControllerAi extends PlayerController { return true; } else { Card rem = (Card) source.getFirstRemembered(); - if (!rem.getZone().is(ZoneType.Battlefield)) { + if (!rem.isInZone(ZoneType.Battlefield)) { return true; } } @@ -737,7 +737,7 @@ public class PlayerControllerAi extends PlayerController { case "BetterTgtThanRemembered": if (source.getRememberedCount() > 0) { Card rem = (Card) source.getFirstRemembered(); - if (!rem.getZone().is(ZoneType.Battlefield)) { + if (!rem.isInZone(ZoneType.Battlefield)) { return true; } for (Card c : source.getController().getCreaturesInPlay()) { @@ -866,8 +866,8 @@ public class PlayerControllerAi extends PlayerController { } @Override - public ReplacementEffect chooseSingleReplacementEffect(String prompt, List possibleReplacers, Map runParams) { - return brains.chooseSingleReplacementEffect(possibleReplacers, runParams); + public ReplacementEffect chooseSingleReplacementEffect(String prompt, List possibleReplacers) { + return brains.chooseSingleReplacementEffect(possibleReplacers); } @Override diff --git a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java index 0a747747895..40c59393086 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java @@ -10,6 +10,7 @@ import forge.card.MagicColor; import forge.game.Game; import forge.game.GameObject; import forge.game.GlobalRuleChange; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.ApiType; import forge.game.card.*; @@ -1789,8 +1790,8 @@ public class ChangeZoneAi extends SpellAbilityAi { } public boolean doReturnCommanderLogic(SpellAbility sa, Player aiPlayer) { - Map originalParams = (Map)sa.getReplacingObject("OriginalParams"); - SpellAbility causeSa = (SpellAbility)originalParams.get("Cause"); + Map originalParams = (Map)sa.getReplacingObject(AbilityKey.OriginalParams); + SpellAbility causeSa = (SpellAbility)originalParams.get(AbilityKey.Cause); SpellAbility causeSub = null; // Squee, the Immortal: easier to recast it (the call below has to be "contains" since SA is an intrinsic effect) @@ -1813,7 +1814,7 @@ public class ChangeZoneAi extends SpellAbilityAi { // A blink effect implemented using a delayed trigger return !"Exile".equals(exec.getParam("Origin")) || !"Battlefield".equals(exec.getParam("Destination")); } - } else return causeSa.getHostCard() == null || !causeSa.getHostCard().equals(sa.getReplacingObject("Card")) + } else return causeSa.getHostCard() == null || !causeSa.getHostCard().equals(sa.getReplacingObject(AbilityKey.Card)) || !causeSa.getActivatingPlayer().equals(aiPlayer); } diff --git a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java index 40141ae80a4..bd5371cbb75 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DamageDealAi.java @@ -76,7 +76,7 @@ public class DamageDealAi extends DamageAiBase { // Set PayX here to maximum value. dmg = ComputerUtilMana.determineLeftoverMana(sa, ai); source.setSVar("PayX", Integer.toString(dmg)); - } else if (sa.getSVar(damage).equals("Count$CardsInYourHand") && source.getZone().is(ZoneType.Hand)) { + } else if (sa.getSVar(damage).equals("Count$CardsInYourHand") && source.isInZone(ZoneType.Hand)) { dmg--; // the card will be spent casting the spell, so actual damage is 1 less } } @@ -113,7 +113,7 @@ public class DamageDealAi extends DamageAiBase { // Set PayX here to maximum value. It will be adjusted later depending on the target. source.setSVar("PayX", Integer.toString(dmg)); - } else if (sa.getSVar(damage).contains("InYourHand") && source.getZone().is(ZoneType.Hand)) { + } else if (sa.getSVar(damage).contains("InYourHand") && source.isInZone(ZoneType.Hand)) { dmg = CardFactoryUtil.xCount(source, sa.getSVar(damage)) - 1; // the card will be spent casting the spell, so actual damage is 1 less } else if (sa.getSVar(damage).equals("TargetedPlayer$CardsInHand")) { // cards that deal damage by the number of cards in target player's hand, e.g. Sudden Impact diff --git a/forge-ai/src/main/java/forge/ai/ability/DrawAi.java b/forge-ai/src/main/java/forge/ai/ability/DrawAi.java index 212f0bbdab6..355361bfda7 100644 --- a/forge-ai/src/main/java/forge/ai/ability/DrawAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/DrawAi.java @@ -409,7 +409,7 @@ public class DrawAi extends SpellAbilityAi { if (computerHandSize + numCards > computerMaxHandSize && game.getPhaseHandler().isPlayerTurn(ai)) { if (xPaid) { numCards = computerMaxHandSize - computerHandSize; - if (sa.getHostCard().getZone().is(ZoneType.Hand)) { + if (sa.getHostCard().isInZone(ZoneType.Hand)) { numCards++; // the card will be spent } source.setSVar("PayX", Integer.toString(numCards)); diff --git a/forge-ai/src/main/java/forge/ai/ability/FightAi.java b/forge-ai/src/main/java/forge/ai/ability/FightAi.java index 9a3b0965c42..1b95b09c1ca 100644 --- a/forge-ai/src/main/java/forge/ai/ability/FightAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/FightAi.java @@ -45,6 +45,8 @@ public class FightAi extends SpellAbilityAi { aiCreatures = ComputerUtil.getSafeTargets(ai, sa, aiCreatures); List humCreatures = ai.getOpponents().getCreaturesInPlay(); humCreatures = CardLists.getTargetableCards(humCreatures, sa); + if (humCreatures.isEmpty()) + return false; //prevent IndexOutOfBoundsException on MOJHOSTO variant // assumes the triggered card belongs to the ai if (sa.hasParam("Defined")) { diff --git a/forge-ai/src/main/java/forge/ai/ability/ManifestAi.java b/forge-ai/src/main/java/forge/ai/ability/ManifestAi.java index f98cd0bd02e..b3d205c4958 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ManifestAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ManifestAi.java @@ -2,12 +2,12 @@ package forge.ai.ability; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; -import com.google.common.collect.Maps; import forge.ai.ComputerUtil; import forge.ai.ComputerUtilCard; import forge.ai.ComputerUtilMana; import forge.ai.SpellAbilityAi; import forge.game.Game; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.card.CardCollection; import forge.game.card.CardCollectionView; @@ -97,11 +97,10 @@ public class ManifestAi extends SpellAbilityAi { topCopy.turnFaceDownNoUpdate(); topCopy.setManifested(true); - final Map repParams = Maps.newHashMap(); - repParams.put("Affected", topCopy); - repParams.put("Origin", card.getZone().getZoneType()); - repParams.put("Destination", ZoneType.Battlefield); - repParams.put("Source", sa.getHostCard()); + final Map repParams = AbilityKey.mapFromAffected(topCopy); + repParams.put(AbilityKey.Origin, card.getZone().getZoneType()); + repParams.put(AbilityKey.Destination, ZoneType.Battlefield); + repParams.put(AbilityKey.Source, sa.getHostCard()); List list = game.getReplacementHandler().getReplacementList(ReplacementType.Moved, repParams, ReplacementLayer.Other); if (!list.isEmpty()) { return false; diff --git a/forge-ai/src/main/java/forge/ai/ability/PumpAi.java b/forge-ai/src/main/java/forge/ai/ability/PumpAi.java index 31c4c7a8ddd..ce161caee80 100644 --- a/forge-ai/src/main/java/forge/ai/ability/PumpAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/PumpAi.java @@ -309,7 +309,7 @@ public class PumpAi extends PumpAiBase { } } else { defense = AbilityUtils.calculateAmount(sa.getHostCard(), numDefense, sa); - if (numDefense.contains("X") && sa.getSVar("X").equals("Count$CardsInYourHand") && source.getZone().is(ZoneType.Hand)) { + if (numDefense.contains("X") && sa.getSVar("X").equals("Count$CardsInYourHand") && source.isInZone(ZoneType.Hand)) { defense--; // the card will be spent casting the spell, so actual toughness is 1 less } } @@ -328,7 +328,7 @@ public class PumpAi extends PumpAiBase { } } else { attack = AbilityUtils.calculateAmount(sa.getHostCard(), numAttack, sa); - if (numAttack.contains("X") && sa.getSVar("X").equals("Count$CardsInYourHand") && source.getZone().is(ZoneType.Hand)) { + if (numAttack.contains("X") && sa.getSVar("X").equals("Count$CardsInYourHand") && source.isInZone(ZoneType.Hand)) { attack--; // the card will be spent casting the spell, so actual power is 1 less } } diff --git a/forge-ai/src/main/java/forge/ai/ability/SacrificeAi.java b/forge-ai/src/main/java/forge/ai/ability/SacrificeAi.java index 94e36b479da..78081283c46 100644 --- a/forge-ai/src/main/java/forge/ai/ability/SacrificeAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/SacrificeAi.java @@ -63,6 +63,7 @@ public class SacrificeAi extends SpellAbilityAi { final boolean destroy = sa.hasParam("Destroy"); Player opp = ai.getWeakestOpponent(); + if (tgt != null) { sa.resetTargets(); if (!opp.canBeTargetedBy(sa)) { @@ -74,8 +75,16 @@ public class SacrificeAi extends SpellAbilityAi { num = (num == null) ? "1" : num; final int amount = AbilityUtils.calculateAmount(sa.getHostCard(), num, sa); - List list = - CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa); + List list = null; + try { + list = CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa); + } catch (NullPointerException e) { + return false; + } finally { + if (list == null) + return false; + }//prevent NPE on MoJhoSto + for (Card c : list) { if (c.hasSVar("SacMe") && Integer.parseInt(c.getSVar("SacMe")) > 3) { return false; @@ -131,15 +140,31 @@ public class SacrificeAi extends SpellAbilityAi { amount = Math.min(ComputerUtilMana.determineLeftoverMana(sa, ai), amount); } - List humanList = - CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa); + List humanList = null; + try { + humanList = CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa); + } catch (NullPointerException e) { + return false; + } finally { + if (humanList == null) + return false; + }//prevent NPE on MoJhoSto // Since all of the cards have AI:RemoveDeck:All, I enabled 1 for 1 // (or X for X) trades for special decks return humanList.size() >= amount; } else if (defined.equals("You")) { - List computerList = - CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa); + + List computerList = null; + try { + computerList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid.split(","), sa.getActivatingPlayer(), sa.getHostCard(), sa); + } catch (NullPointerException e) { + return false; + } finally { + if (computerList == null) + return false; + }//prevent NPE on MoJhoSto + for (Card c : computerList) { if (c.hasSVar("SacMe") || ComputerUtilCard.evaluateCreature(c) <= 135) { return true; diff --git a/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java b/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java index 79104d062a6..7e03c1cf0f5 100644 --- a/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/SetStateAi.java @@ -148,7 +148,7 @@ public class SetStateAi extends SpellAbilityAi { if (card.isFaceDown()) { // hidden agenda if (card.getState(CardStateName.Original).hasIntrinsicKeyword("Hidden agenda") - && card.getZone().is(ZoneType.Command)) { + && card.isInZone(ZoneType.Command)) { String chosenName = card.getNamedCard(); for (Card cast : ai.getGame().getStack().getSpellsCastThisTurn()) { if (cast.getController() == ai && cast.getName().equals(chosenName)) { diff --git a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java index d2ae1de2379..cd99a5a6d94 100644 --- a/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java +++ b/forge-ai/src/main/java/forge/ai/simulation/GameCopier.java @@ -228,7 +228,7 @@ public class GameCopier { CardFactory.copyCopiableCharacteristics(c, result); return result; } - if (USE_FROM_PAPER_CARD && !c.isEmblem()) { + if (USE_FROM_PAPER_CARD && !c.isEmblem() && c.getPaperCard() != null) { Card newCard = Card.fromPaperCard(c.getPaperCard(), newOwner); newCard.setCommander(c.isCommander()); return newCard; diff --git a/forge-core/pom.xml b/forge-core/pom.xml index 5daa8ffcee7..a7f407b138f 100644 --- a/forge-core/pom.xml +++ b/forge-core/pom.xml @@ -6,7 +6,7 @@ forge forge - 1.6.30-SNAPSHOT + 1.6.31-SNAPSHOT forge-core @@ -21,7 +21,7 @@ org.apache.commons commons-lang3 - 3.7 + 3.8.1 diff --git a/forge-core/src/main/java/forge/ImageKeys.java b/forge-core/src/main/java/forge/ImageKeys.java index 3e5192ba642..e07f836566d 100644 --- a/forge-core/src/main/java/forge/ImageKeys.java +++ b/forge-core/src/main/java/forge/ImageKeys.java @@ -111,7 +111,18 @@ public final class ImageKeys { file = findFile(dir, TextUtil.fastReplace(filename, "AE", "Ae")); if (file != null) { return file; } } - + //try fullborder... + if (filename.contains(".full")) { + file = findFile(dir, TextUtil.fastReplace(filename, ".full", ".fullborder")); + 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 (!filename.contains(".full")) { + file = findFile(dir, TextUtil.addSuffix(filename,".full")); + if (file != null) { return file; } + file = findFile(dir, TextUtil.addSuffix(filename,".fullborder")); + if (file != null) { return file; } + } // some S00 cards are really part of 6ED String s2kAlias = getSetFolder("S00"); if (filename.startsWith(s2kAlias)) { diff --git a/forge-core/src/main/java/forge/LobbyPlayer.java b/forge-core/src/main/java/forge/LobbyPlayer.java index 79139ec3a75..3f60952a336 100644 --- a/forge-core/src/main/java/forge/LobbyPlayer.java +++ b/forge-core/src/main/java/forge/LobbyPlayer.java @@ -11,6 +11,7 @@ import org.apache.commons.lang3.StringUtils; public abstract class LobbyPlayer { protected String name; private int avatarIndex = -1; + private int sleeveIndex = -1; private String avatarCardImageKey; public LobbyPlayer(String name) { @@ -59,9 +60,15 @@ public abstract class LobbyPlayer { public int getAvatarIndex() { return avatarIndex; } + public int getSleeveIndex() { + return sleeveIndex; + } public void setAvatarIndex(int avatarIndex) { this.avatarIndex = avatarIndex; } + public void setSleeveIndex(int sleeveIndex) { + this.sleeveIndex = sleeveIndex; + } public String getAvatarCardImageKey() { return avatarCardImageKey; diff --git a/forge-core/src/main/java/forge/StaticData.java b/forge-core/src/main/java/forge/StaticData.java index d9d02dcc78b..6b65424daab 100644 --- a/forge-core/src/main/java/forge/StaticData.java +++ b/forge-core/src/main/java/forge/StaticData.java @@ -35,6 +35,7 @@ public class StaticData { private Predicate standardPredicate; private Predicate brawlPredicate; + private Predicate pioneerPredicate; private Predicate modernPredicate; private Predicate commanderPredicate; private Predicate oathbreakerPredicate; @@ -197,13 +198,13 @@ public class StaticData { public TokenDb getAllTokens() { return allTokens; } - public Predicate getStandardPredicate() { - return standardPredicate; - } + public void setStandardPredicate(Predicate standardPredicate) { this.standardPredicate = standardPredicate; } - public void setModernPredicate(Predicate modernPredicate) { this.modernPredicate = standardPredicate; } + public void setPioneerPredicate(Predicate pioneerPredicate) { this.pioneerPredicate = pioneerPredicate; } + + public void setModernPredicate(Predicate modernPredicate) { this.modernPredicate = modernPredicate; } public void setCommanderPredicate(Predicate commanderPredicate) { this.commanderPredicate = commanderPredicate; } @@ -211,9 +212,11 @@ public class StaticData { public void setBrawlPredicate(Predicate brawlPredicate) { this.brawlPredicate = brawlPredicate; } - public Predicate getModernPredicate() { - return modernPredicate; - } + public Predicate getStandardPredicate() { return standardPredicate; } + + public Predicate getPioneerPredicate() { return pioneerPredicate; } + + public Predicate getModernPredicate() { return modernPredicate; } public Predicate getCommanderPredicate() { return commanderPredicate; } diff --git a/forge-core/src/main/java/forge/deck/DeckFormat.java b/forge-core/src/main/java/forge/deck/DeckFormat.java index 99bc2613fad..f9cd57dc0ef 100644 --- a/forge-core/src/main/java/forge/deck/DeckFormat.java +++ b/forge-core/src/main/java/forge/deck/DeckFormat.java @@ -21,7 +21,6 @@ import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; - import forge.StaticData; import forge.card.CardRules; import forge.card.CardRulesPredicates; @@ -37,8 +36,11 @@ import forge.util.TextUtil; import org.apache.commons.lang3.Range; import org.apache.commons.lang3.tuple.ImmutablePair; -import java.util.*; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; import java.util.Map.Entry; +import java.util.Set; /** * GameType is an enum to determine the type of current game. :) @@ -324,23 +326,32 @@ public enum DeckFormat { } final int maxCopies = getMaxCardCopies(); - if (maxCopies < Integer.MAX_VALUE) { - //Must contain no more than 4 of the same card - //shared among the main deck and sideboard, except - //basic lands, Shadowborn Apostle, Relentless Rats and Rat Colony + //Must contain no more than 4 of the same card + //shared among the main deck and sideboard, except + //basic lands, Shadowborn Apostle, Relentless Rats and Rat Colony + // Seven Dwarves can have 7 in the deck. More than 7 in deck + sb is ok in Limited - final CardPool allCards = deck.getAllCardsInASinglePool(hasCommander()); + final CardPool allCards = deck.getAllCardsInASinglePool(hasCommander()); - // should group all cards by name, so that different editions of same card are really counted as the same card - for (final Entry cp : Aggregates.groupSumBy(allCards, PaperCard.FN_GET_NAME)) { - final IPaperCard simpleCard = StaticData.instance().getCommonCards().getCard(cp.getKey()); - if (simpleCard == null) { - return TextUtil.concatWithSpace("contains the nonexisting card", cp.getKey()); - } + // should group all cards by name, so that different editions of same card are really counted as the same card + for (final Entry cp : Aggregates.groupSumBy(allCards, PaperCard.FN_GET_NAME)) { + final IPaperCard simpleCard = StaticData.instance().getCommonCards().getCard(cp.getKey()); + // Might cause issues since it ignores "Special" Cards + if (simpleCard == null) { + return TextUtil.concatWithSpace("contains the nonexisting card", cp.getKey()); + } - if (!canHaveAnyNumberOf(simpleCard) && cp.getValue() > maxCopies) { - return TextUtil.concatWithSpace("must not contain more than", String.valueOf(maxCopies), "copies of the card", cp.getKey()); - } + if (canHaveAnyNumberOf(simpleCard)) { + continue; + } + + Integer cardCopies = canHaveSpecificNumberInDeck(simpleCard); + if (cardCopies != null && deck.getMain().countByName(cp.getKey(), true) > cardCopies) { + return TextUtil.concatWithSpace("must not contain more than", String.valueOf(cardCopies), "copies of the card", cp.getKey()); + } + + if (cardCopies == null && cp.getValue() > maxCopies) { + return TextUtil.concatWithSpace("must not contain more than", String.valueOf(maxCopies), "copies of the card", cp.getKey()); } } @@ -362,6 +373,16 @@ public enum DeckFormat { "A deck can have any number of cards named CARDNAME."); } + public static Integer canHaveSpecificNumberInDeck(final IPaperCard card) { + // Ideally, this would be parsed during card parsing and set this value + if (Iterables.contains(card.getRules().getMainPart().getKeywords(), + "A deck can have up to seven cards named CARDNAME.")) { + return 7; + } + + return null; + } + public static String getPlaneSectionConformanceProblem(final CardPool planes) { //Must contain at least 10 planes/phenomenons, but max 2 phenomenons. Singleton. if (planes == null || planes.countAll() < 10) { diff --git a/forge-gui/src/main/java/forge/card/CardTranslation.java b/forge-core/src/main/java/forge/util/CardTranslation.java similarity index 81% rename from forge-gui/src/main/java/forge/card/CardTranslation.java rename to forge-core/src/main/java/forge/util/CardTranslation.java index babdb70d35d..7e6d7b3dfdb 100644 --- a/forge-gui/src/main/java/forge/card/CardTranslation.java +++ b/forge-core/src/main/java/forge/util/CardTranslation.java @@ -1,9 +1,6 @@ -package forge.card; +package forge.util; -import com.esotericsoftware.minlog.Log; import com.google.common.base.Charsets; -import forge.properties.ForgeConstants; -import forge.util.LineReader; import java.io.FileInputStream; import java.io.IOException; @@ -15,12 +12,12 @@ public class CardTranslation { private static Map translatednames; private static Map translatedtypes; private static Map translatedoracles; - private static String languageSelected; + private static String languageSelected = "en-US"; - private static void readTranslationFile(String language) { + private static void readTranslationFile(String language, String languagesDirectory) { String filename = "cardnames-" + language + ".txt"; - try (LineReader translationFile = new LineReader(new FileInputStream(ForgeConstants.LANG_DIR + filename), Charsets.UTF_8)) { + try (LineReader translationFile = new LineReader(new FileInputStream(languagesDirectory + filename), Charsets.UTF_8)) { for (String line : translationFile.readLines()) { String[] matches = line.split("\\|"); if (matches.length >= 2) { @@ -34,7 +31,7 @@ public class CardTranslation { } } } catch (IOException e) { - Log.error("Error reading translation file: cardnames-" + language + ".txt"); + System.err.println("Error reading translation file: cardnames-" + language + ".txt"); } } @@ -66,7 +63,7 @@ public class CardTranslation { } public static HashMap getTranslationTexts(String cardname, String altcardname) { - HashMap translations = new HashMap(); + HashMap translations = new HashMap<>(); translations.put("name", getTranslatedName(cardname)); translations.put("oracle", getTranslatedOracle(cardname)); translations.put("altname", getTranslatedName(altcardname)); @@ -78,14 +75,14 @@ public class CardTranslation { return !languageSelected.equals("en-US"); } - public static void preloadTranslation(String language) { + public static void preloadTranslation(String language, String languagesDirectory) { languageSelected = language; if (needsTranslation()) { translatednames = new HashMap<>(); translatedtypes = new HashMap<>(); translatedoracles = new HashMap<>(); - readTranslationFile(languageSelected); + readTranslationFile(languageSelected, languagesDirectory); } } } \ No newline at end of file diff --git a/forge-core/src/main/java/forge/util/ComparatorUtil.java b/forge-core/src/main/java/forge/util/ComparatorUtil.java new file mode 100644 index 00000000000..7f575825439 --- /dev/null +++ b/forge-core/src/main/java/forge/util/ComparatorUtil.java @@ -0,0 +1,78 @@ +package forge.util; + +import java.util.*; + +/** + * @author Gili Tzabari + */ +public final class ComparatorUtil +{ + /** + * Verify that a comparator is transitive. + * + * @param the type being compared + * @param comparator the comparator to test + * @param elements the elements to test against + * @throws AssertionError if the comparator is not transitive + */ + public static String verifyTransitivity(Comparator comparator, Collection elements) + { + String exception = ""; + for (T first: elements) + { + for (T second: elements) + { + int result1 = comparator.compare(first, second); + int result2 = comparator.compare(second, first); + if (result1 != -result2) + { + // Uncomment the following line to step through the failed case + //comparator.compare(first, second); + /*throw new AssertionError("compare(" + first + ", " + second + ") == " + result1 + + " but swapping the parameters returns " + result2);*/ + exception = "compare(" + first + ", " + second + ") == " + result1 + + " but swapping the parameters returns " + result2; + System.err.println(exception); + return exception; + } + } + } + for (T first: elements) + { + for (T second: elements) + { + int firstGreaterThanSecond = comparator.compare(first, second); + if (firstGreaterThanSecond <= 0) + continue; + for (T third: elements) + { + int secondGreaterThanThird = comparator.compare(second, third); + if (secondGreaterThanThird <= 0) + continue; + int firstGreaterThanThird = comparator.compare(first, third); + if (firstGreaterThanThird <= 0) + { + // Uncomment the following line to step through the failed case + //comparator.compare(first, third); + /*throw new AssertionError("compare(" + first + ", " + second + ") > 0, " + + "compare(" + second + ", " + third + ") > 0, but compare(" + first + ", " + third + ") == " + + firstGreaterThanThird);*/ + exception = "compare(" + first + ", " + second + ") > 0, " + + "compare(" + second + ", " + third + ") > 0, but compare(" + first + ", " + third + ") == " + + firstGreaterThanThird; + System.err.println(exception); + return exception; + } + } + } + } + return exception; + } + + /** + * Prevent construction. + */ + private ComparatorUtil() + { + } +} \ No newline at end of file diff --git a/forge-gui/src/main/java/forge/util/LineReader.java b/forge-core/src/main/java/forge/util/LineReader.java similarity index 100% rename from forge-gui/src/main/java/forge/util/LineReader.java rename to forge-core/src/main/java/forge/util/LineReader.java diff --git a/forge-game/pom.xml b/forge-game/pom.xml index 0d19263f85c..77521379fa7 100644 --- a/forge-game/pom.xml +++ b/forge-game/pom.xml @@ -6,7 +6,7 @@ forge forge - 1.6.30-SNAPSHOT + 1.6.31-SNAPSHOT forge-game @@ -32,8 +32,8 @@ io.sentry - sentry-log4j - 1.7.5 + sentry-log4j2 + 1.7.27 diff --git a/forge-game/src/main/java/forge/game/GameAction.java b/forge-game/src/main/java/forge/game/GameAction.java index e7fb4887257..683a6b297a9 100644 --- a/forge-game/src/main/java/forge/game/GameAction.java +++ b/forge-game/src/main/java/forge/game/GameAction.java @@ -55,8 +55,6 @@ import org.apache.commons.lang3.tuple.ImmutablePair; import java.util.*; -import static forge.util.EnumMapUtil.toStringMap; - /** * Methods for common actions performed during a game. * @@ -147,11 +145,6 @@ public class GameAction { } } - // if an adventureCard is put from Stack somewhere else, need to reset to Original State - if (c.isAdventureCard() && ((zoneFrom != null && zoneFrom.is(ZoneType.Stack)) || !zoneTo.is(ZoneType.Stack))) { - c.setState(CardStateName.Original, true); - } - // Clean up the temporary Dash SVar when the Dashed card leaves the battlefield // Clean up the temporary AtEOT SVar String endofTurn = c.getSVar("EndOfTurnLeavePlay"); @@ -258,7 +251,7 @@ public class GameAction { } if(noLandLKI.isLand()) { // if it isn't on the Stack, it stays in that Zone - if (!c.getZone().is(ZoneType.Stack)) { + if (!c.isInZone(ZoneType.Stack)) { return c; } // if something would only be a land when entering the battlefield and not before @@ -292,8 +285,7 @@ public class GameAction { copied.getOwner().addInboundToken(copied); } - Map repParams = AbilityKey.newMap(); - repParams.put(AbilityKey.Affected, copied); + Map repParams = AbilityKey.mapFromAffected(copied); repParams.put(AbilityKey.CardLKI, lastKnownInfo); repParams.put(AbilityKey.Cause, cause); repParams.put(AbilityKey.Origin, zoneFrom != null ? zoneFrom.getZoneType() : null); @@ -303,7 +295,7 @@ public class GameAction { repParams.putAll(params); } - ReplacementResult repres = game.getReplacementHandler().run(ReplacementType.Moved, toStringMap(repParams)); + ReplacementResult repres = game.getReplacementHandler().run(ReplacementType.Moved, repParams); if (repres != ReplacementResult.NotReplaced) { // reset failed manifested Cards back to original if (c.isManifested()) { @@ -355,6 +347,11 @@ public class GameAction { } } + // if an adventureCard is put from Stack somewhere else, need to reset to Original State + if (copied.isAdventureCard() && ((zoneFrom != null && zoneFrom.is(ZoneType.Stack)) || !zoneTo.is(ZoneType.Stack))) { + copied.setState(CardStateName.Original, false); + } + GameEntityCounterTable table = new GameEntityCounterTable(); // need to suspend cards own replacement effects @@ -704,7 +701,9 @@ public class GameAction { // Run triggers final Map runParams = AbilityKey.mapFromCard(c); runParams.put(AbilityKey.Cause, cause); - runParams.put(AbilityKey.Origin, origin.getZoneType().name()); + if (origin != null) { // is generally null when adding via dev mode + runParams.put(AbilityKey.Origin, origin.getZoneType().name()); + } if (params != null) { runParams.putAll(params); } @@ -1389,11 +1388,10 @@ public class GameAction { } // Replacement effects - final Map repRunParams = Maps.newHashMap(); - repRunParams.put("Source", sa); - repRunParams.put("Card", c); - repRunParams.put("Affected", c); - repRunParams.put("Regeneration", regenerate); + final Map repRunParams = AbilityKey.mapFromCard(c); + repRunParams.put(AbilityKey.Source, sa); + repRunParams.put(AbilityKey.Affected, c); + repRunParams.put(AbilityKey.Regeneration, regenerate); if (game.getReplacementHandler().run(ReplacementType.Destroy, repRunParams) != ReplacementResult.NotReplaced) { return false; diff --git a/forge-game/src/main/java/forge/game/GameActionUtil.java b/forge-game/src/main/java/forge/game/GameActionUtil.java index b0575c15420..e1f237ecf0d 100644 --- a/forge-game/src/main/java/forge/game/GameActionUtil.java +++ b/forge-game/src/main/java/forge/game/GameActionUtil.java @@ -300,12 +300,12 @@ public final class GameActionUtil { costs.add(new OptionalCostValue(type, cost)); } } else if (keyword.equals("Retrace")) { - if (source.getZone().is(ZoneType.Graveyard)) { + if (source.isInZone(ZoneType.Graveyard)) { final Cost cost = new Cost("Discard<1/Land>", false); costs.add(new OptionalCostValue(OptionalCost.Retrace, cost)); } } else if (keyword.equals("Jump-start")) { - if (source.getZone().is(ZoneType.Graveyard)) { + if (source.isInZone(ZoneType.Graveyard)) { final Cost cost = new Cost("Discard<1/Card>", false); costs.add(new OptionalCostValue(OptionalCost.Jumpstart, cost)); } diff --git a/forge-game/src/main/java/forge/game/GameEntity.java b/forge-game/src/main/java/forge/game/GameEntity.java index c5a51de5b22..177815f6141 100644 --- a/forge-game/src/main/java/forge/game/GameEntity.java +++ b/forge-game/src/main/java/forge/game/GameEntity.java @@ -115,25 +115,24 @@ public abstract class GameEntity extends GameObject implements IIdentifiable { public int replaceDamage(final int damage, final Card source, final boolean isCombat, final boolean prevention, final CardDamageMap damageMap, final CardDamageMap preventMap, GameEntityCounterTable counterTable, final SpellAbility cause) { // Replacement effects - final Map repParams = Maps.newHashMap(); - repParams.put("Affected", this); - repParams.put("DamageSource", source); - repParams.put("DamageAmount", damage); - repParams.put("IsCombat", isCombat); - repParams.put("NoPreventDamage", !prevention); - repParams.put("DamageMap", damageMap); - repParams.put("PreventMap", preventMap); - repParams.put("CounterTable", counterTable); + final Map repParams = AbilityKey.mapFromAffected(this); + repParams.put(AbilityKey.DamageSource, source); + repParams.put(AbilityKey.DamageAmount, damage); + repParams.put(AbilityKey.IsCombat, isCombat); + repParams.put(AbilityKey.NoPreventDamage, !prevention); + repParams.put(AbilityKey.DamageMap, damageMap); + repParams.put(AbilityKey.PreventMap, preventMap); + repParams.put(AbilityKey.CounterTable, counterTable); if (cause != null) { - repParams.put("Cause", cause); + repParams.put(AbilityKey.Cause, cause); } switch (getGame().getReplacementHandler().run(ReplacementType.DamageDone, repParams)) { case NotReplaced: return damage; case Updated: - int newDamage = (int) repParams.get("DamageAmount"); - GameEntity newTarget = (GameEntity) repParams.get("Affected"); + int newDamage = (int) repParams.get(AbilityKey.DamageAmount); + GameEntity newTarget = (GameEntity) repParams.get(AbilityKey.Affected); // check if this is still the affected card or player if (this.equals(newTarget)) { return newDamage; @@ -169,15 +168,14 @@ public abstract class GameEntity extends GameObject implements IIdentifiable { int restDamage = damage; // first try to replace the damage - final Map repParams = Maps.newHashMap(); - repParams.put("Affected", this); - repParams.put("DamageSource", source); - repParams.put("DamageAmount", damage); - repParams.put("IsCombat", isCombat); - repParams.put("Prevention", true); - repParams.put("PreventMap", preventMap); + final Map repParams = AbilityKey.mapFromAffected(this); + repParams.put(AbilityKey.DamageSource, source); + repParams.put(AbilityKey.DamageAmount, damage); + repParams.put(AbilityKey.IsCombat, isCombat); + repParams.put(AbilityKey.Prevention, true); + repParams.put(AbilityKey.PreventMap, preventMap); if (cause != null) { - repParams.put("Cause", cause); + repParams.put(AbilityKey.Cause, cause); } switch (getGame().getReplacementHandler().run(ReplacementType.DamageDone, repParams)) { @@ -185,7 +183,7 @@ public abstract class GameEntity extends GameObject implements IIdentifiable { restDamage = damage; break; case Updated: - restDamage = (int) repParams.get("DamageAmount"); + restDamage = (int) repParams.get(AbilityKey.DamageAmount); break; default: restDamage = 0; diff --git a/forge-game/src/main/java/forge/game/GameFormat.java b/forge-game/src/main/java/forge/game/GameFormat.java index 8f714aac24a..9eb259404ea 100644 --- a/forge-game/src/main/java/forge/game/GameFormat.java +++ b/forge-game/src/main/java/forge/game/GameFormat.java @@ -47,7 +47,7 @@ import java.util.Map.Entry; public class GameFormat implements Comparable { private final String name; public enum FormatType {Sanctioned, Casual, Historic, Digital, Custom} - public enum FormatSubType {Block, Standard, Extended, Modern, Legacy, Vintage, Commander, Planechase, Videogame, MTGO, Custom} + public enum FormatSubType {Block, Standard, Extended, Pioneer, Modern, Legacy, Vintage, Commander, Planechase, Videogame, MTGO, Custom} // contains allowed sets, when empty allows all sets private FormatType formatType; @@ -290,6 +290,7 @@ public class GameFormat implements Comparable { private List coreFormats = new ArrayList<>(); { coreFormats.add("Standard.txt"); + coreFormats.add("Pioneer.txt"); coreFormats.add("Modern.txt"); coreFormats.add("Legacy.txt"); coreFormats.add("Vintage.txt"); @@ -468,6 +469,10 @@ public class GameFormat implements Comparable { return this.map.get("Extended"); } + public GameFormat getPioneer() { + return this.map.get("Pioneer"); + } + public GameFormat getModern() { return this.map.get("Modern"); } diff --git a/forge-game/src/main/java/forge/game/GameLogFormatter.java b/forge-game/src/main/java/forge/game/GameLogFormatter.java index 0e100e9db4f..f244600cc88 100644 --- a/forge-game/src/main/java/forge/game/GameLogFormatter.java +++ b/forge-game/src/main/java/forge/game/GameLogFormatter.java @@ -33,11 +33,11 @@ import forge.game.player.RegisteredPlayer; import forge.game.spellability.TargetChoices; import forge.game.zone.ZoneType; import forge.util.Lang; +import forge.util.Localizer; import forge.util.maps.MapOfLists; public class GameLogFormatter extends IGameEventVisitor.Base { private final GameLog log; - public GameLogFormatter(GameLog gameLog) { log = gameLog; } @@ -52,16 +52,15 @@ public class GameLogFormatter extends IGameEventVisitor.Base { @Override public GameLogEntry visit(GameEventScry ev) { + final Localizer localizer = Localizer.getInstance(); String scryOutcome = ""; - String toTop = Lang.nounWithAmount(ev.toTop, "card") + " to the top of the library"; - String toBottom = Lang.nounWithAmount(ev.toBottom, "card") + " to the bottom of the library"; if (ev.toTop > 0 && ev.toBottom > 0) { - scryOutcome = ev.player.toString() + " scried " + toTop + " and " + toBottom; + scryOutcome = localizer.getMessage("lblLogScryTopBottomLibrary").replace("%s", ev.player.toString()).replace("%top", String.valueOf(ev.toTop)).replace("%bottom", String.valueOf(ev.toBottom)); } else if (ev.toBottom == 0) { - scryOutcome = ev.player.toString() + " scried " + toTop; + scryOutcome = localizer.getMessage("lblLogScryTopLibrary").replace("%s", ev.player.toString()).replace("%top", String.valueOf(ev.toTop)); } else { - scryOutcome = ev.player.toString() + " scried " + toBottom; + scryOutcome = localizer.getMessage("lblLogScryBottomLibrary").replace("%s", ev.player.toString()).replace("%bottom", String.valueOf(ev.toBottom)); } return new GameLogEntry(GameLogEntryType.STACK_RESOLVE, scryOutcome); @@ -218,6 +217,7 @@ public class GameLogFormatter extends IGameEventVisitor.Base { @Override public GameLogEntry visit(final GameEventAttackersDeclared ev) { final StringBuilder sb = new StringBuilder(); + final Localizer localizer = Localizer.getInstance(); // Loop through Defenders // Append Defending Player/Planeswalker @@ -233,7 +233,7 @@ public class GameLogFormatter extends IGameEventVisitor.Base { sb.append(" to attack ").append(k).append("."); } if (sb.length() == 0) { - sb.append(ev.player).append(" didn't attack this turn."); + sb.append(localizer.getMessage("lblPlayerDidntAttackThisTurn").replace("%s", ev.player.toString())); } return new GameLogEntry(GameLogEntryType.COMBAT, sb.toString()); } @@ -281,7 +281,7 @@ public class GameLogFormatter extends IGameEventVisitor.Base { @Override public GameLogEntry visit(GameEventMulligan ev) { - String message = ev.player.toString() + " has mulliganed down to " + ev.player.getZone(ZoneType.Hand).size() + " cards."; + String message = Localizer.getInstance().getMessage("lblPlayerHasMulliganedDownToNCards").replace("%d", String.valueOf(ev.player.getZone(ZoneType.Hand).size())).replace("%s", ev.player.toString()); return new GameLogEntry(GameLogEntryType.MULLIGAN, message); } diff --git a/forge-game/src/main/java/forge/game/ability/AbilityKey.java b/forge-game/src/main/java/forge/game/ability/AbilityKey.java index a33cd8e8f3e..4821b088c8a 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityKey.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityKey.java @@ -3,6 +3,7 @@ package forge.game.ability; import java.util.EnumMap; import java.util.Map; +import forge.game.GameEntity; import forge.game.card.Card; /** @@ -37,12 +38,15 @@ public enum AbilityKey { CostStack("CostStack"), CounterAmount("CounterAmount"), CounteredSA("CounteredSA"), + CounterNum("CounterNum"), + CounterTable("CounterTable"), CounterType("CounterType"), Crew("Crew"), CumulativeUpkeepPaid("CumulativeUpkeepPaid"), CurrentCastSpells("CurrentCastSpells"), CurrentStormCount("CurrentStormCount"), DamageAmount("DamageAmount"), + DamageMap("DamageMap"), DamageSource("DamageSource"), DamageSources("DamageSources"), DamageTarget("DamageTarget"), @@ -53,18 +57,23 @@ public enum AbilityKey { Destination("Destination"), Devoured("Devoured"), EchoPaid("EchoPaid"), + EffectOnly("EffectOnly"), Exploited("Exploited"), Explorer("Explorer"), Event("Event"), Fighter("Fighter"), FirstTime("FirstTime"), Fizzle("Fizzle"), + IsCombat("IsCombat"), // TODO confirm that this and IsCombatDamage can be merged IsCombatDamage("IsCombatDamage"), IndividualCostPaymentInstance("IndividualCostPaymentInstance"), IsMadness("IsMadness"), - LifeAmount("LifeAmount"), + LifeAmount("LifeAmount"), //TODO confirm that this and LifeGained can be merged + LifeGained("LifeGained"), + Mana("Mana"), MonstrosityAmount("MonstrosityAmount"), NewCounterAmount("NewCounterAmount"), + NoPreventDamage("NoPreventDamage"), Num("Num"), // TODO confirm that this and NumThisTurn can be merged NumBlockers("NumBlockers"), NumThisTurn("NumThisTurn"), @@ -76,10 +85,15 @@ public enum AbilityKey { Origin("Origin"), OriginalController("OriginalController"), OriginalDefender("OriginalDefender"), + OriginalParams("OriginalParams"), PayingMana("PayingMana"), Phase("Phase"), Player("Player"), + PreventMap("PreventMap"), + Prevention("Prevention"), Produced("Produced"), + Regeneration("Regeneration"), + ReplacementResult("ReplacementResult"), Result("Result"), Scheme("Scheme"), Source("Source"), @@ -91,8 +105,12 @@ public enum AbilityKey { StackInstance("StackInstance"), StackSa("StackSa"), StackSi("StackSi"), + SurveilNum("SurveilNum"), Target("Target"), Targets("Targets"), + TgtSA("TgtSA"), + Token("Token"), + TokenNum("TokenNum"), Transformer("Transformer"), Vehicle("Vehicle"), Won("Won"); @@ -141,4 +159,11 @@ public enum AbilityKey { runParams.put(Card, card); return runParams; } + + public static Map mapFromAffected(GameEntity gameEntity) { + final Map runParams = newMap(); + + runParams.put(Affected, gameEntity); + return runParams; + } } diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index f17336ca80a..97877f115ad 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -48,7 +48,7 @@ public class AbilityUtils { public static CounterType getCounterType(String name, SpellAbility sa) throws Exception { CounterType counterType; if ("ReplacedCounterType".equals(name)) { - name = (String) sa.getReplacingObject("CounterType"); + name = (String) sa.getReplacingObject(AbilityKey.CounterType); } try { counterType = CounterType.getType(name); @@ -157,7 +157,9 @@ public class AbilityUtils { } else if (defined.startsWith("Replaced") && (sa != null)) { final SpellAbility root = sa.getRootAbility(); - final Object crd = root.getReplacingObject(defined.substring(8)); + AbilityKey type = AbilityKey.fromString(defined.substring(8)); + final Object crd = root.getReplacingObject(type); + if (crd instanceof Card) { c = game.getCardState((Card) crd); } else if (crd instanceof List) { @@ -712,7 +714,7 @@ public class AbilityUtils { } else if (calcX[0].startsWith("Replaced")) { final SpellAbility root = sa.getRootAbility(); - list = new CardCollection((Card) root.getReplacingObject(calcX[0].substring(8))); + list = new CardCollection((Card) root.getReplacingObject(AbilityKey.fromString(calcX[0].substring(8)))); } else if (calcX[0].startsWith("ReplaceCount")) { // ReplaceCount is similar to a regular Count, but just @@ -720,7 +722,7 @@ public class AbilityUtils { final SpellAbility root = sa.getRootAbility(); final String[] l = calcX[1].split("/"); final String m = CardFactoryUtil.extractOperators(calcX[1]); - final int count = (Integer) root.getReplacingObject(l[0]); + final int count = (Integer) root.getReplacingObject(AbilityKey.fromString(l[0])); return CardFactoryUtil.doXMath(count, m, card) * multiplier; } @@ -1063,7 +1065,7 @@ public class AbilityUtils { if (defined.endsWith("Controller")) { String replacingType = defined.substring(8); replacingType = replacingType.substring(0, replacingType.length() - 10); - final Object c = root.getReplacingObject(replacingType); + final Object c = root.getReplacingObject(AbilityKey.fromString(replacingType)); if (c instanceof Card) { o = ((Card) c).getController(); } @@ -1074,14 +1076,14 @@ public class AbilityUtils { else if (defined.endsWith("Owner")) { String replacingType = defined.substring(8); replacingType = replacingType.substring(0, replacingType.length() - 5); - final Object c = root.getReplacingObject(replacingType); + final Object c = root.getReplacingObject(AbilityKey.fromString(replacingType)); if (c instanceof Card) { o = ((Card) c).getOwner(); } } else { final String replacingType = defined.substring(8); - o = root.getReplacingObject(replacingType); + o = root.getReplacingObject(AbilityKey.fromString(replacingType)); } if (o != null) { if (o instanceof Player) { diff --git a/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java b/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java index 1d15998fe9c..960a0c38563 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/AmassEffect.java @@ -8,6 +8,7 @@ import forge.game.card.Card; import forge.game.card.CardCollectionView; import forge.game.card.CardLists; import forge.game.card.CardPredicates; +import forge.game.card.CardZoneTable; import forge.game.card.CounterType; import forge.game.card.token.TokenInfo; import forge.game.event.GameEventTokenCreated; @@ -44,6 +45,17 @@ public class AmassEffect extends SpellAbilityEffect { final int amount = AbilityUtils.calculateAmount(card, sa.getParamOrDefault("Num", "1"), sa); final boolean remember = sa.hasParam("RememberAmass"); + boolean useZoneTable = true; + CardZoneTable triggerList = sa.getChangeZoneTable(); + if (triggerList == null) { + triggerList = new CardZoneTable(); + useZoneTable = false; + } + if (sa.hasParam("ChangeZoneTable")) { + sa.setChangeZoneTable(triggerList); + useZoneTable = true; + } + // create army token if needed if (CardLists.count(activator.getCardsIn(ZoneType.Battlefield), CardPredicates.isType("Army")) == 0) { final String tokenScript = "b_0_0_zombie_army"; @@ -54,9 +66,16 @@ public class AmassEffect extends SpellAbilityEffect { // Should this be catching the Card that's returned? Card c = game.getAction().moveToPlay(tok, sa); + if (c.getZone() != null) { + triggerList.put(ZoneType.None, c.getZone().getZoneType(), c); + } c.updateStateForView(); } + if (!useZoneTable) { + triggerList.triggerChangesZoneAll(game); + triggerList.clear(); + } game.fireEvent(new GameEventTokenCreated()); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/BlockEffect.java b/forge-game/src/main/java/forge/game/ability/effects/BlockEffect.java index 5737a68e3e2..3994617deb7 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/BlockEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/BlockEffect.java @@ -12,6 +12,8 @@ import forge.game.spellability.SpellAbility; import forge.game.trigger.TriggerType; import forge.game.zone.ZoneType; +import forge.util.Lang; + import java.util.*; public class BlockEffect extends SpellAbilityEffect { @@ -106,7 +108,7 @@ public class BlockEffect extends SpellAbilityEffect { } } - sb.append(String.join(", ", blockers)).append(" block ").append(String.join(", ", attackers)); + sb.append(Lang.joinHomogenous(blockers)).append(" block ").append(Lang.joinHomogenous(attackers)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java index 742132bac5f..5ca1a765d2f 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CloneEffect.java @@ -110,7 +110,7 @@ public class CloneEffect extends SpellAbilityEffect { } if (sa.hasParam("CloneZone")) { - if (!tgtCard.getZone().is(ZoneType.smartValueOf(sa.getParam("CloneZone")))) { + if (!tgtCard.isInZone(ZoneType.smartValueOf(sa.getParam("CloneZone")))) { return; } } @@ -134,7 +134,7 @@ public class CloneEffect extends SpellAbilityEffect { tgtCard.clearImprintedCards(); // check if clone is now an Aura that needs to be attached - if (tgtCard.isAura() && !tgtCard.getZone().is(ZoneType.Battlefield)) { + if (tgtCard.isAura() && !tgtCard.isInZone(ZoneType.Battlefield)) { AttachEffect.attachAuraOnIndirectEnterBattlefield(tgtCard); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java b/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java index 1c072cf3dba..f82231f20b4 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/CounterEffect.java @@ -18,7 +18,6 @@ import java.util.List; import java.util.Map; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; public class CounterEffect extends SpellAbilityEffect { @Override @@ -155,10 +154,9 @@ public class CounterEffect extends SpellAbilityEffect { final SpellAbility srcSA, final SpellAbilityStackInstance si) { final Game game = tgtSA.getActivatingPlayer().getGame(); // Run any applicable replacement effects. - final Map repParams = Maps.newHashMap(); - repParams.put("TgtSA", tgtSA); - repParams.put("Affected", tgtSA.getHostCard()); - repParams.put("Cause", srcSA.getHostCard()); + final Map repParams = AbilityKey.mapFromAffected(tgtSA.getHostCard()); + repParams.put(AbilityKey.TgtSA, tgtSA); + repParams.put(AbilityKey.Cause, srcSA.getHostCard()); if (game.getReplacementHandler().run(ReplacementType.Counter, repParams) != ReplacementResult.NotReplaced) { return; } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ETBReplacementEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ETBReplacementEffect.java index 4241b8280d1..b524281dbe7 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ETBReplacementEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ETBReplacementEffect.java @@ -1,5 +1,6 @@ package forge.game.ability.effects; +import forge.game.ability.AbilityKey; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; import forge.game.spellability.SpellAbility; @@ -11,6 +12,6 @@ import forge.game.spellability.SpellAbility; public class ETBReplacementEffect extends SpellAbilityEffect { @Override public void resolve(SpellAbility sa) { - sa.getActivatingPlayer().getGame().getAction().moveToPlay(((Card) sa.getReplacingObject("Card")), sa); + sa.getActivatingPlayer().getGame().getAction().moveToPlay(((Card) sa.getReplacingObject(AbilityKey.Card)), sa); } } \ No newline at end of file diff --git a/forge-game/src/main/java/forge/game/ability/effects/PermanentCreatureEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PermanentCreatureEffect.java index 64f1e37220c..c2207b51063 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PermanentCreatureEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PermanentCreatureEffect.java @@ -2,6 +2,7 @@ package forge.game.ability.effects; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; /** * TODO: Write javadoc for this type. @@ -13,7 +14,7 @@ public class PermanentCreatureEffect extends PermanentEffect { public String getStackDescription(final SpellAbility sa) { final Card sourceCard = sa.getHostCard(); final StringBuilder sb = new StringBuilder(); - sb.append(sourceCard.getName()).append(" - Creature ").append(sourceCard.getNetPower()); + sb.append(sourceCard.getName()).append(" - ").append(Localizer.getInstance().getMessage("lblCreature")).append(" ").append(sourceCard.getNetPower()); sb.append(" / ").append(sourceCard.getNetToughness()); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java b/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java index e43f7876b5d..75d8693b8f0 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/PumpEffect.java @@ -120,7 +120,10 @@ public class PumpEffect extends SpellAbilityEffect { && !(host.isInPlay() || host.isInZone(ZoneType.Stack))) { return; } - p.addChangedKeywords(keywords, ImmutableList.of(), timestamp); + + if (!keywords.isEmpty()) { + p.addChangedKeywords(keywords, ImmutableList.of(), timestamp); + } if (!sa.hasParam("Permanent")) { // If not Permanent, remove Pumped at EOT @@ -129,12 +132,7 @@ public class PumpEffect extends SpellAbilityEffect { @Override public void run() { - - if (keywords.size() > 0) { - for (int i = 0; i < keywords.size(); i++) { - p.removeKeyword(keywords.get(i)); - } - } + p.removeChangedKeywords(timestamp); } }; addUntilCommand(sa, untilEOT); diff --git a/forge-game/src/main/java/forge/game/ability/effects/ReplaceDamageEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ReplaceDamageEffect.java index 6620b89c346..6261fac4440 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ReplaceDamageEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ReplaceDamageEffect.java @@ -2,10 +2,9 @@ package forge.game.ability.effects; import java.util.Map; +import forge.game.ability.AbilityKey; import org.apache.commons.lang3.StringUtils; -import com.google.common.collect.Maps; - import forge.game.Game; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; @@ -31,10 +30,10 @@ public class ReplaceDamageEffect extends SpellAbilityEffect { String varValue = sa.getParamOrDefault("VarName", "1"); @SuppressWarnings("unchecked") - Map originalParams = (Map) sa.getReplacingObject("OriginalParams"); - Map params = Maps.newHashMap(originalParams); + Map originalParams = (Map) sa.getReplacingObject(AbilityKey.OriginalParams); + Map params = AbilityKey.newMap(originalParams); - Integer dmg = (Integer) sa.getReplacingObject("DamageAmount"); + Integer dmg = (Integer) sa.getReplacingObject(AbilityKey.DamageAmount); int prevent = AbilityUtils.calculateAmount(card, varValue, sa); @@ -54,10 +53,10 @@ public class ReplaceDamageEffect extends SpellAbilityEffect { // no damage for original target anymore if (dmg <= 0) { - originalParams.put("ReplacementResult", ReplacementResult.Replaced); + originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Replaced); return; } - params.put("DamageAmount", dmg); + params.put(AbilityKey.DamageAmount, dmg); //try to call replacementHandler with new Params @@ -65,16 +64,16 @@ public class ReplaceDamageEffect extends SpellAbilityEffect { switch (result) { case NotReplaced: case Updated: { - for (Map.Entry e : params.entrySet()) { + for (Map.Entry e : params.entrySet()) { originalParams.put(e.getKey(), e.getValue()); } // effect was updated - originalParams.put("ReplacementResult", ReplacementResult.Updated); + originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated); break; } default: // effect was replaced with something else - originalParams.put("ReplacementResult", result); + originalParams.put(AbilityKey.ReplacementResult, result); break; } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java index 260eb307491..af761de13fb 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ReplaceEffect.java @@ -7,6 +7,7 @@ import com.google.common.collect.Maps; import forge.game.Game; import forge.game.GameObject; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; import forge.game.card.Card; @@ -23,14 +24,14 @@ public class ReplaceEffect extends SpellAbilityEffect { final Card card = sa.getHostCard(); final Game game = card.getGame(); - final String varName = sa.getParam("VarName"); + final AbilityKey varName = AbilityKey.fromString(sa.getParam("VarName")); final String varValue = sa.getParam("VarValue"); final String type = sa.getParamOrDefault("VarType", "amount"); final ReplacementType retype = sa.getReplacementEffect().getMode(); @SuppressWarnings("unchecked") - Map originalParams = (Map) sa.getReplacingObject("OriginalParams"); - Map params = Maps.newHashMap(originalParams); + Map originalParams = (Map) sa.getReplacingObject(AbilityKey.OriginalParams); + Map params = Maps.newHashMap(originalParams); if ("Card".equals(type)) { List list = AbilityUtils.getDefinedCards(card, varValue, sa); @@ -56,8 +57,8 @@ public class ReplaceEffect extends SpellAbilityEffect { params.put(varName, AbilityUtils.calculateAmount(card, varValue, sa)); } - if (params.containsKey("EffectOnly")) { - params.put("EffectOnly", true); + if (params.containsKey(AbilityKey.EffectOnly)) { + params.put(AbilityKey.EffectOnly, true); } //try to call replacementHandler with new Params @@ -65,16 +66,16 @@ public class ReplaceEffect extends SpellAbilityEffect { switch (result) { case NotReplaced: case Updated: { - for (Map.Entry e : params.entrySet()) { + for (Map.Entry e : params.entrySet()) { originalParams.put(e.getKey(), e.getValue()); } // effect was updated - originalParams.put("ReplacementResult", ReplacementResult.Updated); + originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated); break; } default: // effect was replaced with something else - originalParams.put("ReplacementResult", result); + originalParams.put(AbilityKey.ReplacementResult, result); break; } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/ReplaceSplitDamageEffect.java b/forge-game/src/main/java/forge/game/ability/effects/ReplaceSplitDamageEffect.java index 4d504b97c28..048d41e1c17 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/ReplaceSplitDamageEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/ReplaceSplitDamageEffect.java @@ -3,10 +3,9 @@ package forge.game.ability.effects; import java.util.List; import java.util.Map; +import forge.game.ability.AbilityKey; import org.apache.commons.lang3.StringUtils; -import com.google.common.collect.Maps; - import forge.game.Game; import forge.game.GameEntity; import forge.game.GameEntityCounterTable; @@ -36,10 +35,10 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect { String varValue = sa.getParamOrDefault("VarName", "1"); @SuppressWarnings("unchecked") - Map originalParams = (Map) sa.getReplacingObject("OriginalParams"); - Map params = Maps.newHashMap(originalParams); + Map originalParams = (Map) sa.getReplacingObject(AbilityKey.OriginalParams); + Map params = AbilityKey.newMap(originalParams); - Integer dmg = (Integer) sa.getReplacingObject("DamageAmount"); + Integer dmg = (Integer) sa.getReplacingObject(AbilityKey.DamageAmount); int prevent = AbilityUtils.calculateAmount(card, varValue, sa); @@ -57,15 +56,15 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect { card.setSVar(varValue, "Number$" + prevent); } - Card sourceLKI = (Card) sa.getReplacingObject("Source"); + Card sourceLKI = (Card) sa.getReplacingObject(AbilityKey.Source); - CardDamageMap damageMap = (CardDamageMap) originalParams.get("DamageMap"); - CardDamageMap preventMap = (CardDamageMap) originalParams.get("PreventMap"); - GameEntityCounterTable counterTable = (GameEntityCounterTable) originalParams.get("CounterTable"); - SpellAbility cause = (SpellAbility) originalParams.get("Cause"); + CardDamageMap damageMap = (CardDamageMap) originalParams.get(AbilityKey.DamageMap); + CardDamageMap preventMap = (CardDamageMap) originalParams.get(AbilityKey.PreventMap); + GameEntityCounterTable counterTable = (GameEntityCounterTable) originalParams.get(AbilityKey.CounterTable); + SpellAbility cause = (SpellAbility) originalParams.get(AbilityKey.Cause); - boolean isCombat = (Boolean) originalParams.get("IsCombat"); - boolean noPrevention = (Boolean) originalParams.get("NoPreventDamage"); + boolean isCombat = (Boolean) originalParams.get(AbilityKey.IsCombat); + boolean noPrevention = (Boolean) originalParams.get(AbilityKey.NoPreventDamage); GameEntity obj = (GameEntity) list.get(0); @@ -74,26 +73,26 @@ public class ReplaceSplitDamageEffect extends SpellAbilityEffect { // no damage for original target anymore if (dmg <= 0) { - originalParams.put("ReplacementResult", ReplacementResult.Replaced); + originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Replaced); return; } - params.put("DamageAmount", dmg); + params.put(AbilityKey.DamageAmount, dmg); //try to call replacementHandler with new Params ReplacementResult result = game.getReplacementHandler().run(event, params); switch (result) { case NotReplaced: case Updated: { - for (Map.Entry e : params.entrySet()) { + for (Map.Entry e : params.entrySet()) { originalParams.put(e.getKey(), e.getValue()); } // effect was updated - originalParams.put("ReplacementResult", ReplacementResult.Updated); + originalParams.put(AbilityKey.ReplacementResult, ReplacementResult.Updated); break; } default: // effect was replaced with something else - originalParams.put("ReplacementResult", result); + originalParams.put(AbilityKey.ReplacementResult, result); break; } } diff --git a/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java b/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java index 0d76b269cdc..49fd4e62a98 100644 --- a/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java +++ b/forge-game/src/main/java/forge/game/ability/effects/TokenEffect.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.List; import forge.card.MagicColor; +import forge.game.ability.AbilityKey; import forge.game.card.token.TokenInfo; import org.apache.commons.lang3.StringUtils; @@ -224,8 +225,11 @@ public class TokenEffect extends SpellAbilityEffect { // Cause of the Token Effect, in general it should be this // but if its a Replacement Effect, it might be something else or null SpellAbility cause = sa; - if (root.isReplacementAbility() && root.hasReplacingObject("Cause")) { - cause = (SpellAbility)root.getReplacingObject("Cause"); + if (root.isReplacementAbility()) { + SpellAbility replacingObject = (SpellAbility) root.getReplacingObject(AbilityKey.Cause); + if (replacingObject != null) { + cause = replacingObject; + } } final boolean remember = sa.hasParam("RememberTokens"); diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index c580357e6c8..e7fac44ec75 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -689,9 +689,7 @@ public class Card extends GameEntity implements Comparable { if (result && runTriggers) { // Run replacement effects - Map repParams = Maps.newHashMap(); - repParams.put("Affected", this); - getGame().getReplacementHandler().run(ReplacementType.TurnFaceUp, repParams); + getGame().getReplacementHandler().run(ReplacementType.TurnFaceUp, AbilityKey.mapFromAffected(this)); // Run triggers getGame().getTriggerHandler().registerActiveTrigger(this, false); @@ -1241,18 +1239,17 @@ public class Card extends GameEntity implements Comparable { addAmount = 0; // As per rule 107.1b return 0; } - final Map repParams = Maps.newHashMap(); - repParams.put("Affected", this); - repParams.put("Source", source); - repParams.put("CounterType", counterType); - repParams.put("CounterNum", addAmount); - repParams.put("EffectOnly", applyMultiplier); + final Map repParams = AbilityKey.mapFromAffected(this); + repParams.put(AbilityKey.Source, source); + repParams.put(AbilityKey.CounterType, counterType); + repParams.put(AbilityKey.CounterNum, addAmount); + repParams.put(AbilityKey.EffectOnly, applyMultiplier); switch (getGame().getReplacementHandler().run(ReplacementType.AddCounter, repParams)) { case NotReplaced: break; case Updated: { - addAmount = (int) repParams.get("CounterNum"); + addAmount = (int) repParams.get(AbilityKey.CounterNum); break; } default: @@ -3158,6 +3155,7 @@ public class Card extends GameEntity implements Comparable { public final void addColor(final String s, final boolean addToColors, final long timestamp) { changedCardColors.put(timestamp, new CardColor(s, addToColors, timestamp)); currentState.getView().updateColors(this); + currentState.getView().updateHasChangeColors(!getChangedCardColors().isEmpty()); } public final void removeColor(final long timestampIn) { @@ -3165,6 +3163,7 @@ public class Card extends GameEntity implements Comparable { if (removeCol != null) { currentState.getView().updateColors(this); + currentState.getView().updateHasChangeColors(!getChangedCardColors().isEmpty()); } } @@ -3611,10 +3610,7 @@ public class Card extends GameEntity implements Comparable { if (!tapped) { return; } // Run Replacement effects - final Map repRunParams = Maps.newHashMap(); - repRunParams.put("Affected", this); - - if (getGame().getReplacementHandler().run(ReplacementType.Untap, repRunParams) != ReplacementResult.NotReplaced) { + if (getGame().getReplacementHandler().run(ReplacementType.Untap, AbilityKey.mapFromAffected(this)) != ReplacementResult.NotReplaced) { return; } @@ -5622,34 +5618,7 @@ public class Card extends GameEntity implements Comparable { } final Card source = sa.getHostCard(); - final MutableBoolean result = new MutableBoolean(true); - visitKeywords(currentState, new Visitor() { - @Override - public boolean visit(KeywordInterface kw) { - switch (kw.getOriginal()) { - case "Shroud": - StringBuilder sb = new StringBuilder(); - sb.append("Can target CardUID_").append(getId()); - sb.append(" with spells and abilities as though it didn't have shroud."); - if (sa.getActivatingPlayer() == null) { - System.err.println("Unexpected behavior: SA activator was null when trying to determine if the activating player could target a card with Shroud. SA host card = " + source + ", SA = " + sa); - result.setFalse(); // FIXME: maybe this should check by SA host card controller at this point instead? - } else if (!sa.getActivatingPlayer().hasKeyword(sb.toString())) { - result.setFalse(); - } - break; - case "CARDNAME can't be the target of spells.": - if (sa.isSpell()) { - result.setFalse(); - } - break; - } - return result.isTrue(); - } - }); - if (result.isFalse()) { - return false; - } + if (sa.isSpell()) { for(KeywordInterface inst : source.getKeywords()) { String kw = inst.getOriginal(); diff --git a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java index f0317647e70..d5ffd39750c 100644 --- a/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java +++ b/forge-game/src/main/java/forge/game/card/CardFactoryUtil.java @@ -4501,7 +4501,9 @@ public class CardFactoryUtil { effect = "Mode$ CantTarget | Hexproof$ True | ValidCard$ Card.Self | Secondary$ True" + sbValid.toString() + " | Activator$ Opponent | Description$ " + sbDesc.toString() + " (" + inst.getReminderText() + ")"; - + } else if (keyword.equals("Shroud")) { + effect = "Mode$ CantTarget | Shroud$ True | ValidCard$ Card.Self | Secondary$ True" + + " | Description$ Shroud (" + inst.getReminderText() + ")"; } else if (keyword.startsWith("Strive")) { final String[] k = keyword.split(":"); final String manacost = k[1]; @@ -4693,19 +4695,30 @@ public class CardFactoryUtil { } sa.setAdventure(true); + StringBuilder sb = new StringBuilder(); + sb.append("Event$ Moved | ValidCard$ Card.Self | Origin$ Stack | ExcludeDestination$ Exile "); + sb.append("| ValidStackSa$ Spell.Adventure | Fizzle$ False | Secondary$ True | Description$ Adventure"); + + String repeffstr = sb.toString(); + String abExile = "DB$ ChangeZone | Defined$ Self | Origin$ Stack | Destination$ Exile | StackDescription$ None"; - AbilitySub saExile = (AbilitySub)AbilityFactory.getAbility(abExile, card); + SpellAbility saExile = AbilityFactory.getAbility(abExile, card); String abEffect = "DB$ Effect | RememberObjects$ Self | StaticAbilities$ Play | ExileOnMoved$ Exile | Duration$ Permanent | ConditionDefined$ Self | ConditionPresent$ Card.nonCopiedSpell"; AbilitySub saEffect = (AbilitySub)AbilityFactory.getAbility(abEffect, card); - StringBuilder sb = new StringBuilder(); - sb.append("Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonAdventure"); - sb.append(" | AffectedZone$ Exile | Description$ You may cast the card."); - saEffect.setSVar("Play", sb.toString()); + StringBuilder sbPlay = new StringBuilder(); + sbPlay.append("Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonAdventure"); + sbPlay.append(" | AffectedZone$ Exile | Description$ You may cast the card."); + saEffect.setSVar("Play", sbPlay.toString()); saExile.setSubAbility(saEffect); - sa.appendSubAbility(saExile); + + ReplacementEffect re = ReplacementHandler.parseReplacement(repeffstr, card, true); + re.setLayer(ReplacementLayer.Other); + + re.setOverridingAbility(saExile); + card.addReplacementEffect(re); } } diff --git a/forge-game/src/main/java/forge/game/card/CardState.java b/forge-game/src/main/java/forge/game/card/CardState.java index 84ece1c6bdf..1fafb514335 100644 --- a/forge-game/src/main/java/forge/game/card/CardState.java +++ b/forge-game/src/main/java/forge/game/card/CardState.java @@ -532,6 +532,9 @@ public class CardState extends GameObject { staticAbilities.add(sa.copy(card, lki)); } } + if (lki && source.loyaltyRep != null) { + this.loyaltyRep = source.loyaltyRep.copy(card, lki); + } } public CardState copy(final Card host, CardStateName name, final boolean lki) { diff --git a/forge-game/src/main/java/forge/game/card/CardView.java b/forge-game/src/main/java/forge/game/card/CardView.java index e14f45f1bb6..bc2c4c9ac2c 100644 --- a/forge-game/src/main/java/forge/game/card/CardView.java +++ b/forge-game/src/main/java/forge/game/card/CardView.java @@ -523,7 +523,6 @@ public class CardView extends GameEntityView { void updateChangedColorWords(Card c) { set(TrackableProperty.ChangedColorWords, c.getChangedTextColorWords()); } - public Map getChangedTypes() { return get(TrackableProperty.ChangedTypes); } @@ -706,11 +705,13 @@ public class CardView extends GameEntityView { // update the color only while in Game if (c.getGame() != null) { currentStateView.updateColors(currentState); + currentStateView.updateHasChangeColors(!c.getChangedCardColors().isEmpty()); } } else { currentStateView.updateLoyalty(currentState); } currentState.getView().updateKeywords(c, currentState); //update keywords even if state doesn't change + currentState.getView().setOriginalColors(c); //set original Colors CardState alternateState = isSplitCard && isFaceDown() ? c.getState(CardStateName.RightSplit) : c.getAlternateState(); @@ -840,13 +841,22 @@ public class CardView extends GameEntityView { public ColorSet getColors() { return get(TrackableProperty.Colors); } + public ColorSet getOriginalColors() { + return get(TrackableProperty.OriginalColors); + } void updateColors(Card c) { set(TrackableProperty.Colors, c.determineColor()); } void updateColors(CardState c) { set(TrackableProperty.Colors, ColorSet.fromMask(c.getColor())); } - + void setOriginalColors(Card c) { + set(TrackableProperty.OriginalColors, c.determineColor()); + } + void updateHasChangeColors(boolean hasChangeColor) { + set(TrackableProperty.HasChangedColors, hasChangeColor); + } + public boolean hasChangeColors() { return get(TrackableProperty.HasChangedColors); } public String getImageKey() { return getImageKey(null); } diff --git a/forge-game/src/main/java/forge/game/card/token/TokenInfo.java b/forge-game/src/main/java/forge/game/card/token/TokenInfo.java index 59000cb3b8f..c540ad0b56a 100644 --- a/forge-game/src/main/java/forge/game/card/token/TokenInfo.java +++ b/forge-game/src/main/java/forge/game/card/token/TokenInfo.java @@ -3,12 +3,12 @@ package forge.game.card.token; import com.google.common.base.Joiner; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import forge.ImageKeys; import forge.StaticData; import forge.card.CardType; import forge.card.MagicColor; import forge.game.Game; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardFactory; @@ -166,19 +166,18 @@ public class TokenInfo { Player player = controller; Card proto = prototype; - final Map repParams = Maps.newHashMap(); - repParams.put("Affected", player); - repParams.put("Token", prototype); - repParams.put("TokenNum", multiplier); - repParams.put("EffectOnly", applyMultiplier); + final Map repParams = AbilityKey.mapFromAffected(player); + repParams.put(AbilityKey.Token, prototype); + repParams.put(AbilityKey.TokenNum, multiplier); + repParams.put(AbilityKey.EffectOnly, applyMultiplier); switch (game.getReplacementHandler().run(ReplacementType.CreateToken, repParams)) { case NotReplaced: break; case Updated: { - multiplier = (int) repParams.get("TokenNum"); - player = (Player) repParams.get("Affected"); - proto = (Card) repParams.get("Token"); + multiplier = (int) repParams.get(AbilityKey.TokenNum); + player = (Player) repParams.get(AbilityKey.Affected); + proto = (Card) repParams.get(AbilityKey.Token); break; } default: diff --git a/forge-game/src/main/java/forge/game/combat/Combat.java b/forge-game/src/main/java/forge/game/combat/Combat.java index 0b7b6dfb8f7..7ce208dd8a8 100644 --- a/forge-game/src/main/java/forge/game/combat/Combat.java +++ b/forge-game/src/main/java/forge/game/combat/Combat.java @@ -50,7 +50,7 @@ import java.util.Map.Entry; */ public class Combat { private final Player playerWhoAttacks; - private final AttackConstraints attackConstraints; + private AttackConstraints attackConstraints; // Defenders, as they are attacked by hostile forces private final FCollection attackableEntries = new FCollection<>(); @@ -70,11 +70,7 @@ public class Combat { public Combat(final Player attacker) { playerWhoAttacks = attacker; - - // Create keys for all possible attack targets - attackableEntries.addAll(CombatUtil.getAllPossibleDefenders(playerWhoAttacks)); - - attackConstraints = new AttackConstraints(this); + initConstraints(); } public Combat(Combat combat, GameObjectMap map) { @@ -119,6 +115,13 @@ public class Combat { attackConstraints = new AttackConstraints(this); } + public void initConstraints() { + attackableEntries.clear(); + // Create keys for all possible attack targets + attackableEntries.addAll(CombatUtil.getAllPossibleDefenders(playerWhoAttacks)); + attackConstraints = new AttackConstraints(this); + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); diff --git a/forge-game/src/main/java/forge/game/cost/CostAdjustment.java b/forge-game/src/main/java/forge/game/cost/CostAdjustment.java index 6e178003a76..dc24242bdba 100644 --- a/forge-game/src/main/java/forge/game/cost/CostAdjustment.java +++ b/forge-game/src/main/java/forge/game/cost/CostAdjustment.java @@ -192,7 +192,7 @@ public class CostAdjustment { } for (final StaticAbility stAb : reduceAbilities) { - sumGeneric += applyReduceCostAbility(stAb, sa, cost); + sumGeneric += applyReduceCostAbility(stAb, sa, cost, sumGeneric); } // need to reduce generic extra because of 2 hybrid mana cost.decreaseGenericMana(sumGeneric); @@ -360,7 +360,7 @@ public class CostAdjustment { * @param manaCost * a ManaCost */ - private static int applyReduceCostAbility(final StaticAbility staticAbility, final SpellAbility sa, final ManaCostBeingPaid manaCost) { + private static int applyReduceCostAbility(final StaticAbility staticAbility, final SpellAbility sa, final ManaCostBeingPaid manaCost, int sumReduced) { //Can't reduce zero cost if (manaCost.toString().equals("{0}")) { return 0; @@ -393,7 +393,7 @@ public class CostAdjustment { minMana = Integer.valueOf(staticAbility.getParam("MinMana")); } - final int maxReduction = Math.max(0, manaCost.getConvertedManaCost() - minMana); + final int maxReduction = Math.max(0, manaCost.getConvertedManaCost() - minMana - sumReduced); if (maxReduction > 0) { return Math.min(value, maxReduction); } diff --git a/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java b/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java index 6e7adb840fb..0ef5b3ffcd7 100644 --- a/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java +++ b/forge-game/src/main/java/forge/game/keyword/KeywordInstance.java @@ -9,6 +9,8 @@ import com.google.common.collect.Lists; import forge.game.card.Card; import forge.game.card.CardFactoryUtil; +import forge.game.player.Player; +import forge.game.player.PlayerFactoryUtil; import forge.game.replacement.ReplacementEffect; import forge.game.spellability.SpellAbility; import forge.game.staticability.StaticAbility; @@ -82,7 +84,7 @@ public abstract class KeywordInstance> implements K public final void createTraits(final Card host, final boolean intrinsic) { createTraits(host, intrinsic, false); } - + /* * (non-Javadoc) * @see forge.game.keyword.KeywordInterface#createTraits(forge.game.card.Card, boolean, boolean) @@ -125,6 +127,53 @@ public abstract class KeywordInstance> implements K } } + /* (non-Javadoc) + * @see forge.game.keyword.KeywordInterface#createTraits(forge.game.player.Player) + */ + @Override + public void createTraits(Player player) { + createTraits(player, false); + } + /* (non-Javadoc) + * @see forge.game.keyword.KeywordInterface#createTraits(forge.game.player.Player, boolean) + */ + @Override + public void createTraits(Player player, boolean clear) { + if (clear) { + triggers.clear(); + replacements.clear(); + abilities.clear(); + staticAbilities.clear(); + } + try { + String msg = "KeywordInstance:createTraits: make Traits for Keyword"; + Sentry.getContext().recordBreadcrumb( + new BreadcrumbBuilder().setMessage(msg) + .withData("Player", player.getName()).withData("Keyword", this.original).build() + ); + + // add Extra for debugging + Sentry.getContext().addExtra("Player", player); + Sentry.getContext().addExtra("Keyword", this.original); + + PlayerFactoryUtil.addTriggerAbility(this, player); + PlayerFactoryUtil.addReplacementEffect(this, player); + PlayerFactoryUtil.addSpellAbility(this, player); + PlayerFactoryUtil.addStaticAbility(this, player); + } catch (Exception e) { + String msg = "KeywordInstance:createTraits: failed Traits for Keyword"; + Sentry.getContext().recordBreadcrumb( + new BreadcrumbBuilder().setMessage(msg) + .withData("Player", player.getName()).withData("Keyword", this.original).build() + ); + //rethrow + throw new RuntimeException("Error in Keyword " + this.original + " for player " + player.getName(), e); + } finally { + // remove added extra + Sentry.getContext().removeExtra("Player"); + Sentry.getContext().removeExtra("Keyword"); + } + } /* * (non-Javadoc) * @see forge.game.keyword.KeywordInterface#addTrigger(forge.game.trigger.Trigger) diff --git a/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java b/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java index d8b5f152605..2832cdd2ee4 100644 --- a/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java +++ b/forge-game/src/main/java/forge/game/keyword/KeywordInterface.java @@ -3,6 +3,7 @@ package forge.game.keyword; import java.util.Collection; import forge.game.card.Card; +import forge.game.player.Player; import forge.game.replacement.ReplacementEffect; import forge.game.spellability.SpellAbility; import forge.game.staticability.StaticAbility; @@ -24,6 +25,9 @@ public interface KeywordInterface extends Cloneable { void createTraits(final Card host, final boolean intrinsic); void createTraits(final Card host, final boolean intrinsic, final boolean clear); + void createTraits(final Player player); + void createTraits(final Player player, final boolean clear); + void addTrigger(final Trigger trg); void addReplacement(final ReplacementEffect trg); diff --git a/forge-game/src/main/java/forge/game/keyword/KeywordsChange.java b/forge-game/src/main/java/forge/game/keyword/KeywordsChange.java index 1f87bc4762f..73e1c1aa272 100644 --- a/forge-game/src/main/java/forge/game/keyword/KeywordsChange.java +++ b/forge-game/src/main/java/forge/game/keyword/KeywordsChange.java @@ -23,6 +23,11 @@ import java.util.List; import com.google.common.collect.Lists; import forge.game.card.Card; +import forge.game.player.Player; +import forge.game.replacement.ReplacementEffect; +import forge.game.spellability.SpellAbility; +import forge.game.staticability.StaticAbility; +import forge.game.trigger.Trigger; /** *

@@ -131,7 +136,13 @@ public class KeywordsChange implements Cloneable { inst.createTraits(host, false, true); } } - + + public final void addKeywordsToPlayer(final Player player) { + for (KeywordInterface inst : keywords.getValues()) { + inst.createTraits(player, true); + } + } + public final boolean removeKeywordfromAdd(final String keyword) { return keywords.remove(keyword); } @@ -201,6 +212,47 @@ public class KeywordsChange implements Cloneable { } } + /** + * @return the triggers + */ + public Collection getTriggers() { + List result = Lists.newArrayList(); + for (KeywordInterface k : this.keywords.getValues()) { + result.addAll(k.getTriggers()); + } + return result; + } + /** + * @return the replacements + */ + public Collection getReplacements() { + List result = Lists.newArrayList(); + for (KeywordInterface k : this.keywords.getValues()) { + result.addAll(k.getReplacements()); + } + return result; + } + /** + * @return the abilities + */ + public Collection getAbilities() { + List result = Lists.newArrayList(); + for (KeywordInterface k : this.keywords.getValues()) { + result.addAll(k.getAbilities()); + } + return result; + } + /** + * @return the staticAbilities + */ + public Collection getStaticAbilities() { + List result = Lists.newArrayList(); + for (KeywordInterface k : this.keywords.getValues()) { + result.addAll(k.getStaticAbilities()); + } + return result; + } + /* (non-Javadoc) * @see java.lang.Object#toString() */ diff --git a/forge-game/src/main/java/forge/game/mana/ManaPool.java b/forge-game/src/main/java/forge/game/mana/ManaPool.java index 9fb66880820..e90e6eb9b50 100644 --- a/forge-game/src/main/java/forge/game/mana/ManaPool.java +++ b/forge-game/src/main/java/forge/game/mana/ManaPool.java @@ -234,7 +234,7 @@ public class ManaPool extends ManaConversionMatrix implements Iterable { final Card host = sa.getHostCard(); if (mana.addsKeywords(sa) && mana.addsKeywordsType() && host.getType().hasStringType(mana.getManaAbility().getAddsKeywordsType())) { - final long timestamp = sa.getHostCard().getGame().getNextTimestamp(); + final long timestamp = host.getGame().getNextTimestamp(); final List kws = Arrays.asList(mana.getAddedKeywords().split(" & ")); host.addChangedCardKeywords(kws, null, false, false, timestamp); if (mana.addsKeywordsUntil()) { @@ -243,14 +243,7 @@ public class ManaPool extends ManaConversionMatrix implements Iterable { @Override public void run() { - if (!kws.isEmpty()) { - for (String kw : kws) { - if (kw.startsWith("HIDDEN")) { - sa.getHostCard().removeHiddenExtrinsicKeyword(kw); - } - } - host.removeChangedCardKeywords(timestamp); - } + host.removeChangedCardKeywords(timestamp); host.getGame().fireEvent(new GameEventCardStatsChanged(host)); } }; @@ -261,10 +254,10 @@ public class ManaPool extends ManaConversionMatrix implements Iterable { } } if (mana.addsCounters(sa)) { - mana.getManaAbility().createETBCounters(sa.getHostCard()); + mana.getManaAbility().createETBCounters(host); } if (mana.triggersWhenSpent()) { - mana.getManaAbility().addTriggersWhenSpent(sa, sa.getHostCard()); + mana.getManaAbility().addTriggersWhenSpent(sa, host); } } return true; diff --git a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java index 48e86dbfa72..85e7a784d90 100644 --- a/forge-game/src/main/java/forge/game/phase/PhaseHandler.java +++ b/forge-game/src/main/java/forge/game/phase/PhaseHandler.java @@ -283,6 +283,7 @@ public class PhaseHandler implements java.io.Serializable { case COMBAT_DECLARE_ATTACKERS: if (!playerTurn.hasLost()) { + combat.initConstraints(); game.getStack().freezeStack(); declareAttackersTurnBasedAction(); game.getStack().unfreezeStack(); diff --git a/forge-game/src/main/java/forge/game/phase/PhaseType.java b/forge-game/src/main/java/forge/game/phase/PhaseType.java index 15fda8e63d1..565f772f156 100644 --- a/forge-game/src/main/java/forge/game/phase/PhaseType.java +++ b/forge-game/src/main/java/forge/game/phase/PhaseType.java @@ -44,7 +44,16 @@ public enum PhaseType { nameForScripts = name_for_scripts; } - + + public final boolean phaseforUpdateField() { + boolean result = + ((ALL_PHASES.indexOf(this) >= ALL_PHASES.indexOf(UNTAP) + && ALL_PHASES.indexOf(this) < ALL_PHASES.indexOf(COMBAT_FIRST_STRIKE_DAMAGE)) + || (ALL_PHASES.indexOf(this) >= ALL_PHASES.indexOf(MAIN2) + && ALL_PHASES.indexOf(this) < ALL_PHASES.indexOf(CLEANUP))); + return result; + } + public final boolean isAfter(final PhaseType phase) { return ALL_PHASES.indexOf(this) > ALL_PHASES.indexOf(phase); } diff --git a/forge-game/src/main/java/forge/game/player/Player.java b/forge-game/src/main/java/forge/game/player/Player.java index a187d2a101e..510041f2043 100644 --- a/forge-game/src/main/java/forge/game/player/Player.java +++ b/forge-game/src/main/java/forge/game/player/Player.java @@ -20,6 +20,8 @@ package forge.game.player; import com.google.common.base.Function; import com.google.common.base.Predicates; import com.google.common.collect.*; + +import forge.ImageKeys; import forge.LobbyPlayer; import forge.card.MagicColor; import forge.game.*; @@ -41,7 +43,6 @@ import forge.game.phase.PhaseType; import forge.game.replacement.ReplacementHandler; import forge.game.replacement.ReplacementResult; import forge.game.replacement.ReplacementType; -import forge.game.spellability.AbilityActivated; import forge.game.spellability.SpellAbility; import forge.game.staticability.StaticAbility; import forge.game.trigger.Trigger; @@ -155,6 +156,7 @@ public class Player extends GameEntity implements Comparable { private Card monarchEffect = null; private Card blessingEffect = null; + private Card keywordEffect = null; private final AchievementTracker achievementTracker = new AchievementTracker(); private final PlayerView view; @@ -235,10 +237,7 @@ public class Player extends GameEntity implements Comparable { } // Replacement effects - final Map repRunParams = Maps.newHashMap(); - repRunParams.put("Affected", this); - - if (game.getReplacementHandler().run(ReplacementType.SetInMotion, repRunParams) != ReplacementResult.NotReplaced) { + if (game.getReplacementHandler().run(ReplacementType.SetInMotion, AbilityKey.mapFromAffected(this)) != ReplacementResult.NotReplaced) { return; } @@ -403,10 +402,9 @@ public class Player extends GameEntity implements Comparable { public final boolean gainLife(int lifeGain, final Card source, final SpellAbility sa) { // Run any applicable replacement effects. - final Map repParams = Maps.newHashMap(); - repParams.put("Affected", this); - repParams.put("LifeGained", lifeGain); - repParams.put("Source", source); + final Map repParams = AbilityKey.mapFromAffected(this); + repParams.put(AbilityKey.LifeGained, lifeGain); + repParams.put(AbilityKey.Source, source); if (!canGainLife()) { return false; @@ -417,8 +415,8 @@ public class Player extends GameEntity implements Comparable { break; case Updated: // check if this is still the affected player - if (this.equals(repParams.get("Affected"))) { - lifeGain = (int) repParams.get("LifeGained"); + if (this.equals(repParams.get(AbilityKey.Affected))) { + lifeGain = (int) repParams.get(AbilityKey.LifeGained); // negative update means life loss if (lifeGain < 0) { this.loseLife(-lifeGain); @@ -914,18 +912,17 @@ public class Player extends GameEntity implements Comparable { return 0; } - final Map repParams = Maps.newHashMap(); - repParams.put("Affected", this); - repParams.put("Source", source); - repParams.put("CounterType", counterType); - repParams.put("CounterNum", addAmount); - repParams.put("EffectOnly", applyMultiplier); + final Map repParams = AbilityKey.mapFromAffected(this); + repParams.put(AbilityKey.Source, source); + repParams.put(AbilityKey.CounterType, counterType); + repParams.put(AbilityKey.CounterNum, addAmount); + repParams.put(AbilityKey.EffectOnly, applyMultiplier); switch (getGame().getReplacementHandler().run(ReplacementType.AddCounter, repParams)) { case NotReplaced: break; case Updated: { - addAmount = (int) repParams.get("CounterNum"); + addAmount = (int) repParams.get(AbilityKey.CounterNum); break; } default: @@ -1030,23 +1027,25 @@ public class Player extends GameEntity implements Comparable { public final void addChangedKeywords(final List addKeywords, final List removeKeywords, final Long timestamp) { // if the key already exists - merge entries + KeywordsChange cks = null; if (changedKeywords.containsKey(timestamp)) { - final KeywordsChange cks = changedKeywords.get(timestamp); + getKeywordCard().removeChangedCardTraits(timestamp); - changedKeywords.put(timestamp, cks.merge(addKeywords, removeKeywords, - cks.isRemoveAllKeywords(), cks.isRemoveIntrinsicKeywords())); - updateKeywords(); - return; + cks = changedKeywords.get(timestamp).merge(addKeywords, removeKeywords, false, false); + } else { + cks = new KeywordsChange(addKeywords, removeKeywords, false, false); } - - changedKeywords.put(timestamp, new KeywordsChange(addKeywords, removeKeywords, false, false)); + cks.addKeywordsToPlayer(this); + getKeywordCard().addChangedCardTraits(cks.getAbilities(), null, cks.getTriggers(), cks.getReplacements(), cks.getStaticAbilities(), false, false, false, timestamp); + changedKeywords.put(timestamp, cks); updateKeywords(); game.fireEvent(new GameEventPlayerStatsChanged(this)); } public final KeywordsChange removeChangedKeywords(final Long timestamp) { - KeywordsChange change = changedKeywords.remove(Long.valueOf(timestamp)); + KeywordsChange change = changedKeywords.remove(timestamp); if (change != null) { + getKeywordCard().removeChangedCardTraits(timestamp); updateKeywords(); game.fireEvent(new GameEventPlayerStatsChanged(this)); } @@ -1105,6 +1104,7 @@ public class Player extends GameEntity implements Comparable { for (final Entry ck : ImmutableList.copyOf(changedKeywords.entrySet())) { if (ck.getValue().isEmpty() && changedKeywords.remove(ck.getKey()) != null) { keywordRemoved = true; + getKeywordCard().removeChangedCardTraits(ck.getKey()); } } @@ -1183,33 +1183,17 @@ public class Player extends GameEntity implements Comparable { @Override public final boolean canBeTargetedBy(final SpellAbility sa) { - if (hasKeyword("Shroud")) { - return false; - } - if (hasKeyword("Hexproof")) { - final Player a = sa.getActivatingPlayer(); - if (isOpponentOf(a)) { - boolean cancelHexproof = false; - for (String k : a.getKeywords()) { - if (k.startsWith("IgnoreHexproof")) { - String[] m = k.split(":"); - if (isValid(m[1].split(","), a, sa.getHostCard(), sa)) { - cancelHexproof = true; - break; - } - } - } - if (!cancelHexproof) { + + // CantTarget static abilities + for (final Card ca : getGame().getCardsIn(ZoneType.listValueOf("Battlefield,Command"))) { + for (final StaticAbility stAb : ca.getStaticAbilities()) { + if (stAb.applyAbility("CantTarget", this, sa)) { return false; } } } - if (hasProtectionFrom(sa.getHostCard())) { - return false; - } - - return (!hasKeyword("You can't be the targets of spells or activated abilities") || (!sa.isSpell() && (!(sa instanceof AbilityActivated)))); + return !hasProtectionFrom(sa.getHostCard()); } @@ -1276,16 +1260,15 @@ public class Player extends GameEntity implements Comparable { public void surveil(int num, SpellAbility cause) { - final Map repParams = Maps.newHashMap(); - repParams.put("Affected", this); - repParams.put("Source", cause); - repParams.put("SurveilNum", num); + final Map repParams = AbilityKey.mapFromAffected(this); + repParams.put(AbilityKey.Source, cause); + repParams.put(AbilityKey.SurveilNum, num); switch (getGame().getReplacementHandler().run(ReplacementType.Surveil, repParams)) { case NotReplaced: break; case Updated: { - num = (int) repParams.get("SurveilNum"); + num = (int) repParams.get(AbilityKey.SurveilNum); break; } default: @@ -1346,9 +1329,8 @@ public class Player extends GameEntity implements Comparable { final CardCollection toReveal = new CardCollection(); // Replacement effects - final Map repRunParams = Maps.newHashMap(); - repRunParams.put("Affected", this); - repRunParams.put("Number", n); + final Map repRunParams = AbilityKey.mapFromAffected(this); + repRunParams.put(AbilityKey.Number, n); if (game.getReplacementHandler().run(ReplacementType.DrawCards, repRunParams) != ReplacementResult.NotReplaced) { return drawn; @@ -1378,10 +1360,7 @@ public class Player extends GameEntity implements Comparable { final PlayerZone library = getZone(ZoneType.Library); // Replacement effects - final Map repRunParams = Maps.newHashMap(); - repRunParams.put("Affected", this); - - if (game.getReplacementHandler().run(ReplacementType.Draw, repRunParams) != ReplacementResult.NotReplaced) { + if (game.getReplacementHandler().run(ReplacementType.Draw, AbilityKey.mapFromAffected(this)) != ReplacementResult.NotReplaced) { return drawn; } @@ -1556,10 +1535,9 @@ public class Player extends GameEntity implements Comparable { // that should not trigger other Replacement again if (!discardToTopOfLibrary && !discardMadness) { // Replacement effects - final Map repRunParams = Maps.newHashMap(); - repRunParams.put("Card", c); - repRunParams.put("Source", source); - repRunParams.put("Affected", this); + final Map repRunParams = AbilityKey.mapFromCard(c); + repRunParams.put(AbilityKey.Source, source); + repRunParams.put(AbilityKey.Affected, this); if (game.getReplacementHandler().run(ReplacementType.Discard, repRunParams) != ReplacementResult.NotReplaced) { return null; @@ -1861,10 +1839,7 @@ public class Player extends GameEntity implements Comparable { } // Replacement effects - final Map runParams = Maps.newHashMap(); - runParams.put("Affected", this); - - if (game.getReplacementHandler().run(ReplacementType.GameLoss, runParams) != ReplacementResult.NotReplaced) { + if (game.getReplacementHandler().run(ReplacementType.GameLoss, AbilityKey.mapFromAffected(this)) != ReplacementResult.NotReplaced) { return false; } } @@ -2455,6 +2430,7 @@ public class Player extends GameEntity implements Comparable { controllerCreator = ctrlr; controller = ctrlr; updateAvatar(); + updateSleeve(); view.updateIsAI(this); view.updateLobbyPlayerName(this); } @@ -2464,6 +2440,10 @@ public class Player extends GameEntity implements Comparable { view.updateAvatarCardImageKey(this); } + public void updateSleeve() { + view.updateSleeveIndex(this); + } + /** * Run a procedure using a different controller */ @@ -2985,4 +2965,26 @@ public class Player extends GameEntity implements Comparable { || !hasKeyword("Spells and abilities you control can't cause you to search your library."); } + + public Card getKeywordCard() { + if (keywordEffect != null) { + return keywordEffect; + } + + final PlayerZone com = getZone(ZoneType.Command); + + keywordEffect = new Card(game.nextCardId(), null, false, game); + keywordEffect.setImmutable(true); + keywordEffect.setOwner(this); + keywordEffect.setName("Keyword Effects"); + keywordEffect.setImageKey(ImageKeys.HIDDEN_CARD); + keywordEffect.addType("Effect"); + + keywordEffect.updateStateForView(); + + com.add(keywordEffect); + + this.updateZoneForView(com); + return keywordEffect; + } } diff --git a/forge-game/src/main/java/forge/game/player/PlayerController.java b/forge-game/src/main/java/forge/game/player/PlayerController.java index ecea26174d9..d5cef95818b 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerController.java +++ b/forge-game/src/main/java/forge/game/player/PlayerController.java @@ -211,7 +211,7 @@ public abstract class PlayerController { Map params); public abstract boolean confirmPayment(CostPart costPart, String string, SpellAbility sa); - public abstract ReplacementEffect chooseSingleReplacementEffect(String prompt, List possibleReplacers, Map runParams); + public abstract ReplacementEffect chooseSingleReplacementEffect(String prompt, List possibleReplacers); public abstract String chooseProtectionType(String string, SpellAbility sa, List choices); // these 4 need some refining. diff --git a/forge-game/src/main/java/forge/game/player/PlayerFactoryUtil.java b/forge-game/src/main/java/forge/game/player/PlayerFactoryUtil.java new file mode 100644 index 00000000000..0eff22b1711 --- /dev/null +++ b/forge-game/src/main/java/forge/game/player/PlayerFactoryUtil.java @@ -0,0 +1,46 @@ +package forge.game.player; + +import forge.game.card.Card; +import forge.game.keyword.KeywordInterface; +import forge.game.staticability.StaticAbility; + +public class PlayerFactoryUtil { + + public static void addStaticAbility(final KeywordInterface inst, final Player player) { + final Card card = player.getKeywordCard(); + String keyword = inst.getOriginal(); + String effect = null; + if (keyword.startsWith("Hexproof")) { + final StringBuilder sbDesc = new StringBuilder("Hexproof"); + final StringBuilder sbValid = new StringBuilder(); + + if (!keyword.equals("Hexproof")) { + final String[] k = keyword.split(":"); + + sbDesc.append(" from ").append(k[2]); + sbValid.append("| ValidSource$ ").append(k[1]); + } + + effect = "Mode$ CantTarget | Hexproof$ True | ValidPlayer$ Player.You | Secondary$ True " + + sbValid.toString() + " | Activator$ Opponent | EffectZone$ Command | Description$ " + + sbDesc.toString() + " (" + inst.getReminderText() + ")"; + } else if (keyword.equals("Shroud")) { + effect = "Mode$ CantTarget | Shroud$ True | ValidPlayer$ Player.You | Secondary$ True " + + "| EffectZone$ Command | Description$ Shroud (" + inst.getReminderText() + ")"; + } + if (effect != null) { + StaticAbility st = new StaticAbility(effect, card); + st.setIntrinsic(false); + inst.addStaticAbility(st); + } + } + + public static void addTriggerAbility(final KeywordInterface inst, Player player) { + } + + public static void addReplacementEffect(final KeywordInterface inst, Player player) { + } + + public static void addSpellAbility(final KeywordInterface inst, Player player) { + } +} diff --git a/forge-game/src/main/java/forge/game/player/PlayerView.java b/forge-game/src/main/java/forge/game/player/PlayerView.java index 28dfb54c0e3..735c0709f1b 100644 --- a/forge-game/src/main/java/forge/game/player/PlayerView.java +++ b/forge-game/src/main/java/forge/game/player/PlayerView.java @@ -85,6 +85,13 @@ public class PlayerView extends GameEntityView { set(TrackableProperty.AvatarCardImageKey, p.getLobbyPlayer().getAvatarCardImageKey()); } + public int getSleeveIndex() { + return get(TrackableProperty.SleeveIndex); + } + void updateSleeveIndex(Player p) { + set(TrackableProperty.SleeveIndex, p.getLobbyPlayer().getSleeveIndex()); + } + public String getCurrentPlaneName() { return get(TrackableProperty.CurrentPlane); } void updateCurrentPlaneName( String plane ) { set(TrackableProperty.CurrentPlane, plane); diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceAddCounter.java b/forge-game/src/main/java/forge/game/replacement/ReplaceAddCounter.java index 882daefed56..27a388c2160 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceAddCounter.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceAddCounter.java @@ -1,5 +1,6 @@ package forge.game.replacement; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.card.CounterType; import forge.game.player.Player; @@ -27,20 +28,20 @@ public class ReplaceAddCounter extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) */ @Override - public boolean canReplace(Map runParams) { - if (((int) runParams.get("CounterNum")) <= 0) { + public boolean canReplace(Map runParams) { + if (((int) runParams.get(AbilityKey.CounterNum)) <= 0) { return false; } if (hasParam("EffectOnly")) { - final Boolean effectOnly = (Boolean) runParams.get("EffectOnly"); + final Boolean effectOnly = (Boolean) runParams.get(AbilityKey.EffectOnly); if (!effectOnly) { return false; } } if (hasParam("ValidCard")) { - Object o = runParams.get("Affected"); + Object o = runParams.get(AbilityKey.Affected); if (!(o instanceof Card)) { return false; } @@ -48,7 +49,7 @@ public class ReplaceAddCounter extends ReplacementEffect { return false; } } else if (hasParam("ValidPlayer")) { - Object o = runParams.get("Affected"); + Object o = runParams.get(AbilityKey.Affected); if (!(o instanceof Player)) { return false; } @@ -59,7 +60,7 @@ public class ReplaceAddCounter extends ReplacementEffect { if (hasParam("ValidCounterType")) { String type = getParam("ValidCounterType"); - if (CounterType.getType(type) != runParams.get("CounterType")) { + if (CounterType.getType(type) != runParams.get(AbilityKey.CounterType)) { return false; } } @@ -71,14 +72,14 @@ public class ReplaceAddCounter extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility) */ @Override - public void setReplacingObjects(Map runParams, SpellAbility sa) { - sa.setReplacingObject("CounterNum", runParams.get("CounterNum")); - sa.setReplacingObject("CounterType", ((CounterType) runParams.get("CounterType")).getName()); - Object o = runParams.get("Affected"); + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject(AbilityKey.CounterNum, runParams.get(AbilityKey.CounterNum)); + sa.setReplacingObject(AbilityKey.CounterType, ((CounterType) runParams.get(AbilityKey.CounterType)).getName()); + Object o = runParams.get(AbilityKey.Affected); if (o instanceof Card) { - sa.setReplacingObject("Card", o); + sa.setReplacingObject(AbilityKey.Card, o); } else if (o instanceof Player) { - sa.setReplacingObject("Player", o); + sa.setReplacingObject(AbilityKey.Player, o); } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceCounter.java b/forge-game/src/main/java/forge/game/replacement/ReplaceCounter.java index b3d27814b95..c5968fd1d16 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceCounter.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceCounter.java @@ -17,6 +17,7 @@ */ package forge.game.replacement; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; @@ -42,15 +43,15 @@ public class ReplaceCounter extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) */ @Override - public boolean canReplace(Map runParams) { - final SpellAbility spellAbility = (SpellAbility) runParams.get("TgtSA"); + public boolean canReplace(Map runParams) { + final SpellAbility spellAbility = (SpellAbility) runParams.get(AbilityKey.TgtSA); if (hasParam("ValidCard")) { - if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidCard").split(","), this.getHostCard())) { return false; } } if (hasParam("ValidCause")) { - if (!matchesValid(runParams.get("Cause"), getParam("ValidCause").split(","), this.getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Cause), getParam("ValidCause").split(","), this.getHostCard())) { return false; } } @@ -67,8 +68,8 @@ public class ReplaceCounter extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility) */ @Override - public void setReplacingObjects(Map runParams, SpellAbility sa) { - sa.setReplacingObject("Card", runParams.get("Affected")); + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Affected)); } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceDamage.java b/forge-game/src/main/java/forge/game/replacement/ReplaceDamage.java index 4063ec610bb..2d8681ef508 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceDamage.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceDamage.java @@ -17,6 +17,7 @@ */ package forge.game.replacement; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardFactoryUtil; @@ -46,49 +47,49 @@ public class ReplaceDamage extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) */ @Override - public boolean canReplace(Map runParams) { - if (!(runParams.containsKey("Prevention") == (hasParam("PreventionEffect") || hasParam("Prevent")))) { + public boolean canReplace(Map runParams) { + if (!(runParams.containsKey(AbilityKey.Prevention) == (hasParam("PreventionEffect") || hasParam("Prevent")))) { return false; } - if (((Integer) runParams.get("DamageAmount")) == 0) { + if (((Integer) runParams.get(AbilityKey.DamageAmount)) == 0) { // If no actual damage is dealt, there is nothing to replace return false; } if (hasParam("ValidSource")) { String validSource = getParam("ValidSource"); validSource = AbilityUtils.applyAbilityTextChangeEffects(validSource, this); - if (!matchesValid(runParams.get("DamageSource"), validSource.split(","), getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.DamageSource), validSource.split(","), getHostCard())) { return false; } } if (hasParam("ValidTarget")) { String validTarget = getParam("ValidTarget"); validTarget = AbilityUtils.applyAbilityTextChangeEffects(validTarget, this); - if (!matchesValid(runParams.get("Affected"), validTarget.split(","), getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Affected), validTarget.split(","), getHostCard())) { return false; } } if (hasParam("ValidCause")) { - if (!runParams.containsKey("Cause")) { + if (!runParams.containsKey(AbilityKey.Cause)) { return false; } - SpellAbility cause = (SpellAbility) runParams.get("Cause"); + SpellAbility cause = (SpellAbility) runParams.get(AbilityKey.Cause); String validCause = getParam("ValidCause"); validCause = AbilityUtils.applyAbilityTextChangeEffects(validCause, this); if (!matchesValid(cause, validCause.split(","), getHostCard())) { return false; } if (hasParam("CauseIsSource")) { - if (!cause.getHostCard().equals(runParams.get("DamageSource"))) { + if (!cause.getHostCard().equals(runParams.get(AbilityKey.DamageSource))) { return false; } } } if (hasParam("RelativeToSource")) { - Card source = (Card) runParams.get("DamageSource"); + Card source = (Card) runParams.get(AbilityKey.DamageSource); String validRelative = getParam("RelativeToSource"); validRelative = AbilityUtils.applyAbilityTextChangeEffects(validRelative, this); - if (!matchesValid(runParams.get("DamageTarget"), validRelative.split(","), source)) { + if (!matchesValid(runParams.get(AbilityKey.DamageTarget), validRelative.split(","), source)) { return false; } } @@ -103,17 +104,17 @@ public class ReplaceDamage extends ReplacementEffect { intoperand = CardFactoryUtil.xCount(getHostCard(), getHostCard().getSVar(operand)); } - if (!Expressions.compare((Integer) runParams.get("DamageAmount"), operator, intoperand)) { + if (!Expressions.compare((Integer) runParams.get(AbilityKey.DamageAmount), operator, intoperand)) { return false; } } if (hasParam("IsCombat")) { if (getParam("IsCombat").equals("True")) { - if (!((Boolean) runParams.get("IsCombat"))) { + if (!((Boolean) runParams.get(AbilityKey.IsCombat))) { return false; } } else { - if ((Boolean) runParams.get("IsCombat")) { + if ((Boolean) runParams.get(AbilityKey.IsCombat)) { return false; } } @@ -149,10 +150,10 @@ public class ReplaceDamage extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility) */ @Override - public void setReplacingObjects(Map runParams, SpellAbility sa) { - sa.setReplacingObject("DamageAmount", runParams.get("DamageAmount")); - sa.setReplacingObject("Target", runParams.get("Affected")); - sa.setReplacingObject("Source", runParams.get("DamageSource")); + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject(AbilityKey.DamageAmount, runParams.get(AbilityKey.DamageAmount)); + sa.setReplacingObject(AbilityKey.Target, runParams.get(AbilityKey.Affected)); + sa.setReplacingObject(AbilityKey.Source, runParams.get(AbilityKey.DamageSource)); } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceDestroy.java b/forge-game/src/main/java/forge/game/replacement/ReplaceDestroy.java index d5fe606ab2b..e9c22681fb7 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceDestroy.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceDestroy.java @@ -17,6 +17,7 @@ */ package forge.game.replacement; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; @@ -42,23 +43,23 @@ public class ReplaceDestroy extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) */ @Override - public boolean canReplace(Map runParams) { + public boolean canReplace(Map runParams) { if (hasParam("ValidPlayer")) { - if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), getHostCard())) { return false; } } if (hasParam("ValidCard")) { - Card card = (Card)runParams.get("Card"); + Card card = (Card)runParams.get(AbilityKey.Card); if (!matchesValid(card, getParam("ValidCard").split(","), getHostCard())) { return false; } // extra check for Regeneration if (hasParam("Regeneration")) { - if (!runParams.containsKey("Regeneration")) { + if (!runParams.containsKey(AbilityKey.Regeneration)) { return false; } - if (!(Boolean)runParams.get("Regeneration")) { + if (!(Boolean)runParams.get(AbilityKey.Regeneration)) { return false; } if (!card.canBeShielded()) { @@ -71,7 +72,7 @@ public class ReplaceDestroy extends ReplacementEffect { } } if (hasParam("ValidSource")) { - if (!matchesValid(runParams.get("Source"), getParam("ValidSource").split(","), getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Source), getParam("ValidSource").split(","), getHostCard())) { return false; } } @@ -83,8 +84,8 @@ public class ReplaceDestroy extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility) */ @Override - public void setReplacingObjects(Map runParams, SpellAbility sa) { - sa.setReplacingObject("Card", runParams.get("Card")); + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Card)); } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceDiscard.java b/forge-game/src/main/java/forge/game/replacement/ReplaceDiscard.java index e761d06540e..25bde9c0c6e 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceDiscard.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceDiscard.java @@ -17,6 +17,7 @@ */ package forge.game.replacement; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; @@ -42,24 +43,24 @@ public class ReplaceDiscard extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) */ @Override - public boolean canReplace(Map runParams) { + public boolean canReplace(Map runParams) { if (hasParam("ValidPlayer")) { - if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) { return false; } } if (hasParam("ValidCard")) { - if (!matchesValid(runParams.get("Card"), getParam("ValidCard").split(","), this.getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Card), getParam("ValidCard").split(","), this.getHostCard())) { return false; } } if (hasParam("ValidSource")) { - if (!matchesValid(runParams.get("Source"), getParam("ValidSource").split(","), this.getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Source), getParam("ValidSource").split(","), this.getHostCard())) { return false; } } if (hasParam("DiscardFromEffect")) { - if (null == runParams.get("Source")) { + if (null == runParams.get(AbilityKey.Source)) { return false; } } @@ -71,10 +72,10 @@ public class ReplaceDiscard extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility) */ @Override - public void setReplacingObjects(Map runParams, SpellAbility sa) { - sa.setReplacingObject("Card", runParams.get("Card")); - sa.setReplacingObject("Player", runParams.get("Affected")); - sa.setReplacingObject("Source", runParams.get("Source")); + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Card)); + sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected)); + sa.setReplacingObject(AbilityKey.Source, runParams.get(AbilityKey.Source)); } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceDraw.java b/forge-game/src/main/java/forge/game/replacement/ReplaceDraw.java index 7a32b0b30d0..9dbaf529cad 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceDraw.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceDraw.java @@ -17,6 +17,7 @@ */ package forge.game.replacement; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.phase.PhaseType; import forge.game.player.Player; @@ -44,14 +45,14 @@ public class ReplaceDraw extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) */ @Override - public boolean canReplace(Map runParams) { + public boolean canReplace(Map runParams) { if (hasParam("ValidPlayer")) { - if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) { return false; } } if (hasParam("NotFirstCardInDrawStep")) { - final Player p = (Player)runParams.get("Affected"); + final Player p = (Player)runParams.get(AbilityKey.Affected); if (p.numDrawnThisDrawStep() == 0 && this.getHostCard().getGame().getPhaseHandler().is(PhaseType.DRAW) && this.getHostCard().getGame().getPhaseHandler().isPlayerTurn(p)) { @@ -68,7 +69,7 @@ public class ReplaceDraw extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility) */ @Override - public void setReplacingObjects(Map runParams, SpellAbility sa) { - sa.setReplacingObject("Player", runParams.get("Affected")); + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected)); } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceDrawCards.java b/forge-game/src/main/java/forge/game/replacement/ReplaceDrawCards.java index ca486aa3e64..fecf53a8bf2 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceDrawCards.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceDrawCards.java @@ -17,6 +17,7 @@ */ package forge.game.replacement; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; import forge.util.Expressions; @@ -43,14 +44,14 @@ public class ReplaceDrawCards extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) */ @Override - public boolean canReplace(Map runParams) { + public boolean canReplace(Map runParams) { if (hasParam("ValidPlayer")) { - if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) { return false; } } if (hasParam("Number")) { - final int n = (Integer)runParams.get("Number"); + final int n = (Integer)runParams.get(AbilityKey.Number); String comparator = getParam("Number"); final String operator = comparator.substring(0, 2); final int operandValue = Integer.parseInt(comparator.substring(2)); @@ -68,7 +69,7 @@ public class ReplaceDrawCards extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility) */ @Override - public void setReplacingObjects(Map runParams, SpellAbility sa) { - sa.setReplacingObject("Player", runParams.get("Affected")); + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected)); } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceGainLife.java b/forge-game/src/main/java/forge/game/replacement/ReplaceGainLife.java index c026bd4ff38..083ad7b23d2 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceGainLife.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceGainLife.java @@ -17,6 +17,7 @@ */ package forge.game.replacement; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; @@ -42,22 +43,22 @@ public class ReplaceGainLife extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) */ @Override - public boolean canReplace(Map runParams) { - if (((int)runParams.get("LifeGained")) <= 0) { + public boolean canReplace(Map runParams) { + if (((int)runParams.get(AbilityKey.LifeGained)) <= 0) { return false; } if (hasParam("ValidPlayer")) { - if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) { return false; } } if (hasParam("ValidSource")) { - if (!matchesValid(runParams.get("Source"), getParam("ValidSource").split(","), this.getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Source), getParam("ValidSource").split(","), this.getHostCard())) { return false; } } if ("True".equals(getParam("SourceController"))) { - if (runParams.get("Source") == null || !runParams.get("Affected").equals(((Card)runParams.get("Source")).getController())) { + if (runParams.get(AbilityKey.Source) == null || !runParams.get(AbilityKey.Affected).equals(((Card)runParams.get(AbilityKey.Source)).getController())) { return false; } } @@ -69,9 +70,9 @@ public class ReplaceGainLife extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility) */ @Override - public void setReplacingObjects(Map runParams, SpellAbility sa) { - sa.setReplacingObject("LifeGained", runParams.get("LifeGained")); - sa.setReplacingObject("Player", runParams.get("Affected")); + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject(AbilityKey.LifeGained, runParams.get(AbilityKey.LifeGained)); + sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected)); } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceGameLoss.java b/forge-game/src/main/java/forge/game/replacement/ReplaceGameLoss.java index 0cb784588e5..3860af6c119 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceGameLoss.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceGameLoss.java @@ -1,5 +1,6 @@ package forge.game.replacement; + import forge.game.ability.AbilityKey; import forge.game.card.Card; import java.util.Map; @@ -24,9 +25,9 @@ public class ReplaceGameLoss extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) */ @Override - public boolean canReplace(Map runParams) { + public boolean canReplace(Map runParams) { if (hasParam("ValidPlayer")) { - if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) { return false; } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceMoved.java b/forge-game/src/main/java/forge/game/replacement/ReplaceMoved.java index 650b0e82085..ee295efe59d 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceMoved.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceMoved.java @@ -1,5 +1,6 @@ package forge.game.replacement; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.player.Player; @@ -28,9 +29,9 @@ public class ReplaceMoved extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) */ @Override - public boolean canReplace(Map runParams) { + public boolean canReplace(Map runParams) { final Player controller = getHostCard().getController(); - final Card affected = (Card) runParams.get("Affected"); + final Card affected = (Card) runParams.get(AbilityKey.Affected); if (hasParam("ValidCard")) { if (!matchesValid(affected, getParam("ValidCard").split(","), getHostCard())) { @@ -39,27 +40,27 @@ public class ReplaceMoved extends ReplacementEffect { } if (hasParam("ValidLKI")) { - if (!matchesValid(runParams.get("CardLKI"), getParam("ValidLKI").split(","), getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.CardLKI), getParam("ValidLKI").split(","), getHostCard())) { return false; } } if (hasParam("Origin")) { - ZoneType zt = (ZoneType) runParams.get("Origin"); + ZoneType zt = (ZoneType) runParams.get(AbilityKey.Origin); if (!ZoneType.listValueOf(getParam("Origin")).contains(zt)) { return false; } } if (hasParam("Destination")) { - ZoneType zt = (ZoneType) runParams.get("Destination"); + ZoneType zt = (ZoneType) runParams.get(AbilityKey.Destination); if (!ZoneType.listValueOf(getParam("Destination")).contains(zt)) { return false; } } if (hasParam("ExcludeDestination")) { - ZoneType zt = (ZoneType) runParams.get("Destination"); + ZoneType zt = (ZoneType) runParams.get(AbilityKey.Destination); if (ZoneType.listValueOf(getParam("ExcludeDestination")).contains(zt)) { return false; } @@ -67,29 +68,29 @@ public class ReplaceMoved extends ReplacementEffect { if (hasParam("Fizzle")) { // if Replacement look for Fizzle - if (!runParams.containsKey("Fizzle")) { + if (!runParams.containsKey(AbilityKey.Fizzle)) { return false; } - Boolean val = (Boolean) runParams.get("Fizzle"); + Boolean val = (Boolean) runParams.get(AbilityKey.Fizzle); if ("True".equals(getParam("Fizzle")) != val) { return false; } } if (hasParam("ValidStackSa")) { - if (!runParams.containsKey("StackSa")) { + if (!runParams.containsKey(AbilityKey.StackSa)) { return false; } - if (!((SpellAbility)runParams.get("StackSa")).isValid(getParam("ValidStackSa").split(","), getHostCard().getController(), getHostCard(), null)) { + if (!((SpellAbility)runParams.get(AbilityKey.StackSa)).isValid(getParam("ValidStackSa").split(","), getHostCard().getController(), getHostCard(), null)) { return false; } } if (hasParam("Cause")) { - if (!runParams.containsKey("Cause")) { + if (!runParams.containsKey(AbilityKey.Cause)) { return false; } - SpellAbility cause = (SpellAbility) runParams.get("Cause"); + SpellAbility cause = (SpellAbility) runParams.get(AbilityKey.Cause); if (cause == null) { return false; } @@ -99,8 +100,8 @@ public class ReplaceMoved extends ReplacementEffect { } if (hasParam("NotCause")) { - if (runParams.containsKey("Cause")) { - SpellAbility cause = (SpellAbility) runParams.get("Cause"); + if (runParams.containsKey(AbilityKey.Cause)) { + SpellAbility cause = (SpellAbility) runParams.get(AbilityKey.Cause); if (cause != null) { if (cause.isValid(getParam("NotCause").split(","), controller, getHostCard(), null)) { return false; @@ -116,10 +117,10 @@ public class ReplaceMoved extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility) */ @Override - public void setReplacingObjects(Map runParams, SpellAbility sa) { - sa.setReplacingObject("Card", runParams.get("Affected")); - sa.setReplacingObject("CardLKI", runParams.get("CardLKI")); - sa.setReplacingObject("Cause", runParams.get("Cause")); + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Affected)); + sa.setReplacingObject(AbilityKey.CardLKI, runParams.get(AbilityKey.CardLKI)); + sa.setReplacingObject(AbilityKey.Cause, runParams.get(AbilityKey.Cause)); } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceProduceMana.java b/forge-game/src/main/java/forge/game/replacement/ReplaceProduceMana.java index 3cfc1f92d81..13e8b68f782 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceProduceMana.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceProduceMana.java @@ -1,5 +1,6 @@ package forge.game.replacement; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.card.CardFactoryUtil; import forge.game.spellability.SpellAbility; @@ -29,10 +30,10 @@ public class ReplaceProduceMana extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) */ @Override - public boolean canReplace(Map runParams) { + public boolean canReplace(Map runParams) { //Check for tapping if (!hasParam("NoTapCheck")) { - final SpellAbility manaAbility = (SpellAbility) runParams.get("AbilityMana"); + final SpellAbility manaAbility = (SpellAbility) runParams.get(AbilityKey.AbilityMana); if (manaAbility == null || manaAbility.getRootAbility().getPayCosts() == null || !manaAbility.getRootAbility().getPayCosts().hasTapCost()) { return false; } @@ -48,14 +49,14 @@ public class ReplaceProduceMana extends ReplacementEffect { } catch (NumberFormatException e) { intoperand = CardFactoryUtil.xCount(getHostCard(), getHostCard().getSVar(operand)); } - int manaAmount = StringUtils.countMatches((String) runParams.get("Mana"), " ") + 1; + int manaAmount = StringUtils.countMatches((String) runParams.get(AbilityKey.Mana), " ") + 1; if (!Expressions.compare(manaAmount, operator, intoperand)) { return false; } } if (hasParam("ValidCard")) { - if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidCard").split(","), this.getHostCard())) { return false; } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceSetInMotion.java b/forge-game/src/main/java/forge/game/replacement/ReplaceSetInMotion.java index d74b1171dad..1b2b39f382b 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceSetInMotion.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceSetInMotion.java @@ -17,6 +17,7 @@ */ package forge.game.replacement; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import java.util.Map; @@ -41,9 +42,9 @@ public class ReplaceSetInMotion extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) */ @Override - public boolean canReplace(Map runParams) { + public boolean canReplace(Map runParams) { if (hasParam("ValidPlayer")) { - if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), getHostCard())) { return false; } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceSurveil.java b/forge-game/src/main/java/forge/game/replacement/ReplaceSurveil.java index 3ee74291981..e7b8440e0b5 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceSurveil.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceSurveil.java @@ -1,5 +1,6 @@ package forge.game.replacement; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; @@ -25,13 +26,13 @@ public class ReplaceSurveil extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.Map) */ @Override - public boolean canReplace(Map runParams) { - if (((int) runParams.get("SurveilNum")) <= 0) { + public boolean canReplace(Map runParams) { + if (((int) runParams.get(AbilityKey.SurveilNum)) <= 0) { return false; } if (hasParam("ValidPlayer")) { - if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), this.getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), this.getHostCard())) { return false; } } @@ -43,9 +44,9 @@ public class ReplaceSurveil extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.Map, forge.card.spellability.SpellAbility) */ @Override - public void setReplacingObjects(Map runParams, SpellAbility sa) { - sa.setReplacingObject("Player", runParams.get("Affected")); - sa.setReplacingObject("SurveilNum", runParams.get("SurveilNum")); + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected)); + sa.setReplacingObject(AbilityKey.SurveilNum, runParams.get(AbilityKey.SurveilNum)); } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceToken.java b/forge-game/src/main/java/forge/game/replacement/ReplaceToken.java index fc6bb5ef15c..7204edfdcbe 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceToken.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceToken.java @@ -1,5 +1,6 @@ package forge.game.replacement; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; @@ -25,27 +26,27 @@ public class ReplaceToken extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.Map) */ @Override - public boolean canReplace(Map runParams) { - if (((int) runParams.get("TokenNum")) <= 0) { + public boolean canReplace(Map runParams) { + if (((int) runParams.get(AbilityKey.TokenNum)) <= 0) { return false; } if (hasParam("EffectOnly")) { - final Boolean effectOnly = (Boolean) runParams.get("EffectOnly"); + final Boolean effectOnly = (Boolean) runParams.get(AbilityKey.EffectOnly); if (!effectOnly) { return false; } } if (hasParam("ValidPlayer")) { - if (!matchesValid(runParams.get("Affected"), getParam("ValidPlayer").split(","), getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidPlayer").split(","), getHostCard())) { return false; } } if (hasParam("ValidToken")) { - if (runParams.containsKey("Token")) { - if (!matchesValid(runParams.get("Token"), getParam("ValidToken").split(","), getHostCard())) { + if (runParams.containsKey(AbilityKey.Token)) { + if (!matchesValid(runParams.get(AbilityKey.Token), getParam("ValidToken").split(","), getHostCard())) { return false; } } else { @@ -61,9 +62,9 @@ public class ReplaceToken extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.Map, forge.card.spellability.SpellAbility) */ @Override - public void setReplacingObjects(Map runParams, SpellAbility sa) { - sa.setReplacingObject("TokenNum", runParams.get("TokenNum")); - sa.setReplacingObject("Player", runParams.get("Affected")); + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject(AbilityKey.TokenNum, runParams.get(AbilityKey.TokenNum)); + sa.setReplacingObject(AbilityKey.Player, runParams.get(AbilityKey.Affected)); } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceTurnFaceUp.java b/forge-game/src/main/java/forge/game/replacement/ReplaceTurnFaceUp.java index a2c78959de3..3f433f38916 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceTurnFaceUp.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceTurnFaceUp.java @@ -1,5 +1,6 @@ package forge.game.replacement; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; @@ -25,9 +26,9 @@ public class ReplaceTurnFaceUp extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) */ @Override - public boolean canReplace(Map runParams) { + public boolean canReplace(Map runParams) { if (hasParam("ValidCard")) { - if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidCard").split(","), this.getHostCard())) { return false; } } @@ -38,8 +39,8 @@ public class ReplaceTurnFaceUp extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility) */ @Override - public void setReplacingObjects(Map runParams, SpellAbility sa) { - sa.setReplacingObject("Card", runParams.get("Affected")); + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Affected)); } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplaceUntap.java b/forge-game/src/main/java/forge/game/replacement/ReplaceUntap.java index 7e4168f1281..d52c65e75b8 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplaceUntap.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplaceUntap.java @@ -17,6 +17,7 @@ */ package forge.game.replacement; +import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.player.Player; import forge.game.phase.PhaseType; @@ -44,14 +45,14 @@ public class ReplaceUntap extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#canReplace(java.util.HashMap) */ @Override - public boolean canReplace(Map runParams) { + public boolean canReplace(Map runParams) { if (hasParam("ValidCard")) { - if (!matchesValid(runParams.get("Affected"), getParam("ValidCard").split(","), this.getHostCard())) { + if (!matchesValid(runParams.get(AbilityKey.Affected), getParam("ValidCard").split(","), this.getHostCard())) { return false; } } if (hasParam("UntapStep")) { - final Object o = runParams.get("Affected"); + final Object o = runParams.get(AbilityKey.Affected); //normally should not happen, but protect from possible crash. if (!(o instanceof Card)) { return false; @@ -72,8 +73,8 @@ public class ReplaceUntap extends ReplacementEffect { * @see forge.card.replacement.ReplacementEffect#setReplacingObjects(java.util.HashMap, forge.card.spellability.SpellAbility) */ @Override - public void setReplacingObjects(Map runParams, SpellAbility sa) { - sa.setReplacingObject("Card", runParams.get("Affected")); + public void setReplacingObjects(Map runParams, SpellAbility sa) { + sa.setReplacingObject(AbilityKey.Card, runParams.get(AbilityKey.Affected)); } } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java b/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java index 0c23c297da5..a3989336f0a 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementEffect.java @@ -19,6 +19,7 @@ package forge.game.replacement; import forge.game.Game; import forge.game.TriggerReplacementBase; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.phase.PhaseType; @@ -121,7 +122,7 @@ public abstract class ReplacementEffect extends TriggerReplacementBase { * the run params * @return true, if successful */ - public abstract boolean canReplace(final Map runParams); + public abstract boolean canReplace (final Map runParams); /** *

@@ -198,13 +199,11 @@ public abstract class ReplacementEffect extends TriggerReplacementBase { /** * Sets the replacing objects. - * - * @param runParams + * @param runParams * the run params * @param spellAbility - * the SpellAbility */ - public void setReplacingObjects(final Map runParams, final SpellAbility spellAbility) { + public void setReplacingObjects(final Map runParams, final SpellAbility spellAbility) { // Should be overridden by replacers that need it. } diff --git a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java index 04f1e61cbda..cba94673457 100644 --- a/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java +++ b/forge-game/src/main/java/forge/game/replacement/ReplacementHandler.java @@ -21,10 +21,14 @@ import forge.card.MagicColor; import forge.game.Game; import forge.game.GameLogEntryType; import forge.game.ability.AbilityFactory; +import forge.game.ability.AbilityKey; import forge.game.ability.AbilityUtils; import forge.game.card.Card; import forge.game.card.CardCollection; +import forge.game.card.CardTraitChanges; import forge.game.card.CardUtil; +import forge.game.keyword.KeywordInterface; +import forge.game.keyword.KeywordsChange; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.zone.Zone; @@ -42,6 +46,8 @@ import java.util.*; public class ReplacementHandler { private final Game game; + + private Set hasRun = Sets.newHashSet(); /** * ReplacementHandler. * @param gameState @@ -52,57 +58,82 @@ public class ReplacementHandler { //private final List tmpEffects = new ArrayList(); - public ReplacementResult run(ReplacementType event, final Map runParams) { - final Object affected = runParams.get("Affected"); - Player decider = null; - - // Figure out who decides which of multiple replacements to apply - // as well as whether or not to apply optional replacements. - if (affected instanceof Player) { - decider = (Player) affected; - } else { - decider = ((Card) affected).getController(); - } - - // try out all layer - for (ReplacementLayer layer : ReplacementLayer.values()) { - ReplacementResult res = run(event, runParams, layer, decider); - if (res != ReplacementResult.NotReplaced) { - return res; - } - } - - return ReplacementResult.NotReplaced; - - } - - public List getReplacementList(final ReplacementType event, final Map runParams, final ReplacementLayer layer) { + public List getReplacementList(final ReplacementType event, final Map runParams, final ReplacementLayer layer) { final CardCollection preList = new CardCollection(); boolean checkAgain = false; Card affectedLKI = null; Card affectedCard = null; - if (ReplacementType.Moved.equals(event) && ZoneType.Battlefield.equals(runParams.get("Destination"))) { + if (ReplacementType.Moved.equals(event) && ZoneType.Battlefield.equals(runParams.get(AbilityKey.Destination))) { // if it was caused by an replacement effect, use the already calculated RE list // otherwise the RIOT card would cause a StackError - SpellAbility cause = (SpellAbility) runParams.get("Cause"); + SpellAbility cause = (SpellAbility) runParams.get(AbilityKey.Cause); if (cause != null && cause.isReplacementAbility()) { final ReplacementEffect re = cause.getReplacementEffect(); // only return for same layer if (ReplacementType.Moved.equals(re.getMode()) && layer.equals(re.getLayer())) { - return re.getOtherChoices(); + if (!re.getOtherChoices().isEmpty()) + return re.getOtherChoices(); } } // Rule 614.12 Enter the Battlefield Replacement Effects look at what the card would be on the battlefield - affectedCard = (Card) runParams.get("Affected"); + affectedCard = (Card) runParams.get(AbilityKey.Affected); affectedLKI = CardUtil.getLKICopy(affectedCard); affectedLKI.setLastKnownZone(affectedCard.getController().getZone(ZoneType.Battlefield)); preList.add(affectedLKI); game.getAction().checkStaticAbilities(false, Sets.newHashSet(affectedLKI), preList); checkAgain = true; - runParams.put("Affected", affectedLKI); + + // need to check if Intrinsic has run + for (ReplacementEffect re : affectedLKI.getReplacementEffects()) { + if (re.isIntrinsic() && this.hasRun.contains(re)) { + re.setHasRun(true); + } + } + + // need to check non Intrinsic + for (Map.Entry e : affectedLKI.getChangedCardTraits().entrySet()) { + boolean hasRunRE = false; + String skey = String.valueOf(e.getKey()); + + for (ReplacementEffect re : this.hasRun) { + if (!re.isIntrinsic() && skey.equals(re.getSVar("_ReplacedTimestamp"))) { + hasRunRE = true; + break; + } + } + + for (ReplacementEffect re : e.getValue().getReplacements()) { + re.setSVar("_ReplacedTimestamp", skey); + if (hasRunRE) { + re.setHasRun(true); + } + } + } + for (Map.Entry e : affectedLKI.getChangedCardKeywords().entrySet()) { + boolean hasRunRE = false; + String skey = String.valueOf(e.getKey()); + + for (ReplacementEffect re : this.hasRun) { + if (!re.isIntrinsic() && skey.equals(re.getSVar("_ReplacedTimestamp"))) { + hasRunRE = true; + break; + } + } + + for (KeywordInterface k : e.getValue().getKeywords()) { + for (ReplacementEffect re : k.getReplacements()) { + re.setSVar("_ReplacedTimestamp", skey); + if (hasRunRE) { + re.setHasRun(true); + } + } + } + } + + runParams.put(AbilityKey.Affected, affectedLKI); } final List possibleReplacers = Lists.newArrayList(); @@ -157,7 +188,7 @@ public class ReplacementHandler { for (final ReplacementEffect re : affectedLKI.getReplacementEffects()) { re.setHostCard(affectedCard); } - runParams.put("Affected", affectedCard); + runParams.put(AbilityKey.Affected, affectedCard); } game.getAction().checkStaticAbilities(false); } @@ -171,20 +202,45 @@ public class ReplacementHandler { * * @param runParams * the run params,same as for triggers. - * @return true if the event was replaced. + * @return ReplacementResult, an enum that represents what happened to the replacement effect. */ - public ReplacementResult run(final ReplacementType event, final Map runParams, final ReplacementLayer layer, final Player decider) { + public ReplacementResult run(ReplacementType event, final Map runParams) { + final Object affected = runParams.get(AbilityKey.Affected); + Player decider = null; + + // Figure out who decides which of multiple replacements to apply + // as well as whether or not to apply optional replacements. + if (affected instanceof Player) { + decider = (Player) affected; + } else { + decider = ((Card) affected).getController(); + } + + // try out all layer + for (ReplacementLayer layer : ReplacementLayer.values()) { + ReplacementResult res = run(event, runParams, layer, decider); + if (res != ReplacementResult.NotReplaced) { + return res; + } + } + + return ReplacementResult.NotReplaced; + + } + + private ReplacementResult run(final ReplacementType event, final Map runParams, final ReplacementLayer layer, final Player decider) { final List possibleReplacers = getReplacementList(event, runParams, layer); if (possibleReplacers.isEmpty()) { return ReplacementResult.NotReplaced; } - ReplacementEffect chosenRE = decider.getController().chooseSingleReplacementEffect("Choose a replacement effect to apply first.", possibleReplacers, runParams); + ReplacementEffect chosenRE = decider.getController().chooseSingleReplacementEffect("Choose a replacement effect to apply first.", possibleReplacers); possibleReplacers.remove(chosenRE); chosenRE.setHasRun(true); + hasRun.add(chosenRE); chosenRE.setOtherChoices(possibleReplacers); ReplacementResult res = executeReplacement(runParams, chosenRE, decider, game); if (res == ReplacementResult.NotReplaced) { @@ -192,10 +248,12 @@ public class ReplacementHandler { res = run(event, runParams); } chosenRE.setHasRun(false); + hasRun.remove(chosenRE); chosenRE.setOtherChoices(null); return res; } chosenRE.setHasRun(false); + hasRun.remove(chosenRE); chosenRE.setOtherChoices(null); String message = chosenRE.toString(); if ( !StringUtils.isEmpty(message)) @@ -213,7 +271,7 @@ public class ReplacementHandler { * @param replacementEffect * the replacement effect to run */ - private ReplacementResult executeReplacement(final Map runParams, + private ReplacementResult executeReplacement(final Map runParams, final ReplacementEffect replacementEffect, final Player decider, final Game game) { final Map mapParams = replacementEffect.getMapParams(); @@ -237,7 +295,7 @@ public class ReplacementHandler { do { replacementEffect.setReplacingObjects(runParams, tailend); //set original Params to update them later - tailend.setReplacingObject("OriginalParams", runParams); + tailend.setReplacingObject(AbilityKey.OriginalParams, runParams); tailend = tailend.getSubAbility(); } while(tailend != null); @@ -248,7 +306,7 @@ public class ReplacementHandler { do { replacementEffect.setReplacingObjects(runParams, tailend); //set original Params to update them later - tailend.setReplacingObject("OriginalParams", runParams); + tailend.setReplacingObject(AbilityKey.OriginalParams, runParams); tailend = tailend.getSubAbility(); } while(tailend != null); } @@ -275,7 +333,7 @@ public class ReplacementHandler { Card cardForUi = host.getCardForUi(); String effectDesc = TextUtil.fastReplace(replacementEffect.toString(), "CARDNAME", cardForUi.getName()); final String question = replacementEffect instanceof ReplaceDiscard - ? TextUtil.concatWithSpace("Apply replacement effect of", cardForUi.toString(), "to", TextUtil.addSuffix(runParams.get("Card").toString(),"?\r\n"), TextUtil.enclosedParen(effectDesc)) + ? TextUtil.concatWithSpace("Apply replacement effect of", cardForUi.toString(), "to", TextUtil.addSuffix(runParams.get(AbilityKey.Card).toString(),"?\r\n"), TextUtil.enclosedParen(effectDesc)) : TextUtil.concatWithSpace("Apply replacement effect of", TextUtil.addSuffix(cardForUi.toString(),"?\r\n"), TextUtil.enclosedParen(effectDesc)); boolean confirmed = optDecider.getController().confirmReplacementEffect(replacementEffect, effectSA, question); if (!confirmed) { @@ -292,9 +350,9 @@ public class ReplacementHandler { Player player = host.getController(); if (mapParams.containsKey("ManaReplacement")) { - final SpellAbility manaAb = (SpellAbility) runParams.get("AbilityMana"); - final Player player1 = (Player) runParams.get("Player"); - final String rep = (String) runParams.get("Mana"); + final SpellAbility manaAb = (SpellAbility) runParams.get(AbilityKey.AbilityMana); + final Player player1 = (Player) runParams.get(AbilityKey.Player); + final String rep = (String) runParams.get(AbilityKey.Mana); // Replaced mana type final Card repHost = host; String repType = repHost.getSVar(mapParams.get("ManaReplacement")); @@ -307,8 +365,8 @@ public class ReplacementHandler { player.getController().playSpellAbilityNoStack(effectSA, true); // if the spellability is a replace effect then its some new logic // if ReplacementResult is set in run params use that instead - if (runParams.containsKey("ReplacementResult")) { - return (ReplacementResult) runParams.get("ReplacementResult"); + if (runParams.containsKey(AbilityKey.ReplacementResult)) { + return (ReplacementResult) runParams.get(AbilityKey.ReplacementResult); } } diff --git a/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java b/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java index 8d1cd6db131..9dfae9446b8 100644 --- a/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java +++ b/forge-game/src/main/java/forge/game/spellability/AbilityManaPart.java @@ -128,11 +128,10 @@ public class AbilityManaPart implements java.io.Serializable { final Card source = this.getSourceCard(); final ManaPool manaPool = player.getManaPool(); String afterReplace = applyManaReplacement(sa, produced); - final Map repParams = Maps.newHashMap(); - repParams.put("Mana", afterReplace); - repParams.put("Affected", source); - repParams.put("Player", player); - repParams.put("AbilityMana", sa); + final Map repParams = AbilityKey.mapFromAffected(source); + repParams.put(AbilityKey.Mana, afterReplace); + repParams.put(AbilityKey.Player, player); + repParams.put(AbilityKey.AbilityMana, sa); if (player.getGame().getReplacementHandler().run(ReplacementType.ProduceMana, repParams) != ReplacementResult.NotReplaced) { return; } diff --git a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java index e27af7b79bb..55760357af4 100644 --- a/forge-game/src/main/java/forge/game/spellability/SpellAbility.java +++ b/forge-game/src/main/java/forge/game/spellability/SpellAbility.java @@ -143,7 +143,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit private EnumMap triggeringObjects = AbilityKey.newMap(); - private HashMap replacingObjects = Maps.newHashMap(); + private EnumMap replacingObjects = AbilityKey.newMap(); private List chosenList = null; private CardCollection tappedForConvoke = new CardCollection(); @@ -593,17 +593,15 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit triggerRemembered = Lists.newArrayList(); } - public HashMap getReplacingObjects() { + public Map getReplacingObjects() { return replacingObjects; } - public boolean hasReplacingObject(final String type) { - return replacingObjects.containsKey(type); - } - public Object getReplacingObject(final String type) { + public Object getReplacingObject(final AbilityKey type) { final Object res = replacingObjects.get(type); return res; } - public void setReplacingObject(final String type, final Object o) { + + public void setReplacingObject(final AbilityKey type, final Object o) { replacingObjects.put(type, o); } diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java index bad27de11c1..5b8cc7018a3 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbility.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbility.java @@ -391,6 +391,23 @@ public class StaticAbility extends CardTraitBase implements IIdentifiable, Clone return false; } + public final boolean applyAbility(final String mode, final Player player, final SpellAbility spellAbility) { + // don't apply the ability if it hasn't got the right mode + if (!getParam("Mode").equals(mode)) { + return false; + } + + if (this.isSuppressed() || !this.checkConditions()) { + return false; + } + + if (mode.equals("CantTarget")) { + return StaticAbilityCantTarget.applyCantTargetAbility(this, player, spellAbility); + } + + return false; + } + public final boolean applyAbility(String mode, Card card, CounterType type) { // don't apply the ability if it hasn't got the right mode diff --git a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java index 91ab7dc10bd..00243f7e4c9 100644 --- a/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java +++ b/forge-game/src/main/java/forge/game/staticability/StaticAbilityCantTarget.java @@ -6,12 +6,12 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -22,8 +22,6 @@ import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; -import java.util.Map; - /** * The Class StaticAbilityCantTarget. */ @@ -31,8 +29,8 @@ public class StaticAbilityCantTarget { /** * Apply can't target ability. - * - * @param staticAbility + * + * @param st * the static ability * @param card * the card @@ -40,16 +38,19 @@ public class StaticAbilityCantTarget { * the spell/ability * @return true, if successful */ - public static boolean applyCantTargetAbility(final StaticAbility staticAbility, final Card card, + public static boolean applyCantTargetAbility(final StaticAbility st, final Card card, final SpellAbility spellAbility) { - final Map params = staticAbility.getMapParams(); - final Card hostCard = staticAbility.getHostCard(); + final Card hostCard = st.getHostCard(); final Card source = spellAbility.getHostCard(); final Player activator = spellAbility.getActivatingPlayer(); - if (params.containsKey("AffectedZone")) { + if (st.hasParam("ValidPlayer")) { + return false; + } + + if (st.hasParam("AffectedZone")) { boolean inZone = false; - for (final ZoneType zt : ZoneType.listValueOf(params.get("AffectedZone"))) { + for (final ZoneType zt : ZoneType.listValueOf(st.getParam("AffectedZone"))) { if (card.isInZone(zt)) { inZone = true; break; @@ -65,38 +66,14 @@ public class StaticAbilityCantTarget { } } - if (params.containsKey("ValidSA") - && !spellAbility.isValid(params.get("ValidSA").split(","), hostCard.getController(), hostCard, spellAbility)) { + + if (st.hasParam("ValidCard") + && !card.isValid(st.getParam("ValidCard").split(","), hostCard.getController(), hostCard, null)) { return false; } - if (params.containsKey("ValidCard") - && !card.isValid(params.get("ValidCard").split(","), hostCard.getController(), hostCard, null)) { - return false; - } - if (params.containsKey("ValidSource") - && !source.isValid(params.get("ValidSource").split(","), hostCard.getController(), hostCard, null)) { - return false; - } - - if (params.containsKey("Activator") && (activator != null) - && !activator.isValid(params.get("Activator"), hostCard.getController(), hostCard, spellAbility)) { - return false; - } - - if (spellAbility.getParam("ValidTgts")!=null && - (params.containsKey("SourceCanOnlyTarget") - && (!spellAbility.getParam("ValidTgts").contains(params.get("SourceCanOnlyTarget")) - || spellAbility.getParam("ValidTgts").contains(",")) - || spellAbility.getParam("ValidTgts").contains("non" + params.get("SourceCanOnlyTarget") - ) - ) - ){ - return false; - } - - if (params.containsKey("Hexproof") && (activator != null)) { + if (st.hasParam("Hexproof") && (activator != null)) { for (String k : activator.getKeywords()) { if (k.startsWith("IgnoreHexproof")) { String[] m = k.split(":"); @@ -106,8 +83,81 @@ public class StaticAbilityCantTarget { } } } + if (st.hasParam("Shroud") && (activator != null)) { + for (String k : activator.getKeywords()) { + if (k.startsWith("IgnoreShroud")) { + String[] m = k.split(":"); + if (card.isValid(m[1].split(","), activator, source, spellAbility)) { + return false; + } + } + } + } + + return common(st, spellAbility); + } + + public static boolean applyCantTargetAbility(final StaticAbility st, final Player player, + final SpellAbility spellAbility) { + final Card hostCard = st.getHostCard(); + final Card source = spellAbility.getHostCard(); + final Player activator = spellAbility.getActivatingPlayer(); + + if (st.hasParam("ValidCard") || st.hasParam("AffectedZone")) { + return false; + } + + if (st.hasParam("ValidPlayer") + && !player.isValid(st.getParam("ValidPlayer").split(","), hostCard.getController(), hostCard, null)) { + return false; + } + + + if (st.hasParam("Hexproof") && (activator != null)) { + for (String k : activator.getKeywords()) { + if (k.startsWith("IgnoreHexproof")) { + String[] m = k.split(":"); + if (player.isValid(m[1].split(","), activator, source, spellAbility)) { + return false; + } + } + } + } + + return common(st, spellAbility); + } + + protected static boolean common(final StaticAbility st, final SpellAbility spellAbility) { + final Card hostCard = st.getHostCard(); + final Card source = spellAbility.getHostCard(); + final Player activator = spellAbility.getActivatingPlayer(); + + if (st.hasParam("ValidSA") + && !spellAbility.isValid(st.getParam("ValidSA").split(","), hostCard.getController(), hostCard, spellAbility)) { + return false; + } + + if (st.hasParam("ValidSource") + && !source.isValid(st.getParam("ValidSource").split(","), hostCard.getController(), hostCard, null)) { + return false; + } + + if (st.hasParam("Activator") && (activator != null) + && !activator.isValid(st.getParam("Activator"), hostCard.getController(), hostCard, spellAbility)) { + return false; + } + + if (spellAbility.hasParam("ValidTgts") && + (st.hasParam("SourceCanOnlyTarget") + && (!spellAbility.getParam("ValidTgts").contains(st.getParam("SourceCanOnlyTarget")) + || spellAbility.getParam("ValidTgts").contains(",")) + || spellAbility.getParam("ValidTgts").contains("non" + st.getParam("SourceCanOnlyTarget") + ) + ) + ){ + return false; + } return true; } - } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerAdapt.java b/forge-game/src/main/java/forge/game/trigger/TriggerAdapt.java index c25347d75e4..81b8b35f765 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerAdapt.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerAdapt.java @@ -22,6 +22,7 @@ import java.util.Map; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; /** *

@@ -71,7 +72,7 @@ public class TriggerAdapt extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Adapt: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblAdapt")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerAttached.java b/forge-game/src/main/java/forge/game/trigger/TriggerAttached.java index 49f264f48a6..08b18dcc290 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerAttached.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerAttached.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -83,7 +84,7 @@ public class TriggerAttached extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Attachee: ").append(sa.getTriggeringObject(AbilityKey.Target)); + sb.append(Localizer.getInstance().getMessage("lblAttachee")).append(": ").append(sa.getTriggeringObject(AbilityKey.Target)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerAttackerBlocked.java b/forge-game/src/main/java/forge/game/trigger/TriggerAttackerBlocked.java index 4c00df15b1f..b77d0939526 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerAttackerBlocked.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerAttackerBlocked.java @@ -23,6 +23,7 @@ import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.card.CardLists; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; /** *

@@ -99,8 +100,8 @@ public class TriggerAttackerBlocked extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Attacker: ").append(sa.getTriggeringObject(AbilityKey.Attacker)).append(", "); - sb.append("Number Blockers: ").append(sa.getTriggeringObject(AbilityKey.NumBlockers)); + sb.append(Localizer.getInstance().getMessage("lblAttacker")).append(": ").append(sa.getTriggeringObject(AbilityKey.Attacker)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblNumberBlockers")).append(": ").append(sa.getTriggeringObject(AbilityKey.NumBlockers)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerAttackerBlockedByCreature.java b/forge-game/src/main/java/forge/game/trigger/TriggerAttackerBlockedByCreature.java index 3b77fa06423..b8dad166edc 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerAttackerBlockedByCreature.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerAttackerBlockedByCreature.java @@ -22,6 +22,7 @@ import java.util.Map; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; /** *

@@ -95,8 +96,8 @@ public class TriggerAttackerBlockedByCreature extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Attacker: ").append(sa.getTriggeringObject(AbilityKey.Attacker)).append(", "); - sb.append("Blocker: ").append(sa.getTriggeringObject(AbilityKey.Blocker)); + sb.append(Localizer.getInstance().getMessage("lblAttacker")).append(": ").append(sa.getTriggeringObject(AbilityKey.Attacker)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblBlocker")).append(": ").append(sa.getTriggeringObject(AbilityKey.Blocker)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerAttackerUnblocked.java b/forge-game/src/main/java/forge/game/trigger/TriggerAttackerUnblocked.java index 4236f7d8d36..9e201617e39 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerAttackerUnblocked.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerAttackerUnblocked.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -77,7 +78,7 @@ public class TriggerAttackerUnblocked extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Attacker: ").append(sa.getTriggeringObject(AbilityKey.Attacker)); + sb.append(Localizer.getInstance().getMessage("lblAttacker")).append(": ").append(sa.getTriggeringObject(AbilityKey.Attacker)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerAttackerUnblockedOnce.java b/forge-game/src/main/java/forge/game/trigger/TriggerAttackerUnblockedOnce.java index edece275c05..b17acd00911 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerAttackerUnblockedOnce.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerAttackerUnblockedOnce.java @@ -21,6 +21,7 @@ import forge.game.GameEntity; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.List; import java.util.Map; @@ -92,8 +93,8 @@ public class TriggerAttackerUnblockedOnce extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("AttackingPlayer: ").append(sa.getTriggeringObject(AbilityKey.AttackingPlayer)); - sb.append("Defenders: ").append(sa.getTriggeringObject(AbilityKey.Defenders)); + sb.append(Localizer.getInstance().getMessage("lblAttackingPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.AttackingPlayer)); + sb.append(Localizer.getInstance().getMessage("lblDefenders")).append(": ").append(sa.getTriggeringObject(AbilityKey.Defenders)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerAttackersDeclared.java b/forge-game/src/main/java/forge/game/trigger/TriggerAttackersDeclared.java index 5c4cdf1f6cb..b50ee54a75f 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerAttackersDeclared.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerAttackersDeclared.java @@ -21,6 +21,7 @@ import forge.game.GameEntity; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.List; import java.util.Map; @@ -94,7 +95,7 @@ public class TriggerAttackersDeclared extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Number Attackers: ").append(sa.getTriggeringObject(AbilityKey.Attackers)); + sb.append(Localizer.getInstance().getMessage("lblNumberAttackers")).append(": ").append(sa.getTriggeringObject(AbilityKey.Attackers)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerAttacks.java b/forge-game/src/main/java/forge/game/trigger/TriggerAttacks.java index 20612924991..5634b1f928f 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerAttacks.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerAttacks.java @@ -22,6 +22,7 @@ import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.player.Player; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.List; import java.util.Map; @@ -139,7 +140,7 @@ public class TriggerAttacks extends Trigger { public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Attacker: ").append(sa.getTriggeringObject(AbilityKey.Attacker)); + sb.append(Localizer.getInstance().getMessage("lblAttacker")).append(": ").append(sa.getTriggeringObject(AbilityKey.Attacker)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerBecomeMonarch.java b/forge-game/src/main/java/forge/game/trigger/TriggerBecomeMonarch.java index 8a631667503..85196ffcb2a 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerBecomeMonarch.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerBecomeMonarch.java @@ -6,6 +6,7 @@ import forge.game.Game; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; public class TriggerBecomeMonarch extends Trigger { @@ -42,7 +43,7 @@ public class TriggerBecomeMonarch extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Player: ").append(sa.getTriggeringObject(AbilityKey.Player)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)).append(", "); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerBecomeMonstrous.java b/forge-game/src/main/java/forge/game/trigger/TriggerBecomeMonstrous.java index 0ee053f0c0f..172d04e2468 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerBecomeMonstrous.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerBecomeMonstrous.java @@ -22,6 +22,7 @@ import java.util.Map; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; /** *

@@ -72,7 +73,7 @@ public class TriggerBecomeMonstrous extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Monstrous: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblMonstrous")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerBecomeRenowned.java b/forge-game/src/main/java/forge/game/trigger/TriggerBecomeRenowned.java index 4a7f4fcbde4..fc4c62064cd 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerBecomeRenowned.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerBecomeRenowned.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -72,7 +73,7 @@ public class TriggerBecomeRenowned extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Renowned: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblRenowned")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerBecomesTarget.java b/forge-game/src/main/java/forge/game/trigger/TriggerBecomesTarget.java index bffe201de96..cb56d395650 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerBecomesTarget.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerBecomesTarget.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -96,8 +97,8 @@ public class TriggerBecomesTarget extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Source: ").append(((SpellAbility) sa.getTriggeringObject(AbilityKey.SourceSA)).getHostCard()).append(", "); - sb.append("Target: ").append(sa.getTriggeringObject(AbilityKey.Target)); + sb.append(Localizer.getInstance().getMessage("lblSource")).append(": ").append(((SpellAbility) sa.getTriggeringObject(AbilityKey.SourceSA)).getHostCard()).append(", "); + sb.append(Localizer.getInstance().getMessage("lblTarget")).append(": ").append(sa.getTriggeringObject(AbilityKey.Target)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerBecomesTargetOnce.java b/forge-game/src/main/java/forge/game/trigger/TriggerBecomesTargetOnce.java index 7e897aaf219..5c929279e64 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerBecomesTargetOnce.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerBecomesTargetOnce.java @@ -21,6 +21,7 @@ import forge.game.GameObject; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.List; import java.util.Map; @@ -88,8 +89,8 @@ public class TriggerBecomesTargetOnce extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Source: ").append(((SpellAbility) sa.getTriggeringObject(AbilityKey.SourceSA)).getHostCard()).append(", "); - sb.append("Targets: ").append(sa.getTriggeringObject(AbilityKey.Targets)); + sb.append(Localizer.getInstance().getMessage("lblSource")).append(": ").append(((SpellAbility) sa.getTriggeringObject(AbilityKey.SourceSA)).getHostCard()).append(", "); + sb.append(Localizer.getInstance().getMessage("lblTargets")).append(": ").append(sa.getTriggeringObject(AbilityKey.Targets)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerBlockersDeclared.java b/forge-game/src/main/java/forge/game/trigger/TriggerBlockersDeclared.java index e3beece4401..9a6ebdef762 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerBlockersDeclared.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerBlockersDeclared.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -59,7 +60,7 @@ public class TriggerBlockersDeclared extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Blockers: ").append(sa.getTriggeringObject(AbilityKey.Blockers)); + sb.append(Localizer.getInstance().getMessage("lblBlockers")).append(": ").append(sa.getTriggeringObject(AbilityKey.Blockers)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerBlocks.java b/forge-game/src/main/java/forge/game/trigger/TriggerBlocks.java index 88c4f98c98d..4c7d72c3b2e 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerBlocks.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerBlocks.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -96,7 +97,7 @@ public class TriggerBlocks extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Blocker: ").append(sa.getTriggeringObject(AbilityKey.Blocker)); + sb.append(Localizer.getInstance().getMessage("lblBlocker")).append(": ").append(sa.getTriggeringObject(AbilityKey.Blocker)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerChampioned.java b/forge-game/src/main/java/forge/game/trigger/TriggerChampioned.java index 0d8957a2cfc..53542cb8a5c 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerChampioned.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerChampioned.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -81,7 +82,7 @@ public class TriggerChampioned extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Championed: ").append(sa.getTriggeringObject(AbilityKey.Championed)); + sb.append(Localizer.getInstance().getMessage("lblChampioned")).append(": ").append(sa.getTriggeringObject(AbilityKey.Championed)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerChangesController.java b/forge-game/src/main/java/forge/game/trigger/TriggerChangesController.java index 44a8b0b4470..610da7e7dd2 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerChangesController.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerChangesController.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -80,7 +81,7 @@ public class TriggerChangesController extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Changed Controller: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblChangedController")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerChangesZone.java b/forge-game/src/main/java/forge/game/trigger/TriggerChangesZone.java index 145844de49d..3371d03c786 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerChangesZone.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerChangesZone.java @@ -30,6 +30,7 @@ import forge.util.Expressions; import java.util.Map; import java.util.Set; +import forge.util.Localizer; import org.apache.commons.lang3.ArrayUtils; import com.google.common.collect.Sets; @@ -219,7 +220,7 @@ public class TriggerChangesZone extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Zone Changer: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblZoneChanger")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerChangesZoneAll.java b/forge-game/src/main/java/forge/game/trigger/TriggerChangesZoneAll.java index f84c2e245d3..6d618f3d98a 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerChangesZoneAll.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerChangesZoneAll.java @@ -7,6 +7,7 @@ import forge.game.ability.AbilityKey; import forge.game.card.*; import forge.game.spellability.SpellAbility; import forge.game.zone.ZoneType; +import forge.util.Localizer; public class TriggerChangesZoneAll extends Trigger { @@ -34,7 +35,7 @@ public class TriggerChangesZoneAll extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Amount: ").append(sa.getTriggeringObject(AbilityKey.Amount)); + sb.append(Localizer.getInstance().getMessage("lblAmount")).append(": ").append(sa.getTriggeringObject(AbilityKey.Amount)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerCounterAdded.java b/forge-game/src/main/java/forge/game/trigger/TriggerCounterAdded.java index 5b305ab6e5e..5cc8c980b88 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerCounterAdded.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerCounterAdded.java @@ -25,6 +25,7 @@ import forge.game.card.CounterType; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.util.Expressions; +import forge.util.Localizer; /** *

@@ -127,7 +128,7 @@ public class TriggerCounterAdded extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Added once: "); + sb.append(Localizer.getInstance().getMessage("lblAddedOnce")).append(": "); if (sa.hasTriggeringObject(AbilityKey.Card)) sb.append(sa.getTriggeringObject(AbilityKey.Card)); if (sa.hasTriggeringObject(AbilityKey.Player)) diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerCounterAddedAll.java b/forge-game/src/main/java/forge/game/trigger/TriggerCounterAddedAll.java index d424c8557f3..e80579ae5ec 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerCounterAddedAll.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerCounterAddedAll.java @@ -9,6 +9,7 @@ import forge.game.GameEntityCounterTable; import forge.game.ability.AbilityKey; import forge.game.card.*; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; public class TriggerCounterAddedAll extends Trigger { @@ -41,7 +42,7 @@ public class TriggerCounterAddedAll extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Amount: ").append(sa.getTriggeringObject(AbilityKey.Amount)); + sb.append(Localizer.getInstance().getMessage("lblAmount")).append(": ").append(sa.getTriggeringObject(AbilityKey.Amount)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerCounterAddedOnce.java b/forge-game/src/main/java/forge/game/trigger/TriggerCounterAddedOnce.java index 0244c2f6785..8d349470a72 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerCounterAddedOnce.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerCounterAddedOnce.java @@ -24,6 +24,7 @@ import forge.game.card.Card; import forge.game.card.CounterType; import forge.game.player.Player; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; /** *

@@ -114,13 +115,13 @@ public class TriggerCounterAddedOnce extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Added once: "); + sb.append(Localizer.getInstance().getMessage("lblAddedOnce")).append(": "); if (sa.hasTriggeringObject(AbilityKey.Card)) sb.append(sa.getTriggeringObject(AbilityKey.Card)); if (sa.hasTriggeringObject(AbilityKey.Player)) sb.append(sa.getTriggeringObject(AbilityKey.Player)); - sb.append(" Amount: ").append(sa.getTriggeringObject(AbilityKey.Amount)); + sb.append(" ").append(Localizer.getInstance().getMessage("lblAmount")).append(": ").append(sa.getTriggeringObject(AbilityKey.Amount)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerCounterRemoved.java b/forge-game/src/main/java/forge/game/trigger/TriggerCounterRemoved.java index 5500950474c..a4c7209bfb9 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerCounterRemoved.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerCounterRemoved.java @@ -21,6 +21,7 @@ import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.card.CounterType; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -92,7 +93,7 @@ public class TriggerCounterRemoved extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Removed from: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblRemovedFrom")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerCounterRemovedOnce.java b/forge-game/src/main/java/forge/game/trigger/TriggerCounterRemovedOnce.java index 6cd69c88555..028751ebb00 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerCounterRemovedOnce.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerCounterRemovedOnce.java @@ -21,6 +21,7 @@ import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.card.CounterType; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -84,8 +85,8 @@ public class TriggerCounterRemovedOnce extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Removed from: ").append(sa.getTriggeringObject(AbilityKey.Card)); - sb.append(" Amount: ").append(sa.getTriggeringObject(AbilityKey.Amount)); + sb.append(Localizer.getInstance().getMessage("lblRemovedFrom")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(" ").append(Localizer.getInstance().getMessage("lblAmount")).append(": ").append(sa.getTriggeringObject(AbilityKey.Amount)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerCountered.java b/forge-game/src/main/java/forge/game/trigger/TriggerCountered.java index 0b79ca87704..db4bb45b006 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerCountered.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerCountered.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -108,8 +109,8 @@ public class TriggerCountered extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Countered: ").append(sa.getTriggeringObject(AbilityKey.Card)).append(", "); - sb.append("Cause: ").append(sa.getTriggeringObject(AbilityKey.Cause)); + sb.append(Localizer.getInstance().getMessage("lblCountered")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblCause")).append(": ").append(sa.getTriggeringObject(AbilityKey.Cause)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerCrewed.java b/forge-game/src/main/java/forge/game/trigger/TriggerCrewed.java index 2ad77cbd842..2c93e2a6813 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerCrewed.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerCrewed.java @@ -4,6 +4,7 @@ import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.card.CardCollection; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -45,9 +46,9 @@ public class TriggerCrewed extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Vehicle: ").append(sa.getTriggeringObject(AbilityKey.Vehicle)); + sb.append(Localizer.getInstance().getMessage("lblVehicle")).append(": ").append(sa.getTriggeringObject(AbilityKey.Vehicle)); sb.append(" "); - sb.append("Crew: ").append(sa.getTriggeringObject(AbilityKey.Crew)); + sb.append(Localizer.getInstance().getMessage("lblCrew")).append(": ").append(sa.getTriggeringObject(AbilityKey.Crew)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerCycled.java b/forge-game/src/main/java/forge/game/trigger/TriggerCycled.java index 32416714316..5da329a6360 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerCycled.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerCycled.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -58,7 +59,7 @@ public class TriggerCycled extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Cycled: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblCycled")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerDamageDealtOnce.java b/forge-game/src/main/java/forge/game/trigger/TriggerDamageDealtOnce.java index 5c6aafa1da8..be92e7a2929 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerDamageDealtOnce.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerDamageDealtOnce.java @@ -22,6 +22,7 @@ import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; import forge.util.Expressions; +import forge.util.Localizer; import java.util.Map; import java.util.Set; @@ -116,9 +117,9 @@ public class TriggerDamageDealtOnce extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Damage Source: ").append(sa.getTriggeringObject(AbilityKey.Source)).append(", "); - sb.append("Damaged: ").append(sa.getTriggeringObject(AbilityKey.Targets)).append(", "); - sb.append("Amount: ").append(sa.getTriggeringObject(AbilityKey.DamageAmount)); + sb.append(Localizer.getInstance().getMessage("lblDamageSource")).append(": ").append(sa.getTriggeringObject(AbilityKey.Source)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblDamaged")).append(": ").append(sa.getTriggeringObject(AbilityKey.Targets)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblAmount")).append(": ").append(sa.getTriggeringObject(AbilityKey.DamageAmount)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerDamageDone.java b/forge-game/src/main/java/forge/game/trigger/TriggerDamageDone.java index 8ec27bb576e..0a41c3b53b4 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerDamageDone.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerDamageDone.java @@ -23,6 +23,7 @@ import forge.game.card.CardUtil; import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbilityStackInstance; import forge.util.Expressions; +import forge.util.Localizer; import java.util.Map; @@ -135,9 +136,9 @@ public class TriggerDamageDone extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Damage Source: ").append(sa.getTriggeringObject(AbilityKey.Source)).append(", "); - sb.append("Damaged: ").append(sa.getTriggeringObject(AbilityKey.Target)).append(", "); - sb.append("Amount: ").append(sa.getTriggeringObject(AbilityKey.DamageAmount)); + sb.append(Localizer.getInstance().getMessage("lblDamageSource")).append(": ").append(sa.getTriggeringObject(AbilityKey.Source)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblDamaged")).append(": ").append(sa.getTriggeringObject(AbilityKey.Target)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblAmount")).append(": ").append(sa.getTriggeringObject(AbilityKey.DamageAmount)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerDamageDoneOnce.java b/forge-game/src/main/java/forge/game/trigger/TriggerDamageDoneOnce.java index 6abc7765a85..96233e6ccf7 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerDamageDoneOnce.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerDamageDoneOnce.java @@ -7,6 +7,7 @@ import forge.game.GameEntity; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; public class TriggerDamageDoneOnce extends Trigger { @@ -67,9 +68,9 @@ public class TriggerDamageDoneOnce extends Trigger { public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); if (sa.getTriggeringObject(AbilityKey.Target) != null) { - sb.append("Damaged: ").append(sa.getTriggeringObject(AbilityKey.Target)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblDamaged")).append(": ").append(sa.getTriggeringObject(AbilityKey.Target)).append(", "); } - sb.append("Amount: ").append(sa.getTriggeringObject(AbilityKey.DamageAmount)); + sb.append(Localizer.getInstance().getMessage("lblAmount")).append(": ").append(sa.getTriggeringObject(AbilityKey.DamageAmount)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerDamagePrevented.java b/forge-game/src/main/java/forge/game/trigger/TriggerDamagePrevented.java index 1c0b739ed7f..d38b52f0675 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerDamagePrevented.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerDamagePrevented.java @@ -22,6 +22,7 @@ import forge.game.card.Card; import forge.game.card.CardUtil; import forge.game.spellability.SpellAbility; import forge.util.Expressions; +import forge.util.Localizer; import java.util.Map; @@ -114,9 +115,9 @@ public class TriggerDamagePrevented extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Damage Source: ").append(sa.getTriggeringObject(AbilityKey.Source)).append(", "); - sb.append("Damage Target: ").append(sa.getTriggeringObject(AbilityKey.Target)).append(", "); - sb.append("Amount: ").append(sa.getTriggeringObject(AbilityKey.DamageAmount)); + sb.append(Localizer.getInstance().getMessage("lblDamageSource")).append(": ").append(sa.getTriggeringObject(AbilityKey.Source)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblDamageTarget")).append(": ").append(sa.getTriggeringObject(AbilityKey.Target)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblAmount")).append(": ").append(sa.getTriggeringObject(AbilityKey.DamageAmount)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerDamagePreventedOnce.java b/forge-game/src/main/java/forge/game/trigger/TriggerDamagePreventedOnce.java index 444978bcbda..72383a0720a 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerDamagePreventedOnce.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerDamagePreventedOnce.java @@ -21,6 +21,7 @@ import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; import forge.util.Expressions; +import forge.util.Localizer; import java.util.Map; @@ -104,8 +105,8 @@ public class TriggerDamagePreventedOnce extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Damage Target: ").append(sa.getTriggeringObject(AbilityKey.Target)).append(", "); - sb.append("Amount: ").append(sa.getTriggeringObject(AbilityKey.DamageAmount)); + sb.append(Localizer.getInstance().getMessage("lblDamageTarget")).append(": ").append(sa.getTriggeringObject(AbilityKey.Target)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblAmount")).append(": ").append(sa.getTriggeringObject(AbilityKey.DamageAmount)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerDestroyed.java b/forge-game/src/main/java/forge/game/trigger/TriggerDestroyed.java index 49e4e26c58f..369c7b7015d 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerDestroyed.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerDestroyed.java @@ -22,6 +22,7 @@ import java.util.Map; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; /** *

@@ -75,8 +76,8 @@ public class TriggerDestroyed extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Destroyed: ").append(sa.getTriggeringObject(AbilityKey.Card)).append(", "); - sb.append("Destroyer: ").append(sa.getTriggeringObject(AbilityKey.Causer)); + sb.append(Localizer.getInstance().getMessage("lblDestroyed")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblDestroyer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Causer)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerDevoured.java b/forge-game/src/main/java/forge/game/trigger/TriggerDevoured.java index 6e27f99f7f8..700e5c83167 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerDevoured.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerDevoured.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -70,7 +71,7 @@ public class TriggerDevoured extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Devoured: ").append(sa.getTriggeringObject(AbilityKey.Devoured)); + sb.append(Localizer.getInstance().getMessage("lblDevoured")).append(": ").append(sa.getTriggeringObject(AbilityKey.Devoured)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerDiscarded.java b/forge-game/src/main/java/forge/game/trigger/TriggerDiscarded.java index 14a181b9510..ef604384410 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerDiscarded.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerDiscarded.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -95,8 +96,8 @@ public class TriggerDiscarded extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Discarded: ").append(sa.getTriggeringObject(AbilityKey.Card)).append(", "); - sb.append("Cause: ").append(sa.getTriggeringObject(AbilityKey.Cause)); + sb.append(Localizer.getInstance().getMessage("lblDiscarded")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblCause")).append(": ").append(sa.getTriggeringObject(AbilityKey.Cause)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerDrawn.java b/forge-game/src/main/java/forge/game/trigger/TriggerDrawn.java index d5f3d06f176..eeb6afaff98 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerDrawn.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerDrawn.java @@ -22,6 +22,7 @@ import forge.game.GameStage; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -88,7 +89,7 @@ public class TriggerDrawn extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Player: ").append(sa.getTriggeringObject(AbilityKey.Player)); + sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerEvolved.java b/forge-game/src/main/java/forge/game/trigger/TriggerEvolved.java index afcf96c0e81..dd8d536257f 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerEvolved.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerEvolved.java @@ -22,6 +22,7 @@ import java.util.Map; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; /** *

@@ -69,7 +70,7 @@ public class TriggerEvolved extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Evolved: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblEvolved")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerExerted.java b/forge-game/src/main/java/forge/game/trigger/TriggerExerted.java index 4cc5d65f7e9..d17a504b2fc 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerExerted.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerExerted.java @@ -3,6 +3,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.HashMap; import java.util.Map; @@ -39,7 +40,7 @@ public class TriggerExerted extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Exerted: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblExerted")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerExiled.java b/forge-game/src/main/java/forge/game/trigger/TriggerExiled.java index 616bf8a4c7f..107126c2098 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerExiled.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerExiled.java @@ -24,6 +24,7 @@ import forge.game.spellability.SpellAbility; import java.util.Map; +import forge.util.Localizer; import org.apache.commons.lang3.ArrayUtils; /** @@ -104,7 +105,7 @@ public class TriggerExiled extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Exiled: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblExiled")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerExploited.java b/forge-game/src/main/java/forge/game/trigger/TriggerExploited.java index 475b4977056..509c1951a7e 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerExploited.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerExploited.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -81,8 +82,8 @@ public class TriggerExploited extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Exploited: ").append(sa.getTriggeringObject(AbilityKey.Exploited)).append(", "); - sb.append("Exploiter: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblExploited")).append(": ").append(sa.getTriggeringObject(AbilityKey.Exploited)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblExploiter")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerExplores.java b/forge-game/src/main/java/forge/game/trigger/TriggerExplores.java index f330ffeb0bb..90edb8c33c1 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerExplores.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerExplores.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -69,7 +70,7 @@ public class TriggerExplores extends Trigger { public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Explorer: ").append(sa.getTriggeringObject(AbilityKey.Explorer)); + sb.append(Localizer.getInstance().getMessage("lblExplorer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Explorer)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerFight.java b/forge-game/src/main/java/forge/game/trigger/TriggerFight.java index 1aa88c5732f..fbf2a764773 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerFight.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerFight.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -72,7 +73,7 @@ public class TriggerFight extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Fighter: ").append(sa.getTriggeringObject(AbilityKey.Fighter)); + sb.append(Localizer.getInstance().getMessage("lblFighter")).append(": ").append(sa.getTriggeringObject(AbilityKey.Fighter)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerFlippedCoin.java b/forge-game/src/main/java/forge/game/trigger/TriggerFlippedCoin.java index 932354b241f..52c8e9798e5 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerFlippedCoin.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerFlippedCoin.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -79,7 +80,7 @@ public class TriggerFlippedCoin extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Player: ").append(sa.getTriggeringObject(AbilityKey.Player)); + sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerInvestigated.java b/forge-game/src/main/java/forge/game/trigger/TriggerInvestigated.java index 155d0aacaa6..0ed0ab95e3d 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerInvestigated.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerInvestigated.java @@ -21,6 +21,7 @@ import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.player.Player; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -53,7 +54,7 @@ public class TriggerInvestigated extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Player: ").append(sa.getTriggeringObject(AbilityKey.Player)); + sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerLandPlayed.java b/forge-game/src/main/java/forge/game/trigger/TriggerLandPlayed.java index ed6ceb30dbc..cb8b32fd694 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerLandPlayed.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerLandPlayed.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -58,7 +59,7 @@ public class TriggerLandPlayed extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Land played: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblLandPlayed")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerLifeGained.java b/forge-game/src/main/java/forge/game/trigger/TriggerLifeGained.java index fe92c615a17..17e934eef05 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerLifeGained.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerLifeGained.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -81,8 +82,8 @@ public class TriggerLifeGained extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Player: ").append(sa.getTriggeringObject(AbilityKey.Player)).append(", "); - sb.append("Gained Amount: ").append(sa.getTriggeringObject(AbilityKey.LifeAmount)); + sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblGainedAmount")).append(": ").append(sa.getTriggeringObject(AbilityKey.LifeAmount)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerLifeLost.java b/forge-game/src/main/java/forge/game/trigger/TriggerLifeLost.java index 6a4376b6d1e..cb42ed21581 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerLifeLost.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerLifeLost.java @@ -22,6 +22,7 @@ import java.util.Map; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; /** *

@@ -78,8 +79,8 @@ public class TriggerLifeLost extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Player: ").append(sa.getTriggeringObject(AbilityKey.Player)).append(", "); - sb.append("Lost Amount: ").append(sa.getTriggeringObject(AbilityKey.LifeAmount)); + sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblLostAmount")).append(": ").append(sa.getTriggeringObject(AbilityKey.LifeAmount)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerLosesGame.java b/forge-game/src/main/java/forge/game/trigger/TriggerLosesGame.java index 2e2d0ebf58e..9b9c3df538f 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerLosesGame.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerLosesGame.java @@ -3,6 +3,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -48,7 +49,7 @@ public class TriggerLosesGame extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Player: ").append(sa.getTriggeringObject(AbilityKey.Player)); + sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerPayCumulativeUpkeep.java b/forge-game/src/main/java/forge/game/trigger/TriggerPayCumulativeUpkeep.java index 2c48b559a73..f3789b45f1b 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerPayCumulativeUpkeep.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerPayCumulativeUpkeep.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -79,7 +80,7 @@ public class TriggerPayCumulativeUpkeep extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Mana: ").append(sa.getTriggeringObject(AbilityKey.PayingMana)); + sb.append(Localizer.getInstance().getMessage("lblMana")).append(": ").append(sa.getTriggeringObject(AbilityKey.PayingMana)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerPayLife.java b/forge-game/src/main/java/forge/game/trigger/TriggerPayLife.java index 50bc7d21eea..dec7ee4f3be 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerPayLife.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerPayLife.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -68,8 +69,8 @@ public class TriggerPayLife extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Player: ").append(sa.getTriggeringObject(AbilityKey.Player)).append(", "); - sb.append("paid Amount: ").append(sa.getTriggeringObject(AbilityKey.LifeAmount)); + sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblPaidAmount")).append(": ").append(sa.getTriggeringObject(AbilityKey.LifeAmount)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerPhase.java b/forge-game/src/main/java/forge/game/trigger/TriggerPhase.java index 5a8adfc63de..d059f8205f7 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerPhase.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerPhase.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -69,7 +70,7 @@ public class TriggerPhase extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Phase: ").append(sa.getTriggeringObject(AbilityKey.Player)); + sb.append(Localizer.getInstance().getMessage("lblPhase")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerPhaseIn.java b/forge-game/src/main/java/forge/game/trigger/TriggerPhaseIn.java index 5368c42bd2f..3946cb5eba6 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerPhaseIn.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerPhaseIn.java @@ -3,6 +3,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -35,7 +36,7 @@ public class TriggerPhaseIn extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Phased In: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblPhasedIn")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerPhaseOut.java b/forge-game/src/main/java/forge/game/trigger/TriggerPhaseOut.java index fbc582cae21..bd9d0469d6f 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerPhaseOut.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerPhaseOut.java @@ -3,6 +3,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -43,7 +44,7 @@ public class TriggerPhaseOut extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Phased Out: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblPhasedOut")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerPlanarDice.java b/forge-game/src/main/java/forge/game/trigger/TriggerPlanarDice.java index e811f1b2761..99c63e0ff32 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerPlanarDice.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerPlanarDice.java @@ -4,6 +4,7 @@ import forge.game.PlanarDice; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -62,7 +63,7 @@ public class TriggerPlanarDice extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Roller: ").append(sa.getTriggeringObject(AbilityKey.Player)); + sb.append(Localizer.getInstance().getMessage("lblRoller")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerPlaneswalkedFrom.java b/forge-game/src/main/java/forge/game/trigger/TriggerPlaneswalkedFrom.java index b7aedd7c128..8a174b04fca 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerPlaneswalkedFrom.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerPlaneswalkedFrom.java @@ -4,6 +4,7 @@ import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.card.CardCollection; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -59,7 +60,7 @@ public class TriggerPlaneswalkedFrom extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Planeswalked From: ").append(sa.getTriggeringObject(AbilityKey.Cards)); + sb.append(Localizer.getInstance().getMessage("lblPlaneswalkedFrom")).append(": ").append(sa.getTriggeringObject(AbilityKey.Cards)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerPlaneswalkedTo.java b/forge-game/src/main/java/forge/game/trigger/TriggerPlaneswalkedTo.java index f927242dd71..b12d1cee14a 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerPlaneswalkedTo.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerPlaneswalkedTo.java @@ -3,6 +3,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -59,7 +60,7 @@ public class TriggerPlaneswalkedTo extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Planeswalked To: ").append(sa.getTriggeringObject(AbilityKey.Cards)); + sb.append(Localizer.getInstance().getMessage("lblPlaneswalkedTo")).append(": ").append(sa.getTriggeringObject(AbilityKey.Cards)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerRegenerated.java b/forge-game/src/main/java/forge/game/trigger/TriggerRegenerated.java index 2d07c738ed8..11a965aaaf0 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerRegenerated.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerRegenerated.java @@ -22,6 +22,7 @@ import java.util.Map; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; /** *

@@ -75,7 +76,7 @@ public class TriggerRegenerated extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Regenerated: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblRegenerated")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); //sb.append("Destroyer: ").append(sa.getTriggeringObject("Causer")); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerRevealed.java b/forge-game/src/main/java/forge/game/trigger/TriggerRevealed.java index 21445dfccc2..3d11d6934ce 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerRevealed.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerRevealed.java @@ -5,6 +5,7 @@ import java.util.Map; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; public class TriggerRevealed extends Trigger { @@ -37,7 +38,7 @@ public class TriggerRevealed extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Revealed: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblRevealed")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerSacrificed.java b/forge-game/src/main/java/forge/game/trigger/TriggerSacrificed.java index 42209562b2a..79b4436c909 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerSacrificed.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerSacrificed.java @@ -23,6 +23,7 @@ import forge.game.cost.IndividualCostPaymentInstance; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.zone.CostPaymentStack; +import forge.util.Localizer; import java.util.Map; @@ -135,7 +136,7 @@ public class TriggerSacrificed extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Sacrificed: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblSacrificed")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerScry.java b/forge-game/src/main/java/forge/game/trigger/TriggerScry.java index 67324ace54f..47cb3c7335e 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerScry.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerScry.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -71,7 +72,7 @@ public class TriggerScry extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Scryer: ").append(sa.getTriggeringObject(AbilityKey.Player)); + sb.append(Localizer.getInstance().getMessage("lblScryer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerSearchedLibrary.java b/forge-game/src/main/java/forge/game/trigger/TriggerSearchedLibrary.java index b4a197155b9..56b8f91b65a 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerSearchedLibrary.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerSearchedLibrary.java @@ -24,6 +24,7 @@ import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.player.Player; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; /** *

@@ -82,7 +83,7 @@ public class TriggerSearchedLibrary extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Searcher: ").append(sa.getTriggeringObject(AbilityKey.Player)); + sb.append(Localizer.getInstance().getMessage("lblSearcher")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerShuffled.java b/forge-game/src/main/java/forge/game/trigger/TriggerShuffled.java index 82f1e6d01be..a211eba1438 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerShuffled.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerShuffled.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -83,7 +84,7 @@ public class TriggerShuffled extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Shuffler: ").append(sa.getTriggeringObject(AbilityKey.Player)); + sb.append(Localizer.getInstance().getMessage("lblShuffler")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCast.java b/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCast.java index e13cab7df14..6708ee73337 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCast.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCast.java @@ -38,6 +38,7 @@ import forge.game.spellability.SpellAbilityStackInstance; import forge.game.spellability.TargetChoices; import forge.game.zone.ZoneType; import forge.util.Expressions; +import forge.util.Localizer; /** *

@@ -284,9 +285,9 @@ public class TriggerSpellAbilityCast extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Card: ").append(sa.getTriggeringObject(AbilityKey.Card)).append(", "); - sb.append("Activator: ").append(sa.getTriggeringObject(AbilityKey.Activator)).append(", "); - sb.append("SpellAbility: ").append(sa.getTriggeringObject(AbilityKey.SpellAbility)); + sb.append(Localizer.getInstance().getMessage("lblCard")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblActivator")).append(": ").append(sa.getTriggeringObject(AbilityKey.Activator)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblSpellAbility")).append(": ").append(sa.getTriggeringObject(AbilityKey.SpellAbility)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCopy.java b/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCopy.java index d21383e792b..ec00915227f 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCopy.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerSpellAbilityCopy.java @@ -23,6 +23,7 @@ import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbilityStackInstance; +import forge.util.Localizer; /** *

@@ -102,9 +103,9 @@ public class TriggerSpellAbilityCopy extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Card: ").append(sa.getTriggeringObject(AbilityKey.Card)).append(", "); - sb.append("Activator: ").append(sa.getTriggeringObject(AbilityKey.Activator)).append(", "); - sb.append("SpellAbility: ").append(sa.getTriggeringObject(AbilityKey.SpellAbility)); + sb.append(Localizer.getInstance().getMessage("lblCard")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblActivator")).append(": ").append(sa.getTriggeringObject(AbilityKey.Activator)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblSpellAbility")).append(": ").append(sa.getTriggeringObject(AbilityKey.SpellAbility)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerSurveil.java b/forge-game/src/main/java/forge/game/trigger/TriggerSurveil.java index 91170953511..cb5d6f1afea 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerSurveil.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerSurveil.java @@ -21,6 +21,7 @@ import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.player.Player; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -49,7 +50,7 @@ public class TriggerSurveil extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Player: ").append(sa.getTriggeringObject(AbilityKey.Player)); + sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerTaps.java b/forge-game/src/main/java/forge/game/trigger/TriggerTaps.java index faee4b2ee36..23a30a55195 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerTaps.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerTaps.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -85,7 +86,7 @@ public class TriggerTaps extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Tapped: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblTapped")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerTapsForMana.java b/forge-game/src/main/java/forge/game/trigger/TriggerTapsForMana.java index 78faa4bfd52..de96aa18d8b 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerTapsForMana.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerTapsForMana.java @@ -22,6 +22,7 @@ import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.player.Player; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -114,8 +115,8 @@ public class TriggerTapsForMana extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Tapped for Mana: ").append(sa.getTriggeringObject(AbilityKey.Card)); - sb.append("Produced: ").append(sa.getTriggeringObject(AbilityKey.Produced)); + sb.append(Localizer.getInstance().getMessage("lblTappedForMana")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblProduced")).append(": ").append(sa.getTriggeringObject(AbilityKey.Produced)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerTransformed.java b/forge-game/src/main/java/forge/game/trigger/TriggerTransformed.java index 43f032fd99a..36f0429f32c 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerTransformed.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerTransformed.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -65,7 +66,7 @@ public class TriggerTransformed extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Transformed: ").append(sa.getTriggeringObject(AbilityKey.Transformer)); + sb.append(Localizer.getInstance().getMessage("lblTransformed")).append(": ").append(sa.getTriggeringObject(AbilityKey.Transformer)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerTurnBegin.java b/forge-game/src/main/java/forge/game/trigger/TriggerTurnBegin.java index dba63859d73..e6bd53b8b28 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerTurnBegin.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerTurnBegin.java @@ -3,6 +3,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -29,7 +30,7 @@ public class TriggerTurnBegin extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Player: ").append(sa.getTriggeringObject(AbilityKey.Player)); + sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerTurnFaceUp.java b/forge-game/src/main/java/forge/game/trigger/TriggerTurnFaceUp.java index c1b96e0e102..f27a472667c 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerTurnFaceUp.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerTurnFaceUp.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -70,7 +71,7 @@ public class TriggerTurnFaceUp extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Turn Face up: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblTurnFaceUp")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerUnattach.java b/forge-game/src/main/java/forge/game/trigger/TriggerUnattach.java index d40179f1de6..18dbaeb6c7b 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerUnattach.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerUnattach.java @@ -21,6 +21,7 @@ import forge.game.GameEntity; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -82,8 +83,8 @@ public class TriggerUnattach extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Object: ").append(sa.getTriggeringObject(AbilityKey.Object)).append(", "); - sb.append("Attachment: ").append(sa.getTriggeringObject(AbilityKey.Attach)); + sb.append(Localizer.getInstance().getMessage("lblObject")).append(": ").append(sa.getTriggeringObject(AbilityKey.Object)).append(", "); + sb.append(Localizer.getInstance().getMessage("lblAttachment")).append(": ").append(sa.getTriggeringObject(AbilityKey.Attach)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerUntaps.java b/forge-game/src/main/java/forge/game/trigger/TriggerUntaps.java index 730d805c656..a01a3f8d46d 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerUntaps.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerUntaps.java @@ -20,6 +20,7 @@ package forge.game.trigger; import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import java.util.Map; @@ -74,7 +75,7 @@ public class TriggerUntaps extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Untapped: ").append(sa.getTriggeringObject(AbilityKey.Card)); + sb.append(Localizer.getInstance().getMessage("lblUntapped")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card)); return sb.toString(); } } diff --git a/forge-game/src/main/java/forge/game/trigger/TriggerVote.java b/forge-game/src/main/java/forge/game/trigger/TriggerVote.java index 169a5f39212..1a21bf5aa75 100644 --- a/forge-game/src/main/java/forge/game/trigger/TriggerVote.java +++ b/forge-game/src/main/java/forge/game/trigger/TriggerVote.java @@ -26,6 +26,7 @@ import forge.game.ability.AbilityKey; import forge.game.card.Card; import forge.game.player.Player; import forge.game.spellability.SpellAbility; +import forge.util.Localizer; import forge.util.collect.FCollection; /** @@ -77,7 +78,7 @@ public class TriggerVote extends Trigger { @Override public String getImportantStackObjects(SpellAbility sa) { StringBuilder sb = new StringBuilder(); - sb.append("Voters: ").append(sa.getTriggeringObject(AbilityKey.OtherVoters)); + sb.append(Localizer.getInstance().getMessage("lblVoters")).append(": ").append(sa.getTriggeringObject(AbilityKey.OtherVoters)); return sb.toString(); } diff --git a/forge-game/src/main/java/forge/trackable/TrackableProperty.java b/forge-game/src/main/java/forge/trackable/TrackableProperty.java index a26cfa0951b..b971b3e37f6 100644 --- a/forge-game/src/main/java/forge/trackable/TrackableProperty.java +++ b/forge-game/src/main/java/forge/trackable/TrackableProperty.java @@ -69,6 +69,7 @@ public enum TrackableProperty { //Card State Name(TrackableTypes.StringType), Colors(TrackableTypes.ColorSetType), + OriginalColors(TrackableTypes.ColorSetType), ImageKey(TrackableTypes.StringType), Type(TrackableTypes.CardTypeViewType), ManaCost(TrackableTypes.ManaCostType), @@ -80,6 +81,7 @@ public enum TrackableProperty { Toughness(TrackableTypes.IntegerType), Loyalty(TrackableTypes.StringType), ChangedColorWords(TrackableTypes.StringMapType), + HasChangedColors(TrackableTypes.BooleanType), ChangedTypes(TrackableTypes.StringMapType), KeywordKey(TrackableTypes.StringType), @@ -120,6 +122,7 @@ public enum TrackableProperty { LobbyPlayerName(TrackableTypes.StringType), AvatarIndex(TrackableTypes.IntegerType), AvatarCardImageKey(TrackableTypes.StringType), + SleeveIndex(TrackableTypes.IntegerType), Opponents(TrackableTypes.PlayerViewCollectionType), Life(TrackableTypes.IntegerType), PoisonCounters(TrackableTypes.IntegerType), diff --git a/forge-gui-android/libs/arm64-v8a/libgdx-freetype.so b/forge-gui-android/libs/arm64-v8a/libgdx-freetype.so new file mode 100644 index 00000000000..7565cedda9c Binary files /dev/null and b/forge-gui-android/libs/arm64-v8a/libgdx-freetype.so differ diff --git a/forge-gui-android/libs/arm64-v8a/libgdx.so b/forge-gui-android/libs/arm64-v8a/libgdx.so new file mode 100644 index 00000000000..258b198378c Binary files /dev/null and b/forge-gui-android/libs/arm64-v8a/libgdx.so differ diff --git a/forge-gui-android/libs/armeabi-v7a/libgdx-freetype.so b/forge-gui-android/libs/armeabi-v7a/libgdx-freetype.so index acdeb53636e..648bf6c4f3e 100644 Binary files a/forge-gui-android/libs/armeabi-v7a/libgdx-freetype.so and b/forge-gui-android/libs/armeabi-v7a/libgdx-freetype.so differ diff --git a/forge-gui-android/libs/armeabi-v7a/libgdx.so b/forge-gui-android/libs/armeabi-v7a/libgdx.so index 1b517c99f7a..89150620111 100644 Binary files a/forge-gui-android/libs/armeabi-v7a/libgdx.so and b/forge-gui-android/libs/armeabi-v7a/libgdx.so differ diff --git a/forge-gui-android/libs/armeabi/libgdx-freetype.so b/forge-gui-android/libs/armeabi/libgdx-freetype.so index 26388012eae..53121395224 100644 Binary files a/forge-gui-android/libs/armeabi/libgdx-freetype.so and b/forge-gui-android/libs/armeabi/libgdx-freetype.so differ diff --git a/forge-gui-android/libs/armeabi/libgdx.so b/forge-gui-android/libs/armeabi/libgdx.so index c54c7338740..18158fb4d69 100644 Binary files a/forge-gui-android/libs/armeabi/libgdx.so and b/forge-gui-android/libs/armeabi/libgdx.so differ diff --git a/forge-gui-android/libs/gdx-backend-android-sources.jar b/forge-gui-android/libs/gdx-backend-android-sources.jar index 5315cab4bdb..414fa961cfd 100644 Binary files a/forge-gui-android/libs/gdx-backend-android-sources.jar and b/forge-gui-android/libs/gdx-backend-android-sources.jar differ diff --git a/forge-gui-android/libs/gdx-backend-android.jar b/forge-gui-android/libs/gdx-backend-android.jar index c847c6e1c74..d780673aa6b 100644 Binary files a/forge-gui-android/libs/gdx-backend-android.jar and b/forge-gui-android/libs/gdx-backend-android.jar differ diff --git a/forge-gui-android/libs/gdx-freetype.jar b/forge-gui-android/libs/gdx-freetype.jar index cff324ecd35..eda8b39b168 100644 Binary files a/forge-gui-android/libs/gdx-freetype.jar and b/forge-gui-android/libs/gdx-freetype.jar differ diff --git a/forge-gui-android/libs/gdx-sources.jar b/forge-gui-android/libs/gdx-sources.jar index ca6c8a53100..798fee80a7b 100644 Binary files a/forge-gui-android/libs/gdx-sources.jar and b/forge-gui-android/libs/gdx-sources.jar differ diff --git a/forge-gui-android/libs/gdx.jar b/forge-gui-android/libs/gdx.jar index 7d93f8ba6b3..0ba4a3f2bb4 100644 Binary files a/forge-gui-android/libs/gdx.jar and b/forge-gui-android/libs/gdx.jar differ diff --git a/forge-gui-android/libs/x86/libgdx-freetype.so b/forge-gui-android/libs/x86/libgdx-freetype.so index 62c08dd6038..93020a63c0d 100644 Binary files a/forge-gui-android/libs/x86/libgdx-freetype.so and b/forge-gui-android/libs/x86/libgdx-freetype.so differ diff --git a/forge-gui-android/libs/x86/libgdx.so b/forge-gui-android/libs/x86/libgdx.so index 1f144b902b5..812a5ce27ca 100644 Binary files a/forge-gui-android/libs/x86/libgdx.so and b/forge-gui-android/libs/x86/libgdx.so differ diff --git a/forge-gui-android/libs/x86_64/libgdx-freetype.so b/forge-gui-android/libs/x86_64/libgdx-freetype.so new file mode 100644 index 00000000000..140daa47306 Binary files /dev/null and b/forge-gui-android/libs/x86_64/libgdx-freetype.so differ diff --git a/forge-gui-android/libs/x86_64/libgdx.so b/forge-gui-android/libs/x86_64/libgdx.so new file mode 100644 index 00000000000..03ca6fdc9b8 Binary files /dev/null and b/forge-gui-android/libs/x86_64/libgdx.so differ diff --git a/forge-gui-android/pom.xml b/forge-gui-android/pom.xml index 7708708406e..76e136472a5 100644 --- a/forge-gui-android/pom.xml +++ b/forge-gui-android/pom.xml @@ -6,7 +6,7 @@ jar -Xms1024m -Xmx1536m - 1.6.29.001 + 1.6.30.001 keystore alias storepass @@ -19,7 +19,7 @@ forge forge - 1.6.30-SNAPSHOT + 1.6.31-SNAPSHOT forge-gui-android @@ -81,17 +81,17 @@ com.google.guava guava - 24.1-android + 28.1-android com.thoughtworks.xstream xstream - 1.4.7 + 1.4.9 org.apache.commons commons-lang3 - 3.7 + 3.8.1 xmlpull @@ -104,6 +104,24 @@ gdx-backend-android 1.9.10 + + org.cache2k + cache2k-base-bom + 1.2.4.Final + pom + + + org.cache2k + cache2k-core + 1.2.4.Final + compile + + + org.cache2k + cache2k-api + 1.2.4.Final + compile + diff --git a/forge-gui-android/proguard.cfg b/forge-gui-android/proguard.cfg index e6a1ef032c5..57fa2061f4d 100644 --- a/forge-gui-android/proguard.cfg +++ b/forge-gui-android/proguard.cfg @@ -27,6 +27,22 @@ -dontwarn java.lang.** -dontwarn org.slf4j.** -dontwarn javax.** +-dontwarn org.apache.logging.log4j.** +-dontwarn module-info + +# mandatory proguard rules for cache2k to keep the core implementation +-dontwarn org.cache2k.impl.xmlConfiguration.** +-dontwarn org.cache2k.impl.serverSide.** +-keep interface org.cache2k.spi.Cache2kCoreProvider +-keep public class * extends org.cache2k.spi.Cache2kCoreProvider +# optional proguard rules for cache2k, to keep XML configuration code +# if only programmatic configuration is used, these rules may be ommitted +-keep interface org.cache2k.core.spi.CacheConfigurationProvider +-keep public class * extends org.cache2k.core.spi.CacheConfigurationProvider +-keepclassmembers public class * extends org.cache2k.configuration.ConfigurationBean { + public void set*(...); + public ** get*(); +} -keep class forge.** { *; } -keep class com.thoughtworks.xstream.** { *; } @@ -34,6 +50,7 @@ -keep class com.google.guava.** { *; } -keep class com.google.common.** { *; } -keep class io.sentry.event.Event { *; } +-keep class io.netty.util.internal.logging.** { *; } -keepclassmembers class com.badlogic.gdx.backends.android.AndroidInput* { (com.badlogic.gdx.Application, android.content.Context, java.lang.Object, com.badlogic.gdx.backends.android.AndroidApplicationConfiguration); diff --git a/forge-gui-android/src/forge/app/Main.java b/forge-gui-android/src/forge/app/Main.java index 66728960885..70aa9389704 100644 --- a/forge-gui-android/src/forge/app/Main.java +++ b/forge-gui-android/src/forge/app/Main.java @@ -14,6 +14,7 @@ import android.graphics.BitmapFactory; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.os.PowerManager; @@ -71,7 +72,8 @@ public class Main extends AndroidApplication { Main.this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } - initialize(Forge.getApp(new AndroidClipboard(), adapter, assetsDir)); + boolean value = Build.VERSION.SDK_INT >= 26; + initialize(Forge.getApp(new AndroidClipboard(), adapter, assetsDir, value)); } /*@Override diff --git a/forge-gui-desktop/pom.xml b/forge-gui-desktop/pom.xml index a37c5e7a7b7..1fed7ebefc2 100644 --- a/forge-gui-desktop/pom.xml +++ b/forge-gui-desktop/pom.xml @@ -4,7 +4,7 @@ forge forge - 1.6.30-SNAPSHOT + 1.6.31-SNAPSHOT forge-gui-desktop @@ -142,12 +142,12 @@ com.google.guava guava - 24.1-android + 28.1-android com.thoughtworks.xstream xstream - 1.4.10 + 1.4.11.1 org.testng @@ -168,9 +168,14 @@ test - log4j - log4j - 1.2.17 + org.apache.logging.log4j + log4j-api + 2.11.2 + + + org.apache.logging.log4j + log4j-core + 2.11.2 com.googlecode @@ -180,7 +185,7 @@ org.apache.commons commons-lang3 - 3.7 + 3.8.1 org.freemarker diff --git a/forge-gui-desktop/src/main/java/forge/GuiDesktop.java b/forge-gui-desktop/src/main/java/forge/GuiDesktop.java index ae3bc960403..b5cdb5b9f70 100644 --- a/forge-gui-desktop/src/main/java/forge/GuiDesktop.java +++ b/forge-gui-desktop/src/main/java/forge/GuiDesktop.java @@ -202,6 +202,14 @@ public class GuiDesktop implements IGuiBase { return 0; } + @Override + public int getSleevesCount() { + if (FSkin.isLoaded()) { + return FSkin.getSleeves().size(); + } + return 0; + } + @Override public String showFileDialog(final String title, final String defaultDir) { final JFileChooser fc = new JFileChooser(defaultDir); diff --git a/forge-gui-desktop/src/main/java/forge/deckchooser/FDeckChooser.java b/forge-gui-desktop/src/main/java/forge/deckchooser/FDeckChooser.java index 2c8b5b40eaf..48ea79c9fa6 100644 --- a/forge-gui-desktop/src/main/java/forge/deckchooser/FDeckChooser.java +++ b/forge-gui-desktop/src/main/java/forge/deckchooser/FDeckChooser.java @@ -383,6 +383,11 @@ public class FDeckChooser extends JPanel implements IDecksComboBoxListener { updateMatrix(FModel.getFormats().getStandard()); } break; + case PIONEER_CARDGEN_DECK: + if(FModel.isdeckGenMatrixLoaded()) { + updateMatrix(FModel.getFormats().getPioneer()); + } + break; case MODERN_CARDGEN_DECK: if(FModel.isdeckGenMatrixLoaded()) { updateMatrix(FModel.getFormats().getModern()); diff --git a/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java b/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java index f64ae7e077e..c99b4cb6ab6 100644 --- a/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java +++ b/forge-gui-desktop/src/main/java/forge/gui/GuiChoose.java @@ -293,6 +293,7 @@ public class GuiChoose { @Override public List call() { ListCardArea tempArea = ListCardArea.show(gui,title,cards,manipulable,toTop,toBottom,toAnywhere); + // tempArea.pack(); tempArea.setVisible(true); return tempArea.getCards(); diff --git a/forge-gui-desktop/src/main/java/forge/gui/framework/FScreen.java b/forge-gui-desktop/src/main/java/forge/gui/framework/FScreen.java index 04c6e7f225c..727443f5066 100644 --- a/forge-gui-desktop/src/main/java/forge/gui/framework/FScreen.java +++ b/forge-gui-desktop/src/main/java/forge/gui/framework/FScreen.java @@ -28,7 +28,7 @@ public class FScreen { public static final FScreen HOME_SCREEN = new FScreen( VHomeUI.SINGLETON_INSTANCE, CHomeUI.SINGLETON_INSTANCE, - "Home", + "Home ", FSkin.getIcon(FSkinProp.ICO_FAVICON), false, "Exit Forge", @@ -46,7 +46,7 @@ public class FScreen { public static final FScreen DECK_EDITOR_CONSTRUCTED = new FScreen( VDeckEditorUI.SINGLETON_INSTANCE, CDeckEditorUI.SINGLETON_INSTANCE, - "Deck Editor", + "Deck Editor ", FSkin.getImage(FSkinProp.IMG_PACK), false, "Back to Home", diff --git a/forge-gui-desktop/src/main/java/forge/itemmanager/views/ImageView.java b/forge-gui-desktop/src/main/java/forge/itemmanager/views/ImageView.java index 4c29cde08c5..16e2eca982d 100644 --- a/forge-gui-desktop/src/main/java/forge/itemmanager/views/ImageView.java +++ b/forge-gui-desktop/src/main/java/forge/itemmanager/views/ImageView.java @@ -77,6 +77,7 @@ public class ImageView extends ItemView { private Point hoverScrollPos; private ItemInfo hoveredItem; private ItemInfo focalItem; + private boolean panelOptionsCreated = false; private final List orderedItems = new ArrayList<>(); private final List groups = new ArrayList<>(); @@ -337,7 +338,12 @@ public class ImageView extends ItemView { @Override public void setup(ItemManagerConfig config, Map colOverrides) { - setPanelOptions(config.getShowUniqueCardsOption()); + // if this is the first setup call, panel options will be added to UI components + if (!this.panelOptionsCreated){ + setPanelOptions(config.getShowUniqueCardsOption()); + this.panelOptionsCreated = true; + } + // set status of components in the panel setGroupBy(config.getGroupBy(), true); setPileBy(config.getPileBy(), true); setColumnCount(config.getImageColumnCount(), true); diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/ACEditorBase.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/ACEditorBase.java index 1e809ae2752..3bd75e1d858 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/ACEditorBase.java +++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/ACEditorBase.java @@ -212,6 +212,12 @@ public abstract class ACEditorBase cardAmountInfo = Iterables.find(cardsByName, new Predicate>() { @Override public boolean apply(Entry t) { diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/PlayerPanel.java b/forge-gui-desktop/src/main/java/forge/screens/home/PlayerPanel.java index c6afcf7e625..dd1639b12ee 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/PlayerPanel.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/PlayerPanel.java @@ -14,6 +14,7 @@ import javax.swing.ButtonGroup; import javax.swing.JCheckBoxMenuItem; import javax.swing.JPopupMenu; +import forge.screens.home.sanctioned.SleeveSelector; import net.miginfocom.swing.MigLayout; import org.apache.commons.lang3.StringUtils; @@ -66,7 +67,8 @@ public class PlayerPanel extends FPanel { private final FLabel nameRandomiser; private final FLabel avatarLabel = new FLabel.Builder().opaque(true).hoverable(true).iconScaleFactor(0.99f).iconInBackground(true).build(); - private int avatarIndex; + private final FLabel sleeveLabel = new FLabel.Builder().opaque(true).hoverable(true).iconScaleFactor(0.99f).iconInBackground(true).build(); + private int avatarIndex, sleeveIndex; private final FTextField txtPlayerName = new FTextField.Builder().build(); private FRadioButton radioHuman; @@ -127,6 +129,10 @@ public class PlayerPanel extends FPanel { createAvatar(); this.add(avatarLabel, "spany 2, width 80px, height 80px"); + /*TODO Layout and Override for PC*/ + //createSleeve(); + //this.add(sleeveLabel, "spany 2, width 60px, height 80px"); + createNameEditor(); this.add(lobby.newLabel(localizer.getMessage("lblName") +":"), "w 40px, h 30px, gaptop 5px"); this.add(txtPlayerName, "h 30px, pushx, growx"); @@ -204,6 +210,10 @@ public class PlayerPanel extends FPanel { avatarLabel.setIcon(FSkin.getAvatars().get(Integer.valueOf(type == LobbySlotType.OPEN ? -1 : avatarIndex))); avatarLabel.repaintSelf(); + sleeveLabel.setEnabled(mayEdit); + sleeveLabel.setIcon(FSkin.getSleeves().get(Integer.valueOf(type == LobbySlotType.OPEN ? -1 : sleeveIndex))); + sleeveLabel.repaintSelf(); + txtPlayerName.setEnabled(mayEdit); txtPlayerName.setText(type == LobbySlotType.OPEN ? StringUtils.EMPTY : playerName); nameRandomiser.setEnabled(mayEdit); @@ -332,6 +342,62 @@ public class PlayerPanel extends FPanel { } }; + /** Listens to sleeve buttons and gives the appropriate player focus. */ + private final FocusAdapter sleeveFocusListener = new FocusAdapter() { + @Override + public void focusGained(final FocusEvent e) { + lobby.changePlayerFocus(index); + } + }; + + private final FMouseAdapter sleeveMouseListener = new FMouseAdapter() { + @Override public final void onLeftClick(final MouseEvent e) { + if (!sleeveLabel.isEnabled()) { + return; + } + + final FLabel sleeve = (FLabel)e.getSource(); + + lobby.changePlayerFocus(index); + sleeve.requestFocusInWindow(); + + final SleeveSelector sSel = new SleeveSelector(playerName, sleeveIndex, lobby.getUsedSleeves()); + for (final FLabel lbl : sSel.getSelectables()) { + lbl.setCommand(new UiCommand() { + @Override + public void run() { + setSleeveIndex(Integer.valueOf(lbl.getName().substring(11))); + sSel.setVisible(false); + } + }); + } + + sSel.setVisible(true); + sSel.dispose(); + + if (index < 2) { + lobby.updateSleevePrefs(); + } + + lobby.firePlayerChangeListener(index); + } + + @Override public final void onRightClick(final MouseEvent e) { + if (!sleeveLabel.isEnabled()) { + return; + } + + lobby.changePlayerFocus(index); + sleeveLabel.requestFocusInWindow(); + + setRandomSleeve(); + + if (index < 2) { + lobby.updateSleevePrefs(); + } + } + }; + private void updateVariantControlsVisibility() { final boolean isOathbreaker = lobby.hasVariant(GameType.Oathbreaker); final boolean isTinyLeaders = lobby.hasVariant(GameType.TinyLeaders); @@ -703,6 +769,20 @@ public class PlayerPanel extends FPanel { avatarLabel.addMouseListener(avatarMouseListener); } + private void createSleeve() { + final String[] currentPrefs = FModel.getPreferences().getPref(FPref.UI_SLEEVES).split(","); + if (index < currentPrefs.length) { + sleeveIndex = Integer.parseInt(currentPrefs[index]); + sleeveLabel.setIcon(FSkin.getSleeves().get(sleeveIndex)); + } else { + setRandomSleeve(false); + } + + sleeveLabel.setToolTipText("L-click: Select sleeve. R-click: Randomize sleeve."); + sleeveLabel.addFocusListener(sleeveFocusListener); + sleeveLabel.addMouseListener(sleeveMouseListener); + } + /** Applies a random avatar, avoiding avatars already used. */ private void setRandomAvatar() { setRandomAvatar(true); @@ -721,6 +801,24 @@ public class PlayerPanel extends FPanel { } } + /** Applies a random sleeve, avoiding sleeve already used. */ + private void setRandomSleeve() { + setRandomSleeve(true); + } + private void setRandomSleeve(final boolean fireListeners) { + int random = 0; + + final List usedSleeves = lobby.getUsedSleeves(); + do { + random = MyRandom.getRandom().nextInt(FSkin.getSleeves().size()); + } while (usedSleeves.contains(random)); + setSleeveIndex(random); + + if (fireListeners) { + lobby.firePlayerChangeListener(index); + } + } + private final FSkin.LineSkinBorder focusedBorder = new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_BORDERS).alphaColor(255), 3); private final FSkin.LineSkinBorder defaultBorder = new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_THEME).alphaColor(200), 2); @@ -746,6 +844,16 @@ public class PlayerPanel extends FPanel { avatarLabel.repaintSelf(); } + public int getSleeveIndex() { + return sleeveIndex; + } + public void setSleeveIndex(final int sleeveIndex0) { + sleeveIndex = sleeveIndex0; + final SkinImage icon = FSkin.getSleeves().get(sleeveIndex); + sleeveLabel.setIcon(icon); + sleeveLabel.repaintSelf(); + } + public int getTeam() { return teamComboBox.getSelectedIndex(); } diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java b/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java index 7c0c978b0be..aebb0936bec 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java @@ -3,6 +3,7 @@ package forge.screens.home; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; +import forge.GuiBase; import forge.UiCommand; import forge.ai.AIOption; import forge.deck.*; @@ -222,6 +223,7 @@ public class VLobby implements ILobbyView { DeckType selectedDeckType = deckChooser.getSelectedDeckType(); switch (selectedDeckType){ case STANDARD_CARDGEN_DECK: + case PIONEER_CARDGEN_DECK: case MODERN_CARDGEN_DECK: case LEGACY_CARDGEN_DECK: case VINTAGE_CARDGEN_DECK: @@ -258,6 +260,9 @@ public class VLobby implements ILobbyView { addPlayerBtn.setEnabled(activePlayersNum < MAX_PLAYERS); final boolean allowNetworking = lobby.isAllowNetworking(); + + GuiBase.setNetworkplay(allowNetworking); + ImmutableList vntBoxes = null; if (allowNetworking) { vntBoxes = vntBoxesNetwork; @@ -397,7 +402,7 @@ public class VLobby implements ILobbyView { private UpdateLobbyPlayerEvent getSlot(final int index) { final PlayerPanel panel = playerPanels.get(index); - return UpdateLobbyPlayerEvent.create(panel.getType(), panel.getPlayerName(), panel.getAvatarIndex(), panel.getTeam(), panel.isArchenemy(), panel.isReady(), panel.isDevMode(), panel.getAiOptions()); + return UpdateLobbyPlayerEvent.create(panel.getType(), panel.getPlayerName(), panel.getAvatarIndex(), -1/*TODO panel.getSleeveIndex()*/, panel.getTeam(), panel.isArchenemy(), panel.isReady(), panel.isDevMode(), panel.getAiOptions()); } /** Builds the actual deck panel layouts for each player. @@ -858,6 +863,15 @@ public class VLobby implements ILobbyView { prefs.save(); } + /** Saves sleeve prefs for players one and two. */ + void updateSleevePrefs() { + final int pOneIndex = playerPanels.get(0).getSleeveIndex(); + final int pTwoIndex = playerPanels.get(1).getSleeveIndex(); + + prefs.setPref(FPref.UI_SLEEVES, pOneIndex + "," + pTwoIndex); + prefs.save(); + } + /** Adds a pre-styled FLabel component with the specified title. */ FLabel newLabel(final String title) { return new FLabel.Builder().text(title).fontSize(14).fontStyle(Font.ITALIC).build(); @@ -871,6 +885,14 @@ public class VLobby implements ILobbyView { return usedAvatars; } + List getUsedSleeves() { + final List usedSleeves = Lists.newArrayListWithCapacity(MAX_PLAYERS); + for (final PlayerPanel pp : playerPanels) { + usedSleeves.add(pp.getSleeveIndex()); + } + return usedSleeves; + } + private static final ImmutableList genderOptions = ImmutableList.of("Male", "Female", "Any"), typeOptions = ImmutableList.of("Fantasy", "Generic", "Any"); diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/gauntlet/CSubmenuGauntletQuick.java b/forge-gui-desktop/src/main/java/forge/screens/home/gauntlet/CSubmenuGauntletQuick.java index 237d7124593..d32dd9d2011 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/gauntlet/CSubmenuGauntletQuick.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/gauntlet/CSubmenuGauntletQuick.java @@ -72,6 +72,7 @@ public enum CSubmenuGauntletQuick implements ICDoc { if (view.getBoxColorDecks().isSelected()) { allowedDeckTypes.add(DeckType.COLOR_DECK); } if (view.getBoxStandardColorDecks().isSelected()) { allowedDeckTypes.add(DeckType.STANDARD_COLOR_DECK); } if (view.getBoxStandardGenDecks().isSelected()) { allowedDeckTypes.add(DeckType.STANDARD_CARDGEN_DECK); } + if (view.getBoxPioneerGenDecks().isSelected()) { allowedDeckTypes.add(DeckType.PIONEER_CARDGEN_DECK); } if (view.getBoxModernGenDecks().isSelected()) { allowedDeckTypes.add(DeckType.MODERN_CARDGEN_DECK); } if (view.getBoxLegacyGenDecks().isSelected()) { allowedDeckTypes.add(DeckType.LEGACY_CARDGEN_DECK); } if (view.getBoxVintageGenDecks().isSelected()) { allowedDeckTypes.add(DeckType.VINTAGE_CARDGEN_DECK); } diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/gauntlet/VSubmenuGauntletQuick.java b/forge-gui-desktop/src/main/java/forge/screens/home/gauntlet/VSubmenuGauntletQuick.java index 53d8b4ef1f7..b73bd4e1f32 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/gauntlet/VSubmenuGauntletQuick.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/gauntlet/VSubmenuGauntletQuick.java @@ -56,6 +56,7 @@ public enum VSubmenuGauntletQuick implements IVSubmenu { private final JCheckBox boxColorDecks = new FCheckBox(DeckType.COLOR_DECK.toString()); private final JCheckBox boxStandardColorDecks = new FCheckBox(DeckType.STANDARD_COLOR_DECK.toString()); private final JCheckBox boxStandardCardgenDecks = new FCheckBox(DeckType.STANDARD_CARDGEN_DECK.toString()); + private final JCheckBox boxPioneerCardgenDecks = new FCheckBox(DeckType.PIONEER_CARDGEN_DECK.toString()); private final JCheckBox boxModernCardgenDecks = new FCheckBox(DeckType.MODERN_CARDGEN_DECK.toString()); private final JCheckBox boxLegacyCardgenDecks = new FCheckBox(DeckType.LEGACY_CARDGEN_DECK.toString()); private final JCheckBox boxVintageCardgenDecks = new FCheckBox(DeckType.VINTAGE_CARDGEN_DECK.toString()); @@ -88,11 +89,13 @@ public enum VSubmenuGauntletQuick implements IVSubmenu { boxStandardColorDecks.setSelected(true); if(FModel.isdeckGenMatrixLoaded()) { boxStandardCardgenDecks.setSelected(true); + boxPioneerCardgenDecks.setSelected(true); boxModernCardgenDecks.setSelected(true); boxLegacyCardgenDecks.setSelected(true); boxVintageCardgenDecks.setSelected(true); }else{ boxStandardCardgenDecks.setSelected(false); + boxPioneerCardgenDecks.setSelected(false); boxModernCardgenDecks.setSelected(false); boxLegacyCardgenDecks.setSelected(false); boxVintageCardgenDecks.setSelected(false); @@ -121,6 +124,7 @@ public enum VSubmenuGauntletQuick implements IVSubmenu { pnlOptions.add(boxColorDecks, "w 96%!, h 30px!, gap 2% 0 0 5px"); if(FModel.isdeckGenMatrixLoaded()) { pnlOptions.add(boxStandardCardgenDecks, "w 96%!, h 30px!, gap 2% 0 0 5px"); + pnlOptions.add(boxPioneerCardgenDecks, "w 96%!, h 30px!, gap 2% 0 0 5px"); pnlOptions.add(boxModernCardgenDecks, "w 96%!, h 30px!, gap 2% 0 0 5px"); pnlOptions.add(boxLegacyCardgenDecks, "w 96%!, h 30px!, gap 2% 0 0 5px"); pnlOptions.add(boxVintageCardgenDecks, "w 96%!, h 30px!, gap 2% 0 0 5px"); @@ -221,6 +225,9 @@ public enum VSubmenuGauntletQuick implements IVSubmenu { public JCheckBox getBoxModernGenDecks() { return boxModernCardgenDecks; } + public JCheckBox getBoxPioneerGenDecks() { + return boxPioneerCardgenDecks; + } public JCheckBox getBoxLegacyGenDecks() { return boxLegacyCardgenDecks; } diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/SleeveSelector.java b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/SleeveSelector.java new file mode 100644 index 00000000000..91fb09361ee --- /dev/null +++ b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/SleeveSelector.java @@ -0,0 +1,71 @@ +package forge.screens.home.sanctioned; + +import forge.gui.WrapLayout; +import forge.toolbox.FLabel; +import forge.toolbox.FScrollPane; +import forge.toolbox.FSkin; +import forge.view.FDialog; + +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +@SuppressWarnings("serial") +public class SleeveSelector extends FDialog { + private final List selectables = new ArrayList<>(); + private final Map sleeveMap = FSkin.getSleeves(); + + public SleeveSelector(final String playerName, final int currentIndex, final Collection usedIndices) { + this.setTitle("Select Sleeve for " + playerName); + + final JPanel pnlSleevePics = new JPanel(new WrapLayout()); + + pnlSleevePics.setOpaque(false); + pnlSleevePics.setOpaque(false); + + final FLabel initialSelection = makeSleeveLabel(sleeveMap.get(currentIndex), currentIndex, currentIndex); + pnlSleevePics.add(initialSelection); + for (final Integer i : sleeveMap.keySet()) { + if (currentIndex != i) { + pnlSleevePics.add(makeSleeveLabel(sleeveMap.get(i), i, currentIndex)); + } + } + + final int width = this.getOwner().getWidth() * 3 / 4; + final int height = this.getOwner().getHeight() * 3 / 4; + this.setPreferredSize(new Dimension(width, height)); + this.setSize(width, height); + + final FScrollPane scroller = new FScrollPane(pnlSleevePics, false); + scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + this.add(scroller, "w 100%-24px!, pushy, growy, gap 12px 0 0 0"); + this.setDefaultFocus(initialSelection); + } + + private FLabel makeSleeveLabel(final FSkin.SkinImage img0, final int index0, final int oldIndex) { + final FLabel lbl = new FLabel.Builder().icon(img0).iconScaleFactor(0.95).iconAlignX(SwingConstants.CENTER) + .iconInBackground(true).hoverable(true).selectable(true).selected(oldIndex == index0) + .unhoveredAlpha(oldIndex == index0 ? 0.9f : 0.7f).build(); + + final Dimension size = new Dimension(60, 80); + lbl.setPreferredSize(size); + lbl.setMaximumSize(size); + lbl.setMinimumSize(size); + lbl.setName("SleeveLabel" + index0); + + if (oldIndex == index0) { + lbl.setBorder(new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_BORDERS).alphaColor(255), 3)); + } + + selectables.add(lbl); + + return lbl; + } + + public List getSelectables() { + return this.selectables; + } +} diff --git a/forge-gui-desktop/src/main/java/forge/toolbox/FSkin.java b/forge-gui-desktop/src/main/java/forge/toolbox/FSkin.java index 722c862906b..a80b635e0fe 100644 --- a/forge-gui-desktop/src/main/java/forge/toolbox/FSkin.java +++ b/forge-gui-desktop/src/main/java/forge/toolbox/FSkin.java @@ -859,6 +859,7 @@ public class FSkin { } private static Map avatars; + private static Map sleeves; private static Map fixedFonts = new HashMap<>(); public static Font getFixedFont() { @@ -1039,7 +1040,7 @@ public class FSkin { private static String preferredDir; private static String preferredName; private static BufferedImage bimDefaultSprite, bimFavIcon, bimPreferredSprite, bimFoils, bimQuestDraftDeck, - bimOldFoils, bimDefaultAvatars, bimPreferredAvatars, bimTrophies, bimAbilities, bimManaIcons; + bimOldFoils, bimDefaultAvatars, bimPreferredAvatars, bimTrophies, bimAbilities, bimManaIcons, bimDefaultSleeve, bimDefaultSleeve2; private static int x0, y0, w0, h0, newW, newH, preferredW, preferredH; private static int[] tempCoords; private static int defaultFontSize = 12; @@ -1173,6 +1174,8 @@ public class FSkin { final File f9 = new File(defaultDir + ForgeConstants.SPRITE_FAVICONS_FILE); final File f10 = new File(defaultDir + ForgeConstants.SPRITE_ABILITY_FILE); final File f11 = new File(defaultDir + ForgeConstants.SPRITE_MANAICONS_FILE); + final File f12 = new File(defaultDir + ForgeConstants.SPRITE_SLEEVES_FILE); + final File f13 = new File(defaultDir + ForgeConstants.SPRITE_SLEEVES2_FILE); try { int p = 0; @@ -1190,6 +1193,10 @@ public class FSkin { FView.SINGLETON_INSTANCE.incrementSplashProgessBar(++p); bimDefaultAvatars = ImageIO.read(f4); FView.SINGLETON_INSTANCE.incrementSplashProgessBar(++p); + bimDefaultSleeve = ImageIO.read(f12); + FView.SINGLETON_INSTANCE.incrementSplashProgessBar(++p); + bimDefaultSleeve2 = ImageIO.read(f13); + FView.SINGLETON_INSTANCE.incrementSplashProgessBar(++p); bimTrophies = ImageIO.read(f7); FView.SINGLETON_INSTANCE.incrementSplashProgessBar(++p); bimQuestDraftDeck = ImageIO.read(f8); @@ -1255,6 +1262,8 @@ public class FSkin { // Assemble avatar images assembleAvatars(); + // Sleeves + assembleSleeves(); // Images loaded; can start UI init. FView.SINGLETON_INSTANCE.setSplashProgessBarMessage("Creating display components."); @@ -1266,6 +1275,8 @@ public class FSkin { bimOldFoils.flush(); bimPreferredSprite.flush(); bimDefaultAvatars.flush(); + bimDefaultSleeve.flush(); + bimDefaultSleeve2.flush(); bimQuestDraftDeck.flush(); bimTrophies.flush(); bimAbilities.flush(); @@ -1278,6 +1289,8 @@ public class FSkin { bimOldFoils = null; bimPreferredSprite = null; bimDefaultAvatars = null; + bimDefaultSleeve = null; + bimDefaultSleeve2 = null; bimPreferredAvatars = null; bimQuestDraftDeck = null; bimTrophies = null; @@ -1379,6 +1392,10 @@ public class FSkin { return avatars; } + public static Map getSleeves() { + return sleeves; + } + public static boolean isLoaded() { return loaded; } /** @@ -1482,6 +1499,34 @@ public class FSkin { } } + private static void assembleSleeves() { + sleeves = new HashMap<>(); + int counter = 0; + Color pxTest; + + final int pw = bimDefaultSleeve.getWidth(); + final int ph = bimDefaultSleeve.getHeight(); + + for (int j = 0; j < ph; j += 500) { + for (int i = 0; i < pw; i += 360) { + pxTest = getColorFromPixel(bimDefaultSleeve.getRGB(i + 180, j + 250)); + if (pxTest.getAlpha() == 0) { continue; } + sleeves.put(counter++, new SkinImage(bimDefaultSleeve.getSubimage(i, j, 360, 500))); + } + } + //2nd set + final int aw = bimDefaultSleeve2.getWidth(); + final int ah = bimDefaultSleeve2.getHeight(); + + for (int j = 0; j < ah; j += 500) { + for (int i = 0; i < aw; i += 360) { + pxTest = getColorFromPixel(bimDefaultSleeve2.getRGB(i + 180, j + 250)); + if (pxTest.getAlpha() == 0) { continue; } + sleeves.put(counter++, new SkinImage(bimDefaultSleeve2.getSubimage(i, j, 360, 500))); + } + } + } + private static void setImage(final FSkinProp s0, final BufferedImage bim) { tempCoords = s0.getCoords(); x0 = tempCoords[0]; diff --git a/forge-gui-desktop/src/main/java/forge/view/Main.java b/forge-gui-desktop/src/main/java/forge/view/Main.java index 143b21506b2..05675d2225d 100644 --- a/forge-gui-desktop/src/main/java/forge/view/Main.java +++ b/forge-gui-desktop/src/main/java/forge/view/Main.java @@ -49,6 +49,9 @@ public final class Main { //setup GUI interface GuiBase.setInterface(new GuiDesktop()); + //set PropertyConfig log4j to true + GuiBase.enablePropertyConfig(true); + //install our error handler ExceptionHandler.registerErrorHandling(); diff --git a/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java b/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java index 219ba5887b7..641619e9a9c 100644 --- a/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java +++ b/forge-gui-desktop/src/main/java/forge/view/arcane/CardPanel.java @@ -21,7 +21,6 @@ import forge.CachedCardImage; import forge.FThreads; import forge.StaticData; import forge.card.CardEdition; -import forge.card.CardTranslation; import forge.card.mana.ManaCost; import forge.game.card.Card; import forge.game.card.CardView; @@ -39,6 +38,7 @@ import forge.screens.match.CMatchUI; import forge.toolbox.CardFaceSymbols; import forge.toolbox.FSkin.SkinnedPanel; import forge.toolbox.IDisposable; +import forge.util.CardTranslation; import forge.view.arcane.util.OutlinedLabel; import javax.swing.*; diff --git a/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java b/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java index 0c92e4716ef..1fd4c78d83e 100644 --- a/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java +++ b/forge-gui-desktop/src/test/java/forge/ai/simulation/GameSimulatorTest.java @@ -1284,7 +1284,7 @@ public class GameSimulatorTest extends SimulationTestCase { Game simGame = sim.getSimulatedGameState(); int numZombies = countCardsWithName(simGame, "Zombie"); - assertTrue(numZombies == 2); + assertEquals(2, numZombies); } public void testKalitasNumberOfTokens() { @@ -1309,7 +1309,7 @@ public class GameSimulatorTest extends SimulationTestCase { assertNotNull(fatalPushSA); fatalPushSA.setTargetCard(goblin); - // Electrify: should only generate 1 token + // Electrify: should also generate 2 tokens after the Ixalan rules update Card electrify = addCardToZone("Electrify", p, ZoneType.Hand); SpellAbility electrifySA = electrify.getFirstSpellAbility(); assertNotNull(electrifySA); @@ -1318,11 +1318,11 @@ public class GameSimulatorTest extends SimulationTestCase { GameSimulator sim = createSimulator(game, p); int score = sim.simulateSpellAbility(fatalPushSA).value; assertTrue(score > 0); - assertTrue(countCardsWithName(sim.getSimulatedGameState(), "Zombie") == 2); + assertEquals(2, countCardsWithName(sim.getSimulatedGameState(), "Zombie")); score = sim.simulateSpellAbility(electrifySA).value; assertTrue(score > 0); - assertTrue(countCardsWithName(sim.getSimulatedGameState(), "Zombie") == 3); + assertEquals(countCardsWithName(sim.getSimulatedGameState(), "Zombie"), 4); } public void testPlayerXCount() { @@ -1531,7 +1531,7 @@ public class GameSimulatorTest extends SimulationTestCase { assertNotNull(simGoblin); int effects = simGoblin.getCounters(CounterType.P1P1) + simGoblin.getKeywordMagnitude(Keyword.HASTE); - assertTrue(effects == 2); + assertEquals(2, effects); } public void testTeysaKarlovXathridNecromancer() { @@ -1560,7 +1560,7 @@ public class GameSimulatorTest extends SimulationTestCase { Game simGame = sim.getSimulatedGameState(); int numZombies = countCardsWithName(simGame, "Zombie"); - assertTrue(numZombies == 4); + assertEquals(4, numZombies); } public void testDoubleTeysaKarlovXathridNecromancer() { @@ -1588,7 +1588,7 @@ public class GameSimulatorTest extends SimulationTestCase { Game simGame = sim.getSimulatedGameState(); int numZombies = countCardsWithName(simGame, "Zombie"); - assertTrue(numZombies == 3); + assertEquals(3, numZombies); } @@ -1619,7 +1619,7 @@ public class GameSimulatorTest extends SimulationTestCase { Game simGame = sim.getSimulatedGameState(); // Two cards drawn - assertTrue(simGame.getPlayers().get(0).getZone(ZoneType.Hand).size() == 2); + assertEquals(2, simGame.getPlayers().get(0).getZone(ZoneType.Hand).size()); } public void testTeysaKarlovGitrogMonsterGitrogDies() { @@ -1657,7 +1657,7 @@ public class GameSimulatorTest extends SimulationTestCase { Game simGame = sim.getSimulatedGameState(); // One cards drawn - assertTrue(simGame.getPlayers().get(0).getZone(ZoneType.Hand).size() == 1); + assertEquals(1, simGame.getPlayers().get(0).getZone(ZoneType.Hand).size()); } public void testTeysaKarlovGitrogMonsterTeysaDies() { @@ -1695,7 +1695,7 @@ public class GameSimulatorTest extends SimulationTestCase { Game simGame = sim.getSimulatedGameState(); // One cards drawn - assertTrue(simGame.getPlayers().get(0).getZone(ZoneType.Hand).size() == 1); + assertEquals(1, simGame.getPlayers().get(0).getZone(ZoneType.Hand).size()); } @@ -1742,9 +1742,9 @@ public class GameSimulatorTest extends SimulationTestCase { Game simGame = sim.getSimulatedGameState(); - assertTrue(countCardsWithName(simGame, outLawName) == 0); - assertTrue(countCardsWithName(simGame, hillGiantName) == 2); - assertTrue(countCardsWithName(simGame, terrorName) == 0); + assertEquals(0, countCardsWithName(simGame, outLawName)); + assertEquals(2, countCardsWithName(simGame, hillGiantName)); + assertEquals(0, countCardsWithName(simGame, terrorName)); Card clonedOutLaw = (Card)sim.getGameCopier().find(outlaw); @@ -1754,7 +1754,7 @@ public class GameSimulatorTest extends SimulationTestCase { assertTrue(clonedOutLaw.canTransform()); assertFalse(clonedOutLaw.isBackSide()); - assertTrue(clonedOutLaw.getName().equals(hillGiantName)); + assertEquals(clonedOutLaw.getName(), hillGiantName); assertTrue(clonedOutLaw.isDoubleFaced()); @@ -1763,9 +1763,9 @@ public class GameSimulatorTest extends SimulationTestCase { simGame = sim.getSimulatedGameState(); - assertTrue(countCardsWithName(simGame, outLawName) == 0); - assertTrue(countCardsWithName(simGame, hillGiantName) == 2); - assertTrue(countCardsWithName(simGame, terrorName) == 0); + assertEquals(0, countCardsWithName(simGame, outLawName)); + assertEquals(2, countCardsWithName(simGame, hillGiantName)); + assertEquals(0, countCardsWithName(simGame, terrorName)); Card transformOutLaw = (Card)sim.getGameCopier().find(outlaw); @@ -1775,14 +1775,14 @@ public class GameSimulatorTest extends SimulationTestCase { assertTrue(transformOutLaw.canTransform()); assertTrue(transformOutLaw.isBackSide()); - assertTrue(transformOutLaw.getName().equals(hillGiantName)); + assertEquals(transformOutLaw.getName(), hillGiantName); // need to clean up the clone state simGame.getPhaseHandler().devAdvanceToPhase(PhaseType.CLEANUP); - assertTrue(countCardsWithName(simGame, outLawName) == 0); - assertTrue(countCardsWithName(simGame, hillGiantName) == 1); - assertTrue(countCardsWithName(simGame, terrorName) == 1); + assertEquals(0, countCardsWithName(simGame, outLawName)); + assertEquals(1, countCardsWithName(simGame, hillGiantName)); + assertEquals(1, countCardsWithName(simGame, terrorName)); assertFalse(transformOutLaw.isCloned()); assertTrue(transformOutLaw.isDoubleFaced()); @@ -1790,7 +1790,7 @@ public class GameSimulatorTest extends SimulationTestCase { assertTrue(transformOutLaw.canTransform()); assertTrue(transformOutLaw.isBackSide()); - assertTrue(transformOutLaw.getName().equals(terrorName)); + assertEquals(transformOutLaw.getName(), terrorName); } public void testVolrathsShapeshifter() { @@ -1808,9 +1808,9 @@ public class GameSimulatorTest extends SimulationTestCase { addCardToZone("Abattoir Ghoul", p, ZoneType.Graveyard); game.getAction().checkStateEffects(true); - assertTrue(volrath.getName().equals("Abattoir Ghoul")); - assertTrue(volrath.getNetPower() == 3); - assertTrue(volrath.getNetToughness() == 2); + assertEquals("Abattoir Ghoul", volrath.getName()); + assertEquals(3, volrath.getNetPower()); + assertEquals(2, volrath.getNetToughness()); assertTrue(volrath.hasKeyword(Keyword.FIRST_STRIKE)); SpellAbility discardAfterCopy = findSAWithPrefix(volrath, "{2}"); @@ -1820,9 +1820,9 @@ public class GameSimulatorTest extends SimulationTestCase { addCardToZone("Plains", p, ZoneType.Graveyard); game.getAction().checkStateEffects(true); - assertTrue(volrath.getName().equals("Volrath's Shapeshifter")); - assertTrue(volrath.getNetPower() == 0); - assertTrue(volrath.getNetToughness() == 1); + assertEquals("Volrath's Shapeshifter", volrath.getName()); + assertEquals(0, volrath.getNetPower()); + assertEquals(1, volrath.getNetToughness()); assertTrue(volrath.getKeywords().isEmpty()); SpellAbility discardAfterRevert = findSAWithPrefix(volrath, "{2}"); @@ -1850,9 +1850,9 @@ public class GameSimulatorTest extends SimulationTestCase { Card simSpark = (Card)sim.getGameCopier().find(sparkDouble); assertNotNull(simSpark); - assertTrue(simSpark.getZone().is(ZoneType.Battlefield)); - assertTrue(simSpark.getCounters(CounterType.P1P1) == 1); - assertTrue(simSpark.getCounters(CounterType.LOYALTY) == 5); + assertTrue(simSpark.isInZone(ZoneType.Battlefield)); + assertEquals(1, simSpark.getCounters(CounterType.P1P1)); + assertEquals(5, simSpark.getCounters(CounterType.LOYALTY)); } public void testVituGhaziAndCytoshape() { @@ -1883,8 +1883,8 @@ public class GameSimulatorTest extends SimulationTestCase { Card awakened = findCardWithName(sim.getSimulatedGameState(), "Vitu-Ghazi"); assertNotNull(awakened); - assertTrue(awakened.getName().equals("Vitu-Ghazi")); - assertTrue(awakened.getCounters(CounterType.P1P1) == 9); + assertEquals("Vitu-Ghazi", awakened.getName()); + assertEquals(9, awakened.getCounters(CounterType.P1P1)); assertTrue(awakened.hasKeyword(Keyword.HASTE)); assertTrue(awakened.getType().hasSubtype("Goblin")); } @@ -1910,7 +1910,7 @@ public class GameSimulatorTest extends SimulationTestCase { SpellAbility copiedSA = findSAWithPrefix(oozeOTB, "{1}{G}:"); assertNotNull(copiedSA); - assertTrue(copiedSA.getRestrictions().getLimitToCheck().equals("1")); + assertEquals("1", copiedSA.getRestrictions().getLimitToCheck()); } public void testEpochrasite() { @@ -1932,7 +1932,7 @@ public class GameSimulatorTest extends SimulationTestCase { Card epoOTB = findCardWithName(sim.getSimulatedGameState(), "Epochrasite"); assertNotNull(epoOTB); - assertTrue(epoOTB.getCounters(CounterType.P1P1) == 3); + assertEquals(3, epoOTB.getCounters(CounterType.P1P1)); } @SuppressWarnings("unused") @@ -1967,9 +1967,9 @@ public class GameSimulatorTest extends SimulationTestCase { assertTrue(score > 0); Card dimirdgAfterCopy1 = (Card)sim.getGameCopier().find(dimirdg); - assertTrue(dimirdgAfterCopy1.getName().equals("Jushi Apprentice")); - assertTrue(dimirdgAfterCopy1.getNetPower() == 1); - assertTrue(dimirdgAfterCopy1.getNetToughness() == 2); + assertEquals("Jushi Apprentice", dimirdgAfterCopy1.getName()); + assertEquals(1, dimirdgAfterCopy1.getNetPower()); + assertEquals(2, dimirdgAfterCopy1.getNetToughness()); assertTrue(dimirdgAfterCopy1.isFlipCard()); assertFalse(dimirdgAfterCopy1.isFlipped()); assertFalse(dimirdgAfterCopy1.getType().isLegendary()); @@ -1982,7 +1982,7 @@ public class GameSimulatorTest extends SimulationTestCase { Player copiedPlayer = (Player)sim.getGameCopier().find(p); int handSize = copiedPlayer.getCardsIn(ZoneType.Hand).size(); - assertTrue(handSize == 9); + assertEquals(9, handSize); SpellAbility draw = findSAWithPrefix(dimirdgAfterCopy1, "{2}{U}"); score = sim.simulateSpellAbility(draw).value; @@ -1990,7 +1990,7 @@ public class GameSimulatorTest extends SimulationTestCase { copiedPlayer = (Player)sim.getGameCopier().find(p); handSize = copiedPlayer.getCardsIn(ZoneType.Hand).size(); - assertTrue(handSize == 10); + assertEquals(10, handSize); simGame = sim.getSimulatedGameState(); @@ -2006,9 +2006,9 @@ public class GameSimulatorTest extends SimulationTestCase { Card dimirdgAfterFlip1 = (Card)sim.getGameCopier().find(dimirdgAfterCopy1); - assertTrue(dimirdgAfterFlip1.getName().equals("Tomoya the Revealer")); - assertTrue(dimirdgAfterFlip1.getNetPower() == 2); - assertTrue(dimirdgAfterFlip1.getNetToughness() == 3); + assertEquals("Tomoya the Revealer", dimirdgAfterFlip1.getName()); + assertEquals(2, dimirdgAfterFlip1.getNetPower()); + assertEquals(3, dimirdgAfterFlip1.getNetToughness()); assertTrue(dimirdgAfterFlip1.isFlipped()); assertTrue(dimirdgAfterFlip1.getType().isLegendary()); @@ -2030,9 +2030,9 @@ public class GameSimulatorTest extends SimulationTestCase { System.out.println(dimirdgAfterCopy2.isFlipCard()); System.out.println(dimirdgAfterCopy2.isFlipped()); - assertTrue(dimirdgAfterCopy2.getName().equals("Runeclaw Bear")); - assertTrue(dimirdgAfterCopy2.getNetPower() == 2); - assertTrue(dimirdgAfterCopy2.getNetToughness() == 2); + assertEquals("Runeclaw Bear", dimirdgAfterCopy2.getName()); + assertEquals(2, dimirdgAfterCopy2.getNetPower()); + assertEquals(2, dimirdgAfterCopy2.getNetToughness()); assertTrue(dimirdgAfterCopy2.isFlipped()); assertFalse(dimirdgAfterCopy2.getType().isLegendary()); } @@ -2049,11 +2049,11 @@ public class GameSimulatorTest extends SimulationTestCase { // update stats state game.getAction().checkStateEffects(true); - assertTrue(c1.getNetPower() == 4); - assertTrue(c1.getNetToughness() == 4); + assertEquals(4, c1.getNetPower()); + assertEquals(4, c1.getNetToughness()); - assertTrue(c2.getNetPower() == 4); - assertTrue(c2.getNetToughness() == 4); + assertEquals(4, c2.getNetPower()); + assertEquals(4, c2.getNetToughness()); } public void testPathtoExileActofTreason() { @@ -2090,7 +2090,37 @@ public class GameSimulatorTest extends SimulationTestCase { simGame.getAction().checkStateEffects(true); int numForest = countCardsWithName(simGame, "Forest"); - assertTrue(numForest == 1); + assertEquals(1, numForest); assertEquals(0, simGame.getPlayers().get(1).getCardsIn(ZoneType.Battlefield).size()); } + + public void testAmassTrigger() { + Game game = initAndCreateGame(); + Player p = game.getPlayers().get(0); + String WCname = "Woodland Champion"; + addCard(WCname, p); + for (int i = 0; i < 5; i++) + addCard("Island", p); + + String CardName = "Eternal Skylord"; + Card c = addCardToZone(CardName, p, ZoneType.Hand); + game.getPhaseHandler().devModeSet(PhaseType.MAIN1, p); + game.getAction().checkStateEffects(true); + + SpellAbility playSa = c.getSpellAbilities().get(0); + playSa.setActivatingPlayer(p); + + GameSimulator sim = createSimulator(game, p); + int origScore = sim.getScoreForOrigGame().value; + int score = sim.simulateSpellAbility(playSa).value; + assertTrue(String.format("score=%d vs. origScore=%d", score, origScore), score > origScore); + + Game simGame = sim.getSimulatedGameState(); + + Card simWC = findCardWithName(simGame, WCname); + + assertEquals(1, simWC.getPowerBonusFromCounters()); + assertEquals(3, simGame.getPlayers().get(0).getCreaturesInPlay().size()); + + } } diff --git a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java index 4e3b48f2917..f1906ebdb0f 100644 --- a/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java +++ b/forge-gui-desktop/src/test/java/forge/gamesimulationtests/util/PlayerControllerForTests.java @@ -506,7 +506,7 @@ public class PlayerControllerForTests extends PlayerController { } @Override - public ReplacementEffect chooseSingleReplacementEffect(String prompt, List possibleReplacers, Map runParams) { + public ReplacementEffect chooseSingleReplacementEffect(String prompt, List possibleReplacers) { // TODO Auto-generated method stub return Iterables.getFirst(possibleReplacers, null); } diff --git a/forge-gui-ios/libs/gdx-backend-robovm-sources.jar b/forge-gui-ios/libs/gdx-backend-robovm-sources.jar index de757050e91..1ed5c6f5486 100644 Binary files a/forge-gui-ios/libs/gdx-backend-robovm-sources.jar and b/forge-gui-ios/libs/gdx-backend-robovm-sources.jar differ diff --git a/forge-gui-ios/libs/gdx-backend-robovm.jar b/forge-gui-ios/libs/gdx-backend-robovm.jar index 13e11a2c091..cbf789dd7b1 100644 Binary files a/forge-gui-ios/libs/gdx-backend-robovm.jar and b/forge-gui-ios/libs/gdx-backend-robovm.jar differ diff --git a/forge-gui-ios/libs/gdx-sources.jar b/forge-gui-ios/libs/gdx-sources.jar index ca6c8a53100..798fee80a7b 100644 Binary files a/forge-gui-ios/libs/gdx-sources.jar and b/forge-gui-ios/libs/gdx-sources.jar differ diff --git a/forge-gui-ios/libs/gdx.jar b/forge-gui-ios/libs/gdx.jar index 7d93f8ba6b3..0ba4a3f2bb4 100644 Binary files a/forge-gui-ios/libs/gdx.jar and b/forge-gui-ios/libs/gdx.jar differ diff --git a/forge-gui-ios/libs/libObjectAL.a b/forge-gui-ios/libs/libObjectAL.a index 671fe0f4107..6113d44ffc9 100644 Binary files a/forge-gui-ios/libs/libObjectAL.a and b/forge-gui-ios/libs/libObjectAL.a differ diff --git a/forge-gui-ios/libs/libgdx-freetype.a b/forge-gui-ios/libs/libgdx-freetype.a index 10d04063a66..67ed332cb29 100644 Binary files a/forge-gui-ios/libs/libgdx-freetype.a and b/forge-gui-ios/libs/libgdx-freetype.a differ diff --git a/forge-gui-ios/libs/libgdx.a b/forge-gui-ios/libs/libgdx.a index 6e7ffbc168c..038693b6c84 100644 Binary files a/forge-gui-ios/libs/libgdx.a and b/forge-gui-ios/libs/libgdx.a differ diff --git a/forge-gui-ios/pom.xml b/forge-gui-ios/pom.xml index 21539d4c17e..8cf1da9d802 100644 --- a/forge-gui-ios/pom.xml +++ b/forge-gui-ios/pom.xml @@ -6,13 +6,13 @@ jar -Xms128m -Xmx2048m - 1.6.29.001 + 1.6.30.001 forge forge - 1.6.30-SNAPSHOT + 1.6.31-SNAPSHOT forge-gui-ios @@ -75,5 +75,23 @@ gdx-backend-robovm 1.9.10 + + org.cache2k + cache2k-base-bom + 1.2.4.Final + pom + + + org.cache2k + cache2k-core + 1.2.4.Final + compile + + + org.cache2k + cache2k-api + 1.2.4.Final + compile + diff --git a/forge-gui-ios/src/forge/ios/Main.java b/forge-gui-ios/src/forge/ios/Main.java index bad9865e574..689e07d6fa7 100644 --- a/forge-gui-ios/src/forge/ios/Main.java +++ b/forge-gui-ios/src/forge/ios/Main.java @@ -29,7 +29,7 @@ public class Main extends IOSApplication.Delegate { final IOSApplicationConfiguration config = new IOSApplicationConfiguration(); config.useAccelerometer = false; config.useCompass = false; - final ApplicationListener app = Forge.getApp(new IOSClipboard(), new IOSAdapter(), assetsDir); + final ApplicationListener app = Forge.getApp(new IOSClipboard(), new IOSAdapter(), assetsDir, false); final IOSApplication iosApp = new IOSApplication(app, config); return iosApp; } diff --git a/forge-gui-mobile-dev/libs/gdx-backend-lwjgl-sources.jar b/forge-gui-mobile-dev/libs/gdx-backend-lwjgl-sources.jar index 5a9f4b59ad6..f736a822dd8 100644 Binary files a/forge-gui-mobile-dev/libs/gdx-backend-lwjgl-sources.jar and b/forge-gui-mobile-dev/libs/gdx-backend-lwjgl-sources.jar differ diff --git a/forge-gui-mobile-dev/libs/gdx-backend-lwjgl.jar b/forge-gui-mobile-dev/libs/gdx-backend-lwjgl.jar index 7b1bc3d1143..d1699805b6d 100644 Binary files a/forge-gui-mobile-dev/libs/gdx-backend-lwjgl.jar and b/forge-gui-mobile-dev/libs/gdx-backend-lwjgl.jar differ diff --git a/forge-gui-mobile-dev/libs/gdx-freetype-natives.jar b/forge-gui-mobile-dev/libs/gdx-freetype-natives.jar index c338f9fa739..025707e2973 100644 Binary files a/forge-gui-mobile-dev/libs/gdx-freetype-natives.jar and b/forge-gui-mobile-dev/libs/gdx-freetype-natives.jar differ diff --git a/forge-gui-mobile-dev/libs/gdx-natives.jar b/forge-gui-mobile-dev/libs/gdx-natives.jar index efba8c4ab2e..18f0fbc3dcf 100644 Binary files a/forge-gui-mobile-dev/libs/gdx-natives.jar and b/forge-gui-mobile-dev/libs/gdx-natives.jar differ diff --git a/forge-gui-mobile-dev/pom.xml b/forge-gui-mobile-dev/pom.xml index c515dd9a240..f74a9df9b2b 100644 --- a/forge-gui-mobile-dev/pom.xml +++ b/forge-gui-mobile-dev/pom.xml @@ -4,7 +4,7 @@ forge forge - 1.6.30-SNAPSHOT + 1.6.31-SNAPSHOT forge-gui-mobile-dev @@ -80,5 +80,23 @@ commons-cli 1.4 + + org.cache2k + cache2k-base-bom + 1.2.4.Final + pom + + + org.cache2k + cache2k-core + 1.2.4.Final + compile + + + org.cache2k + cache2k-api + 1.2.4.Final + compile + diff --git a/forge-gui-mobile-dev/src/forge/app/Main.java b/forge-gui-mobile-dev/src/forge/app/Main.java index d80bc49cdae..8f2de339592 100644 --- a/forge-gui-mobile-dev/src/forge/app/Main.java +++ b/forge-gui-mobile-dev/src/forge/app/Main.java @@ -93,7 +93,7 @@ public class Main { config.useHDPI = desktopMode; // enable HiDPI on Mac OS new LwjglApplication(Forge.getApp(new LwjglClipboard(), new DesktopAdapter(switchOrientationFile), - desktopMode ? desktopModeAssetsDir : assetsDir), config); + desktopMode ? desktopModeAssetsDir : assetsDir, true), config); } private static class DesktopAdapter implements IDeviceAdapter { diff --git a/forge-gui-mobile/libs/gdx-freetype.jar b/forge-gui-mobile/libs/gdx-freetype.jar index cff324ecd35..eda8b39b168 100644 Binary files a/forge-gui-mobile/libs/gdx-freetype.jar and b/forge-gui-mobile/libs/gdx-freetype.jar differ diff --git a/forge-gui-mobile/libs/gdx-sources.jar b/forge-gui-mobile/libs/gdx-sources.jar index ca6c8a53100..798fee80a7b 100644 Binary files a/forge-gui-mobile/libs/gdx-sources.jar and b/forge-gui-mobile/libs/gdx-sources.jar differ diff --git a/forge-gui-mobile/libs/gdx.jar b/forge-gui-mobile/libs/gdx.jar index 7d93f8ba6b3..0ba4a3f2bb4 100644 Binary files a/forge-gui-mobile/libs/gdx.jar and b/forge-gui-mobile/libs/gdx.jar differ diff --git a/forge-gui-mobile/pom.xml b/forge-gui-mobile/pom.xml index a3e0183dd9c..bc4bfd7b379 100644 --- a/forge-gui-mobile/pom.xml +++ b/forge-gui-mobile/pom.xml @@ -4,7 +4,7 @@ forge forge - 1.6.30-SNAPSHOT + 1.6.31-SNAPSHOT forge-gui-mobile @@ -48,17 +48,17 @@ com.google.guava guava - 24.1-android + 28.1-android com.thoughtworks.xstream xstream - 1.4.7 + 1.4.9 org.apache.commons commons-lang3 - 3.7 + 3.8.1 com.badlogicgames.gdx @@ -70,6 +70,24 @@ gdx-freetype 1.9.10 + + org.cache2k + cache2k-base-bom + 1.2.4.Final + pom + + + org.cache2k + cache2k-core + 1.2.4.Final + compile + + + org.cache2k + cache2k-api + 1.2.4.Final + compile + diff --git a/forge-gui-mobile/src/forge/Forge.java b/forge-gui-mobile/src/forge/Forge.java index 6489dc33bd4..400e86dc1ec 100644 --- a/forge-gui-mobile/src/forge/Forge.java +++ b/forge-gui-mobile/src/forge/Forge.java @@ -10,7 +10,6 @@ import forge.assets.AssetsDownloader; import forge.assets.FSkin; import forge.assets.FSkinFont; import forge.assets.ImageCache; -import forge.card.CardTranslation; import forge.error.BugReporter; import forge.error.ExceptionHandler; import forge.interfaces.IDeviceAdapter; @@ -31,16 +30,19 @@ import forge.toolbox.FGestureAdapter; import forge.toolbox.FOptionPane; import forge.toolbox.FOverlay; import forge.util.Callback; +import forge.util.CardTranslation; import forge.util.FileUtil; import forge.util.Localizer; import forge.util.Utils; +import java.io.File; +import java.io.FileFilter; import java.util.ArrayList; import java.util.List; import java.util.Stack; public class Forge implements ApplicationListener { - public static final String CURRENT_VERSION = "1.6.29.001"; + public static final String CURRENT_VERSION = "1.6.30.001"; private static final ApplicationListener app = new Forge(); private static Clipboard clipboard; @@ -48,6 +50,7 @@ public class Forge implements ApplicationListener { private static int screenWidth; private static int screenHeight; private static Graphics graphics; + private static FrameRate frameRate; private static FScreen currentScreen; private static SplashScreen splashScreen; private static KeyInputAdapter keyInputAdapter; @@ -59,12 +62,17 @@ public class Forge implements ApplicationListener { public static String extrawide = "default"; public static float heigtModifier = 0.0f; private static boolean isloadingaMatch = false; + public static boolean showFPS = false; + public static boolean enableUIMask = false; + public static boolean enablePreloadExtendedArt = false; + public static String locale = "en-US"; - public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0) { + public static ApplicationListener getApp(Clipboard clipboard0, IDeviceAdapter deviceAdapter0, String assetDir0, boolean value) { if (GuiBase.getInterface() == null) { clipboard = clipboard0; deviceAdapter = deviceAdapter0; GuiBase.setInterface(new GuiMobile(assetDir0)); + GuiBase.enablePropertyConfig(value); } return app; } @@ -79,6 +87,7 @@ public class Forge implements ApplicationListener { graphics = new Graphics(); splashScreen = new SplashScreen(); + frameRate = new FrameRate(); Gdx.input.setInputProcessor(new MainInputProcessor()); /* Set CatchBackKey here and exit the app when you hit the @@ -100,6 +109,10 @@ public class Forge implements ApplicationListener { FSkin.loadLight(skinName, splashScreen); textureFiltering = prefs.getPrefBoolean(FPref.UI_LIBGDX_TEXTURE_FILTERING); + showFPS = prefs.getPrefBoolean(FPref.UI_SHOW_FPS); + enableUIMask = prefs.getPrefBoolean(FPref.UI_ENABLE_BORDER_MASKING); + enablePreloadExtendedArt = prefs.getPrefBoolean(FPref.UI_ENABLE_PRELOAD_EXTENDED_ART); + locale = prefs.getPref(FPref.UI_LANGUAGE); final Localizer localizer = Localizer.getInstance(); @@ -114,23 +127,53 @@ public class Forge implements ApplicationListener { FModel.initialize(splashScreen.getProgressBar(), null); splashScreen.getProgressBar().setDescription(localizer.getMessage("lblLoadingFonts")); - FSkinFont.preloadAll(); + FSkinFont.preloadAll(locale); splashScreen.getProgressBar().setDescription(localizer.getMessage("lblLoadingCardTranslations")); - CardTranslation.preloadTranslation(prefs.getPref(FPref.UI_LANGUAGE)); + CardTranslation.preloadTranslation(locale, ForgeConstants.LANG_DIR); splashScreen.getProgressBar().setDescription(localizer.getMessage("lblFinishingStartup")); + //add reminder to preload + if (enablePreloadExtendedArt) + splashScreen.getProgressBar().setDescription(localizer.getMessage("lblPreloadExtendedArt")); Gdx.app.postRunnable(new Runnable() { @Override public void run() { afterDbLoaded(); + /* call preloadExtendedArt here, if we put it above we will * + * get error: No OpenGL context found in the current thread. */ + preloadExtendedArt(); } }); } }); } + private void preloadExtendedArt() { + if (!enablePreloadExtendedArt) + return; + List keys = new ArrayList<>(); + File[] directories = new File(ForgeConstants.CACHE_CARD_PICS_DIR).listFiles(new FileFilter() { + @Override + public boolean accept(File file) { + if (!file.getName().startsWith("MPS_")) + return false; + return file.isDirectory(); + } + }); + for (File folder : directories) { + File[] files = new File(folder.toString()).listFiles(); + for (File file : files) { + if (file.isFile()) { + keys.add(folder.getName() + "/" +file.getName().replace(".jpg","").replace(".png","")); + } + } + } + if (!keys.isEmpty()) + ImageCache.preloadCache((Iterable)keys); + } + private void afterDbLoaded() { stopContinuousRendering(); //save power consumption by disabling continuous rendering once assets loaded @@ -366,6 +409,9 @@ public class Forge implements ApplicationListener { @Override public void render() { + if (showFPS) + frameRate.update(); + try { ImageCache.allowSingleLoad(); ForgeAnimation.advanceAll(); @@ -408,6 +454,8 @@ public class Forge implements ApplicationListener { graphics.end(); BugReporter.reportException(ex); } + if (showFPS) + frameRate.render(); } @Override diff --git a/forge-gui-mobile/src/forge/FrameRate.java b/forge-gui-mobile/src/forge/FrameRate.java new file mode 100644 index 00000000000..3c11b521d0b --- /dev/null +++ b/forge-gui-mobile/src/forge/FrameRate.java @@ -0,0 +1,62 @@ +package forge; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.utils.Disposable; +import com.badlogic.gdx.utils.TimeUtils; + +/** + * A nicer class for showing framerate that doesn't spam the console + * like Logger.log() + * + * @author William Hartman + */ + +public class FrameRate implements Disposable{ + long lastTimeCounted; + private float sinceChange; + private float frameRate; + private BitmapFont font; + private SpriteBatch batch; + private OrthographicCamera cam; + + public FrameRate() { + lastTimeCounted = TimeUtils.millis(); + sinceChange = 0; + frameRate = Gdx.graphics.getFramesPerSecond(); + font = new BitmapFont(); + batch = new SpriteBatch(); + cam = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + } + + public void resize(int screenWidth, int screenHeight) { + cam = new OrthographicCamera(screenWidth, screenHeight); + cam.translate(screenWidth / 2, screenHeight / 2); + cam.update(); + batch.setProjectionMatrix(cam.combined); + } + + public void update() { + long delta = TimeUtils.timeSinceMillis(lastTimeCounted); + lastTimeCounted = TimeUtils.millis(); + sinceChange += delta; + if(sinceChange >= 1000) { + sinceChange = 0; + frameRate = Gdx.graphics.getFramesPerSecond(); + } + } + + public void render() { + batch.begin(); + font.draw(batch, (int)frameRate + " fps", 3, Gdx.graphics.getHeight() - 3); + batch.end(); + } + + public void dispose() { + font.dispose(); + batch.dispose(); + } + +} \ No newline at end of file diff --git a/forge-gui-mobile/src/forge/Graphics.java b/forge-gui-mobile/src/forge/Graphics.java index fd314326040..366eecc54bf 100644 --- a/forge-gui-mobile/src/forge/Graphics.java +++ b/forge-gui-mobile/src/forge/Graphics.java @@ -292,6 +292,11 @@ public class Graphics { return index + 2; } + public void drawfillBorder(float thickness, Color color, float x, float y, float w, float h, float cornerRadius) { + drawRoundRect(thickness, color, x, y, w, h, cornerRadius); + fillRoundRect(color, x, y, w, h, cornerRadius); + } + public void drawRoundRect(float thickness, FSkinColor skinColor, float x, float y, float w, float h, float cornerRadius) { drawRoundRect(thickness, skinColor.getColor(), x, y, w, h, cornerRadius); } @@ -312,21 +317,18 @@ public class Graphics { } //adjust width/height so rectangle covers equivalent filled area - w = Math.round(w - 1); - h = Math.round(h - 1); + w = Math.round(w + 1); + h = Math.round(h + 1); startShape(ShapeType.Line); shapeRenderer.setColor(color); - x = adjustX(x); - float y2 = adjustY(y, h); - float x2 = x + w; - y = y2 + h; - //TODO: draw arcs at corners - shapeRenderer.line(x, y, x, y2); - shapeRenderer.line(x, y2, x2 + 1, y2); //+1 prevents corner not being filled - shapeRenderer.line(x2, y2, x2, y); - shapeRenderer.line(x2 + 1, y, x, y); //+1 prevents corner not being filled + shapeRenderer.arc(adjustX(x) + cornerRadius, adjustY(y + cornerRadius, 0), cornerRadius, 90f, 90f); + shapeRenderer.arc(adjustX(x) + w - cornerRadius, adjustY(y + cornerRadius, 0), cornerRadius, 0f, 90f); + shapeRenderer.arc(adjustX(x) + w - cornerRadius, adjustY(y + h - cornerRadius, 0), cornerRadius, 270, 90f); + shapeRenderer.arc(adjustX(x) + cornerRadius, adjustY(y + h - cornerRadius, 0), cornerRadius, 180, 90f); + shapeRenderer.rect(adjustX(x), adjustY(y+cornerRadius, h-cornerRadius*2), w, h-cornerRadius*2); + shapeRenderer.rect(adjustX(x+cornerRadius), adjustY(y, h), w-cornerRadius*2, h); endShape(); @@ -343,6 +345,32 @@ public class Graphics { batch.begin(); } + public void fillRoundRect(FSkinColor skinColor, float x, float y, float w, float h, float cornerRadius) { + fillRoundRect(skinColor.getColor(), x, y, w, h, cornerRadius); + } + public void fillRoundRect(Color color, float x, float y, float w, float h, float cornerRadius) { + batch.end(); //must pause batch while rendering shapes + if (alphaComposite < 1) { + color = FSkinColor.alphaColor(color, color.a * alphaComposite); + } + if (color.a < 1) { //enable blending so alpha colored shapes work properly + Gdx.gl.glEnable(GL_BLEND); + } + startShape(ShapeType.Filled); + shapeRenderer.setColor(color); + shapeRenderer.arc(adjustX(x) + cornerRadius, adjustY(y + cornerRadius, 0), cornerRadius, 90f, 90f); + shapeRenderer.arc(adjustX(x) + w - cornerRadius, adjustY(y + cornerRadius, 0), cornerRadius, 0f, 90f); + shapeRenderer.arc(adjustX(x) + w - cornerRadius, adjustY(y + h - cornerRadius, 0), cornerRadius, 270, 90f); + shapeRenderer.arc(adjustX(x) + cornerRadius, adjustY(y + h - cornerRadius, 0), cornerRadius, 180, 90f); + shapeRenderer.rect(adjustX(x), adjustY(y+cornerRadius, h-cornerRadius*2), w, h-cornerRadius*2); + shapeRenderer.rect(adjustX(x+cornerRadius), adjustY(y, h), w-cornerRadius*2, h); + endShape(); + if (color.a < 1) { + Gdx.gl.glDisable(GL_BLEND); + } + batch.begin(); + } + public void drawRect(float thickness, FSkinColor skinColor, float x, float y, float w, float h) { drawRect(thickness, skinColor.getColor(), x, y, w, h); } @@ -535,6 +563,18 @@ public class Graphics { } public float getfloatAlphaComposite() { return alphaComposite; } + + public void drawBorderImage(FImage image, Color color, float x, float y, float w, float h, boolean tint) { + image.draw(this, x, y, w, h); + if(tint){ + float oldalpha = alphaComposite; + setAlphaComposite(0.8f); + drawRoundRect(2f, Color.WHITE, x, y, w, h, (h-w)/12); + setAlphaComposite(1f); + fillRoundRect(color, x, y, w, h, (h-w)/12); + setAlphaComposite(oldalpha); + } + } public void drawImage(FImage image, float x, float y, float w, float h) { drawImage(image, x, y, w, h, false); } diff --git a/forge-gui-mobile/src/forge/GuiMobile.java b/forge-gui-mobile/src/forge/GuiMobile.java index d56c764a639..3843b3c2cec 100644 --- a/forge-gui-mobile/src/forge/GuiMobile.java +++ b/forge-gui-mobile/src/forge/GuiMobile.java @@ -244,6 +244,14 @@ public class GuiMobile implements IGuiBase { return 0; } + @Override + public int getSleevesCount() { + if (FSkin.isLoaded()) { + return FSkin.getSleeves().size(); + } + return 0; + } + @Override public String showFileDialog(final String title, final String defaultDir) { return ForgeConstants.USER_GAMES_DIR + "Test.fgs"; //TODO: Show dialog diff --git a/forge-gui-mobile/src/forge/assets/BitmapFontWriter.java b/forge-gui-mobile/src/forge/assets/BitmapFontWriter.java index 05234d5b1d6..3bec04e875b 100644 --- a/forge-gui-mobile/src/forge/assets/BitmapFontWriter.java +++ b/forge-gui-mobile/src/forge/assets/BitmapFontWriter.java @@ -16,7 +16,6 @@ package forge.assets; - import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.PixmapIO; @@ -25,29 +24,30 @@ import com.badlogic.gdx.graphics.g2d.BitmapFont.Glyph; import com.badlogic.gdx.graphics.g2d.PixmapPacker.Page; import com.badlogic.gdx.utils.Array; -/** A utility to output BitmapFontData to a FNT file. This can be useful for caching the result from TrueTypeFont, for faster load - * times. - * - * The font format is from the AngelCodeFont BMFont tool. - * - * @author mattdesl AKA davedes */ - - /** * This file is 'borrowed' from gdx-tools in the libgdx source */ - public class BitmapFontWriter { +/** A utility to output BitmapFontData to a FNT file. This can be useful for caching the result from TrueTypeFont, for faster load + * times. + *

+ * The font file format is from the AngelCodeFont BMFont tool. + *

+ * Output is nearly identical to the FreeType settting in the Hiero tool {@Link com.badlogic.gdx.tools.hiero.Hiero}. BitmapFontWriter gives more flexibility, eg + * borders and shadows can be used. Hiero is able to avoid outputting the same glyph image more than once if multiple character + * codes have the exact same glyph. + * @author mattdesl AKA davedes */ +public class BitmapFontWriter { /** The output format. */ - public enum OutputFormat { - + public static enum OutputFormat { + /** AngelCodeFont text format */ Text, /** AngelCodeFont XML format */ - XML + XML; } - + /** The output format */ private static OutputFormat format = OutputFormat.Text; @@ -55,26 +55,25 @@ import com.badlogic.gdx.utils.Array; * Pixi.js). * * @param fmt the output format to use */ - public static void setOutputFormat(OutputFormat fmt) { - if (fmt==null) - throw new NullPointerException("format cannot be null"); + public static void setOutputFormat (OutputFormat fmt) { + if (fmt == null) throw new NullPointerException("format cannot be null"); format = fmt; } /** Returns the currently used output format. * @return the output format */ - public static OutputFormat getOutputFormat() { + public static OutputFormat getOutputFormat () { return format; } - + /** The Padding parameter for FontInfo. */ public static class Padding { public int up, down, left, right; - public Padding() { + public Padding () { } - - public Padding(int up, int down, int left, int right) { + + public Padding (int up, int down, int left, int right) { this.up = up; this.down = down; this.left = left; @@ -87,8 +86,8 @@ import com.badlogic.gdx.utils.Array; public int horizontal, vertical; } - /** The font "info" line; this will be ignored by LibGDX's BitmapFont reader, - * but useful for clean and organized output. */ + /** The font "info" line; everything except padding and override metrics are ignored by LibGDX's BitmapFont reader, it is otherwise just useful for + * clean and organized output. */ public static class FontInfo { /** Face name */ public String face; @@ -113,32 +112,55 @@ import com.badlogic.gdx.utils.Array; /** Horizontal/vertical spacing that was applied to font */ public Spacing spacing = new Spacing(); public int outline = 0; - - public FontInfo() { + + /** Override metrics */ + public boolean hasOverrideMetrics; + public float ascent; + public float descent; + public float down; + public float capHeight; + public float lineHeight; + public float spaceXAdvance; + public float xHeight; + + public FontInfo () { } - - public FontInfo(String face, int size) { + + public FontInfo (String face, int size) { this.face = face; this.size = size; } + + public void overrideMetrics (BitmapFontData data) { + hasOverrideMetrics = true; + ascent = data.ascent; + descent = data.descent; + down = data.down; + capHeight = data.capHeight; + lineHeight = data.lineHeight; + spaceXAdvance = data.spaceXadvance; + xHeight = data.xHeight; + } + } - - private static String quote(Object params) { + + private static String quote (Object params) { return quote(params, false); } - - private static String quote(Object params, boolean spaceAfter) { + + private static String quote (Object params, boolean spaceAfter) { if (BitmapFontWriter.getOutputFormat() == OutputFormat.XML) return "\"" + params.toString().trim() + "\"" + (spaceAfter ? " " : ""); else return params.toString(); } - /** Writes the given BitmapFontData to a file, using the specified pageRefs strings as the image paths for each texture - * page. The glyphs in BitmapFontData have a "page" id, which references the index of the pageRef you specify here. + /** Writes the given BitmapFontData to a file, using the specified pageRefs strings as the image paths for each + * texture page. The glyphs in BitmapFontData have a "page" id, which references the index of the pageRef you specify here. * * The FontInfo parameter is useful for cleaner output; such as including a size and font face name hint. However, it can be - * null to use default values. Ultimately, LibGDX ignores the "info" line when reading back fonts. + * null to use default values. LibGDX ignores most of the "info" line when reading back fonts, only padding is used. Padding + * also affects the size, location, and offset of the glyphs that are output. * * Likewise, the scaleW and scaleH are only for cleaner output. They are currently ignored by LibGDX's reader. For maximum * compatibility with other BMFont tools, you should use the width and height of your texture pages (each page should be the @@ -150,21 +172,22 @@ import com.badlogic.gdx.utils.Array; * @param info the optional info for the file header; can be null * @param scaleW the width of your texture pages * @param scaleH the height of your texture pages */ - public static void writeFont (BitmapFontData fontData, String[] pageRefs, FileHandle outFntFile, FontInfo info, int scaleW, int scaleH) { - if (info==null) { + public static void writeFont (BitmapFontData fontData, String[] pageRefs, FileHandle outFntFile, FontInfo info, int scaleW, + int scaleH) { + if (info == null) { info = new FontInfo(); info.face = outFntFile.nameWithoutExtension(); } - + int lineHeight = (int)fontData.lineHeight; int pages = pageRefs.length; int packed = 0; int base = (int)((fontData.capHeight) + (fontData.flipped ? -fontData.ascent : fontData.ascent)); OutputFormat fmt = BitmapFontWriter.getOutputFormat(); - boolean xml = fmt == OutputFormat.XML; - + boolean xml = fmt == OutputFormat.XML; + StringBuilder buf = new StringBuilder(); - + if (xml) { buf.append("\n"); } @@ -172,152 +195,129 @@ import com.badlogic.gdx.utils.Array; String xmlCloseSelf = xml ? "/>" : ""; String xmlTab = xml ? "\t" : ""; String xmlClose = xml ? ">" : ""; - + String xmlQuote = xml ? "\"" : ""; - String alphaChnlParams = - xml ? " alphaChnl=\"0\" redChnl=\"0\" greenChnl=\"0\" blueChnl=\"0\"" - : " alphaChnl=0 redChnl=0 greenChnl=0 blueChnl=0"; - //INFO LINE - - buf.append(xmlOpen) - .append("info face=\"") - .append(info.face==null ? "" : info.face.replaceAll("\"", "'")) - .append("\" size=").append( quote(info.size) ) - .append(" bold=").append( quote(info.bold ? 1 : 0) ) - .append(" italic=").append( quote(info.italic ? 1 : 0) ) - .append(" charset=\"").append(info.charset==null ? "" : info.charset) - .append("\" unicode=").append( quote(info.unicode ? 1 : 0) ) - .append(" stretchH=").append( quote(info.stretchH) ) - .append(" smooth=").append( quote(info.smooth ? 1 : 0) ) - .append(" aa=").append( quote(info.aa) ) - .append(" padding=") - .append(xmlQuote) - .append(info.padding.up).append(",") - .append(info.padding.down).append(",") - .append(info.padding.left).append(",") - .append(info.padding.right) - .append(xmlQuote) - .append(" spacing=") - .append(xmlQuote) - .append(info.spacing.horizontal).append(",") - .append(info.spacing.vertical) - .append(xmlQuote) - .append(xmlCloseSelf) + String alphaChnlParams = xml ? " alphaChnl=\"0\" redChnl=\"0\" greenChnl=\"0\" blueChnl=\"0\"" + : " alphaChnl=0 redChnl=0 greenChnl=0 blueChnl=0"; + + // INFO LINE + buf.append(xmlOpen).append("info face=\"").append(info.face == null ? "" : info.face.replaceAll("\"", "'")) + .append("\" size=").append(quote(info.size)).append(" bold=").append(quote(info.bold ? 1 : 0)).append(" italic=") + .append(quote(info.italic ? 1 : 0)).append(" charset=\"").append(info.charset == null ? "" : info.charset) + .append("\" unicode=").append(quote(info.unicode ? 1 : 0)).append(" stretchH=").append(quote(info.stretchH)) + .append(" smooth=").append(quote(info.smooth ? 1 : 0)).append(" aa=").append(quote(info.aa)).append(" padding=") + .append(xmlQuote).append(info.padding.up).append(",").append(info.padding.right).append(",").append(info.padding.down) + .append(",").append(info.padding.left).append(xmlQuote).append(" spacing=").append(xmlQuote) + .append(info.spacing.horizontal).append(",").append(info.spacing.vertical).append(xmlQuote).append(xmlCloseSelf) .append("\n"); - - //COMMON line - buf.append(xmlOpen) - .append("common lineHeight=").append( quote(lineHeight) ) - .append(" base=").append( quote(base) ) - .append(" scaleW=").append( quote(scaleW) ) - .append(" scaleH=").append( quote(scaleH) ) - .append(" pages=").append( quote(pages) ) - .append(" packed=").append( quote(packed) ) - .append(alphaChnlParams) - .append(xmlCloseSelf) - .append("\n"); - - if (xml) - buf.append("\t\n"); - - //PAGES - for (int i=0; i\n"); + + // PAGES + for (int i = 0; i < pageRefs.length; i++) { + buf.append(xmlTab).append(xmlOpen).append("page id=").append(quote(i)).append(" file=\"").append(pageRefs[i]) + .append("\"").append(xmlCloseSelf).append("\n"); } - - if (xml) - buf.append("\t\n"); - - //CHARS - Array glyphs = new Array<>(256); - for (int i=0; i\n"); + + // CHARS + Array glyphs = new Array(256); + for (int i = 0; i < fontData.glyphs.length; i++) { + if (fontData.glyphs[i] == null) continue; + + for (int j = 0; j < fontData.glyphs[i].length; j++) { + if (fontData.glyphs[i][j] != null) { glyphs.add(fontData.glyphs[i][j]); } } } - - buf.append(xmlOpen) - .append("chars count=").append(quote(glyphs.size)) - .append(xmlClose) - .append("\n"); - - //CHAR definitions - for (int i=0; i\n"); - - //KERNINGS + + if (xml) buf.append("\t\n"); + + // KERNINGS int kernCount = 0; - StringBuilder kernBuf = new StringBuilder(); + StringBuilder kernBuf = new StringBuilder(); for (int i = 0; i < glyphs.size; i++) { for (int j = 0; j < glyphs.size; j++) { Glyph first = glyphs.get(i); Glyph second = glyphs.get(j); int kern = first.getKerning((char)second.id); - if (kern!=0) { + if (kern != 0) { kernCount++; - kernBuf.append(xmlTab) - .append(xmlOpen) - .append("kerning first=").append(quote(first.id)) - .append(" second=").append(quote(second.id)) - .append(" amount=").append(quote(kern, true)) - .append(xmlCloseSelf) - .append("\n"); + kernBuf.append(xmlTab).append(xmlOpen).append("kerning first=").append(quote(first.id)).append(" second=") + .append(quote(second.id)).append(" amount=").append(quote(kern, true)).append(xmlCloseSelf).append("\n"); } } } - //KERN info - buf.append(xmlOpen) - .append("kernings count=").append(quote(kernCount)) - .append(xmlClose) - .append("\n"); + // KERN info + buf.append(xmlOpen).append("kernings count=").append(quote(kernCount)).append(xmlClose).append("\n"); buf.append(kernBuf); - + if (xml) { buf.append("\t\n"); + } + + // Override metrics + if (info.hasOverrideMetrics) { + if (xml) buf.append("\t\n"); + + buf.append(xmlTab).append(xmlOpen) + .append("metrics ascent=").append(quote(info.ascent, true)) + .append(" descent=").append(quote(info.descent, true)) + .append(" down=").append(quote(info.down, true)) + .append(" capHeight=").append(quote(info.capHeight, true)) + .append(" lineHeight=").append(quote(info.lineHeight, true)) + .append(" spaceXAdvance=").append(quote(info.spaceXAdvance, true)) + .append(" xHeight=").append(quote(info.xHeight, true)) + .append(xmlCloseSelf).append("\n"); + + if (xml) buf.append("\t\n"); + } + + if (xml) { buf.append(""); } - + String charset = info.charset; - if (charset!=null&&charset.length()==0) - charset = null; - + if (charset != null && charset.length() == 0) charset = null; + outFntFile.writeString(buf.toString(), false, charset); } - /** A utility method which writes the given font data to a file. * * The specified pixmaps are written to the parent directory of outFntFile, using that file's name without an @@ -337,8 +337,8 @@ import com.badlogic.gdx.utils.Array; * @param info the optional font info for the header file, can be null */ public static void writeFont (BitmapFontData fontData, Pixmap[] pages, FileHandle outFntFile, FontInfo info) { String[] pageRefs = writePixmaps(pages, outFntFile.parent(), outFntFile.nameWithoutExtension()); - - //write the font data + + // write the font data writeFont(fontData, pageRefs, outFntFile, info, pages[0].getWidth(), pages[0].getHeight()); } @@ -357,18 +357,17 @@ import com.badlogic.gdx.utils.Array; * @param fileName the file names for the output images * @return the array of string references to be used with writeFont */ public static String[] writePixmaps (Pixmap[] pages, FileHandle outputDir, String fileName) { - if (pages==null || pages.length==0) - throw new IllegalArgumentException("no pixmaps supplied to BitmapFontWriter.write"); - + if (pages == null || pages.length == 0) throw new IllegalArgumentException("no pixmaps supplied to BitmapFontWriter.write"); + String[] pageRefs = new String[pages.length]; - - for (int i=0; i pages, FileHandle outputDir, String fileName) { Pixmap[] pix = new Pixmap[pages.size]; - for (int i=0; i images = new HashMap<>(); private static final Map avatars = new HashMap<>(); + private static final Map sleeves = new HashMap<>(); + private static final Map borders = new HashMap<>(); - private static List allSkins; + private static Array allSkins; private static FileHandle preferredDir; private static String preferredName; private static boolean loaded = false; @@ -98,12 +99,12 @@ public class FSkin { else { if (splashScreen != null) { if (allSkins == null) { //initialize - allSkins = new ArrayList<>(); - final List skinDirectoryNames = getSkinDirectoryNames(); + allSkins = new Array<>(); + final Array skinDirectoryNames = getSkinDirectoryNames(); for (final String skinDirectoryName : skinDirectoryNames) { allSkins.add(WordUtil.capitalize(skinDirectoryName.replace('_', ' '))); } - Collections.sort(allSkins); + allSkins.sort(); } } @@ -172,6 +173,9 @@ public class FSkin { } avatars.clear(); + sleeves.clear(); + + boolean textureFilter = Forge.isTextureFilteringEnabled(); final Map textures = new HashMap<>(); @@ -183,6 +187,9 @@ public class FSkin { final FileHandle f5 = getSkinFile(ForgeConstants.SPRITE_AVATARS_FILE); final FileHandle f6 = getDefaultSkinFile(SourceFile.OLD_FOILS.getFilename()); final FileHandle f7 = getDefaultSkinFile(ForgeConstants.SPRITE_MANAICONS_FILE); + final FileHandle f8 = getDefaultSkinFile(ForgeConstants.SPRITE_SLEEVES_FILE); + final FileHandle f9 = getDefaultSkinFile(ForgeConstants.SPRITE_SLEEVES2_FILE); + final FileHandle f10 = getDefaultSkinFile(ForgeConstants.SPRITE_BORDER_FILE); try { textures.put(f1.path(), new Texture(f1)); @@ -218,16 +225,25 @@ public class FSkin { //assemble avatar textures int counter = 0; + int scount = 0; Color pxTest; - Pixmap pxDefaultAvatars, pxPreferredAvatars; - Texture txDefaultAvatars, txPreferredAvatars; + Pixmap pxDefaultAvatars, pxPreferredAvatars, pxDefaultSleeves; + Texture txDefaultAvatars, txPreferredAvatars, txDefaultSleeves; pxDefaultAvatars = new Pixmap(f4); - txDefaultAvatars = new Texture(f4); + pxDefaultSleeves = new Pixmap(f8); + txDefaultAvatars = new Texture(f4, textureFilter); + if (textureFilter) + txDefaultAvatars.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); + txDefaultSleeves = new Texture(f8, textureFilter); + if (textureFilter) + txDefaultSleeves.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); if (f5.exists()) { pxPreferredAvatars = new Pixmap(f5); - txPreferredAvatars = new Texture(f5); + txPreferredAvatars = new Texture(f5, textureFilter); + if (textureFilter) + txPreferredAvatars.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); final int pw = pxPreferredAvatars.getWidth(); final int ph = pxPreferredAvatars.getHeight(); @@ -255,8 +271,42 @@ public class FSkin { } } + + final int sw = pxDefaultSleeves.getWidth(); + final int sh = pxDefaultSleeves.getHeight(); + + for (int j = 0; j < sh; j += 500) { + for (int i = 0; i < sw; i += 360) { + pxTest = new Color(pxDefaultSleeves.getPixel(i + 180, j + 250)); + if (pxTest.a == 0) { continue; } + FSkin.sleeves.put(scount++, new TextureRegion(txDefaultSleeves, i, j, 360, 500)); + } + } + + //re init second set of sleeves + pxDefaultSleeves = new Pixmap(f9); + txDefaultSleeves = new Texture(f9, textureFilter); + if (textureFilter) + txDefaultSleeves.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); + + final int sw2 = pxDefaultSleeves.getWidth(); + final int sh2 = pxDefaultSleeves.getHeight(); + + for (int j = 0; j < sh2; j += 500) { + for (int i = 0; i < sw2; i += 360) { + pxTest = new Color(pxDefaultSleeves.getPixel(i + 180, j + 250)); + if (pxTest.a == 0) { continue; } + FSkin.sleeves.put(scount++, new TextureRegion(txDefaultSleeves, i, j, 360, 500)); + } + } + + Texture bordersBW = new Texture(f10); + FSkin.borders.put(0, new TextureRegion(bordersBW, 2, 2, 672, 936)); + FSkin.borders.put(1, new TextureRegion(bordersBW, 676, 2, 672, 936)); + preferredIcons.dispose(); pxDefaultAvatars.dispose(); + pxDefaultSleeves.dispose();; } catch (final Exception e) { System.err.println("FSkin$loadFull: Missing a sprite (default icons, " @@ -314,8 +364,8 @@ public class FSkin { * * @return the skins */ - public static List getSkinDirectoryNames() { - final List mySkins = new ArrayList<>(); + public static Array getSkinDirectoryNames() { + final Array mySkins = new Array<>(); final FileHandle dir = Gdx.files.absolute(ForgeConstants.SKINS_DIR); for (FileHandle skinFile : dir.list()) { @@ -340,5 +390,13 @@ public class FSkin { return avatars; } + public static Map getSleeves() { + return sleeves; + } + + public static Map getBorders() { + return borders; + } + public static boolean isLoaded() { return loaded; } } diff --git a/forge-gui-mobile/src/forge/assets/FSkinFont.java b/forge-gui-mobile/src/forge/assets/FSkinFont.java index 2f98149aceb..3139809db11 100644 --- a/forge-gui-mobile/src/forge/assets/FSkinFont.java +++ b/forge-gui-mobile/src/forge/assets/FSkinFont.java @@ -16,6 +16,7 @@ import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator.FreeTypeFont import com.badlogic.gdx.graphics.glutils.PixmapTextureData; import com.badlogic.gdx.utils.Array; import forge.FThreads; +import forge.Forge; import forge.properties.ForgeConstants; import forge.util.FileUtil; import forge.util.TextBounds; @@ -26,7 +27,10 @@ import java.util.Map; public class FSkinFont { private static final int MIN_FONT_SIZE = 8; - private static final int MAX_FONT_SIZE = 72; + private static int MAX_FONT_SIZE = 72; + + private static final int MAX_FONT_SIZE_LESS_GLYPHS = 72; + private static final int MAX_FONT_SIZE_MANY_GLYPHS = 36; private static final String TTF_FILE = "font1.ttf"; private static final Map fonts = new HashMap<>(); @@ -58,7 +62,9 @@ public class FSkinFont { } //pre-load all supported font sizes - public static void preloadAll() { + public static void preloadAll(String language) { + //todo:really check the language glyph is a lot + MAX_FONT_SIZE = (language.equals("zh-CN")) ? MAX_FONT_SIZE_MANY_GLYPHS : MAX_FONT_SIZE_LESS_GLYPHS; for (int size = MIN_FONT_SIZE; size <= MAX_FONT_SIZE; size++) { _get(size); } @@ -355,7 +361,8 @@ public class FSkinFont { //generate from zh-CN.properties,and cardnames-zh-CN.txt //forge generate 3000+ characters cache need Take some time(MIN_FONT_SIZE - MAX_FONT_SIZE all size) //maybe using libgdx-hiero generate font cache is better - chars += "●、。「」『』一丁七万三上下不与丑专且世丘业丛东丝两严丧个中" + if (Forge.locale.equals("zh-CN")) + chars += "●、。「」『』一丁七万三上下不与丑专且世丘业丛东丝两严丧个中" + "丰临丸丹为主丽举乃久么义之乌乍乐乔乖乘乙九也乡书乱乳乾了予争" + "事二于云互五井亘亚些亡交亥亦产享京亮亲亵人亿什仁仅仆仇今介仍" + "从仑仓仕他仗付仙代令以仪们仰仲件价任份仿伊伍伏伐休众优伙会伟" @@ -377,85 +384,86 @@ public class FSkinFont { + "埃埋城域培基堂堆堕堡堤堪堰塌塑塔塘塞填境墓墙增墟墨壁壅壕壤士" + "壬壮声壳壶处备复夏外多夜够大天太夫央失头夷夸夹夺奇奈奉奋奎契" + "奔奖套奢奥女奴她好如妃妄妆妇妈妖妙妥妪妮妲妹姆姊始姓姜姥姬姿" - + "威娃娅娜婆婉婪婶媒嫁嫩嬉子孑孔孕字存孚孢季孤学孪孳孵孽宁它宅" - + "宇守安完宏宗官宙定宜宝实宠审客宣室宪宫宰害宴家容宾宿寂寄密寇" - + "富寒寓寝察寡寨寰寸对寺寻导封射将尉尊小少尔尖尘尚尝尤尬就尸尹" - + "尺尼尽尾局层居屈屋屏屑展属屠履屯山屹岁岑岔岖岗岚岛岩岱岳岸峡" - + "峭峰峻崇崎崔崖崩崽嵌巅巍川巡巢工左巧巨巫差己已巳巴巷币市布帅" - + "帆师希帕帖帘帜帝带席帮帷常帽幅幔幕干平年并幸幻幼幽广庄庆庇床" - + "序库应底店庙府庞废度座庭庶廉廊延建开异弃弄弊式弑弓引弗弘弟张" - + "弥弦弧弩弯弱張弹强归当录彗形彩彰影役彻彼往征径待很徊律後徒徕" - + "得徘徙從御復循微徵德徽心必忆忌忍忒志忘忠忧快忱念忽忾忿怀态怒" - + "怖思急性怨怪怯总恍恐恒恕恢恣恨恩恫息恰恳恶恸恼悉悍悔悖悟患悦" - + "您悬悯悲悼情惊惑惘惚惠惧惨惩惫惰想惹愁愈愎意愚感愣愤愧愿慈慌" - + "慎慑慕慢慧慨慰慷憎憩懦戈戏成我戒戕或战戟截戮戳戴户戾房所扁扇" - + "扈手才扎扑扒打托扣执扩扫扬扭扮扯扰找承技抄抉把抑抓投抖抗折抚" - + "抛抢护报披抱抵抹押抽拂拆拉拍拒拓拔拖拘招拜拟拣拥拦拧拨择括拯" - + "拱拳拷拼拽拾拿持挂指按挑挖挚挟挠挡挣挥挪挫振挺挽捆捉捍捕捞损" - + "换捣捧据捷捻掀授掉掌掐排掘掠探接控推掩措掮掳掷揍描提插握揭援" - + "揽搁搅搏搐搜搞搬搭携摄摆摇摘摧摩摸摹撒撕撞撤撬播撵撼擅操擎擒" - + "擞擦攀攫支收改攻放政故效敌敏救敕教敞敢散敦敬数敲整文斐斑斓斗" - + "斤斥斧斩断斯新方施旁旅旋族旗无既日旧旨早旭时旷旸旺昂昆昌明昏" - + "易昔昙星映春昨昭是昵昼显晃晋晓晕晖晚晨普景晰晴晶晷智暂暗暮暴" - + "曙曜曝曦曲曳更曼曾替最月有服朗望朝期木未末本札术朵机朽杀杂权" - + "杉李村杖杜束条来杨杯杰松板极构析林枚果枝枢枪枭枯架枷柄柏某染" - + "柜查柩柯柱柳栅标栈栋栏树栓栖栗株样核根格栽桂框案桌桎桑桓桠档" - + "桥桨桩桶梁梅梓梢梣梦梧梨梭梯械检棄棍棒棕棘棚森棱棺椁植椎椒椽" - + "楂楔楚楣楼概榄榆榔榨榴槌槛模横樱樵橇橡橫檀檐次欢欣欧欲欺歇歌" - + "止正此步武歪死歼殁殆殇殉殊残殍殒殓殖殡殴段殷殿毁毅母每毒比毕" - + "毛毡氅氏民氓气氤氦氧氲水永汀汁求汇汉汐汗汛池污汤汨汪汰汲汹汽" - + "沃沈沉沌沐沙沟没沥沦沮河沸油治沼沾沿泄泉泊法泛泞泡波泣泥注泪" - + "泯泰泽洁洋洒洗洛洞津洪洲活洼派流浅浆浇浊测济浑浓浚浩浪浮浴海" - + "浸涅消涉涌涎涛涟涡涤润涨涩液涵淋淘淤淬深混淹添清渊渎渐渔渗渝" - + "渠渡渣渥温港渲渴游湍湖湛湮湾湿溃溅源溜溢溪溯溶溺滋滑滓滔滚滞" - + "满滤滥滨滴漂漏演漠漩漫潘潜潭潮澄澈澹激濑濒瀑瀚灌火灭灯灰灵灼" - + "灾灿炉炎炙炫炬炭炮炸点炼炽烁烂烈烙烛烟烤烦烧烫烬热烽焉焊焚焦" - + "焰然煌煎煞煤照煮煽熄熊熏熔熟熠熵燃燎燕燧爆爪爬爱爵父片版牌牒" - + "牙牛牝牡牢牦牧物牲牵特牺犀犁犄犧犬犯状狂狄狈狐狗狙狞狡狩独狭" - + "狮狰狱狷狸狼猁猎猛猜猪猫献猴猿獒獠獾玄率玉王玖玛玩玫环现玷玻" - + "珀珂珊珍珠班球理琉琐琥琳琴琵琼瑕瑙瑚瑞瑟瑰璃璞璧瓜瓣瓦瓮瓯瓶" - + "瓷甘生用甩甫田由甲电画畅界畏留略畸畿疆疏疑疗疚疡疣疤疫疮疯疲" - + "疵疹疽疾病症痕痛痞痢痨痪痴痹瘟瘠瘤瘫瘴癣癫癸登白百的皆皇皈皮" - + "皱皿盆盈盐监盒盔盖盗盘盛盟目盲直相盾省看真眠眨眩眷眺眼着睁睡" - + "督睥睨睿瞄瞒瞥瞪瞬瞭瞰瞳矛矢知矫短矮石矾矿码砂砍研砖砦砧破砸" - + "砾础硕硫硬确碍碎碑碟碧碰碳碻碾磁磊磨磷磺礁示礼社祀祈祖祝神祟" - + "祠祥票祭祷祸禁禄福离禽私秃秉秋种科秘秣秤秩积称移秽稀程税稚稳" - + "稻穆穗穴究穷穹空穿突窃窍窒窖窗窘窜窝窟窥立竖站竞章童竭端竹笏" - + "笑笔笛笞符第笼等筑筒答策筛筝筹签简箔算箝管箭箱篓篮篱篷簇簧簪" - + "米类粉粒粗粮粹精糊糙糟系素索紧紫累繁纂纠红约级纪纬纯纱纳纵纷" - + "纸纹纺纽线练组绅细织终绊绍经绒结绕绘给绚络绝绞统绥继绩绪续绮" - + "绯绳维绵综绽绿缀缄缅缆缇缉缎缓缕编缘缚缝缠缩缪缰缸缺罅网罔罗" - + "罚罡罩罪置羁羊美羚羞群羽翁翅翎翔翠翡翰翱翻翼耀老考者而耍耐耕" - + "耗耘耙耳耶职联聚聪肃肆肇肉肌肖肝肠肢肤肥肩肯育肴肺肿胀胁胃胆" - + "背胎胖胜胞胡胧胫胶胸能脂脆脉脊脏脑脓脚脱脸腐腔腕腥腱腹腾腿膂" - + "膏膛膜膝臂臃臣自臭至致舌舍舒舞舟航般舰舱船艇良艰色艺艾节芒芙" - + "芜芥芬芭芮花芳芽苇苍苏苔苗苛苜苟若苦英茁茂范茉茎茜茧茨茫茸荆" - + "草荒荚荡荣荨荫药荷莉莎莓莫莱莲莳获莽菁菇菊菌菜菲萃萌萍萎萝营" - + "萦萧萨萼落著葛葬葵蒂蒙蒸蓄蓑蓝蓟蓿蔑蔓蔚蔷蔻蔽蕈蕊蕨蕴蕾薄薇" - + "薙薪藏藐藓藤藻虎虏虐虑虔虚虫虱虹蚀蚁蚊蚋蚣蚺蛆蛇蛊蛋蛎蛙蛛蛞" - + "蛭蛮蛰蛸蛾蜂蜈蜉蜒蜕蜗蜘蜜蜡蜥蜴蜷蜿蝇蝎蝓蝗蝙蝠蝣蝾螂螅融螫" - + "螳螺蟀蟋蟑蟒蟹蠕蠢血行衍街衡衣补表衫衰袂袋袍袖被袭裁裂装裔裘" - + "褐褛褪褫褴褶襄西要覆见观规觅视览觉觊角解触言詹誉誓警计认讧讨" - + "让训议讯记讲许论讽设访诀证评诅识诈诉词试诗诘诚诛话诞诡该详诫" - + "语误诱诲说诵请诸诺读调谆谈谊谋谍谐谕谗谜谟谢谣谦谧谨谬谭谱谴" - + "谵谷豁象豪豹豺貂貌贝贞负贡财责贤败货质贩贪贫贬购贮贯贱贴贵贷" - + "贸费贺贼贾贿赂赃资赋赌赎赏赐赖赘赛赞赠赢赤赦赫走赶起超越趋足" - + "跃跑跖跚跛距跟跨路跳践跺踏踝踢踩踪踵踽蹂蹄蹊蹋蹒蹦蹬躁躏身躯" - + "躲車车轨轩转轭轮软轰轴轻载较辉辑输辖辗辙辛辜辞辟辨辩辫辰辱边" - + "达迁迂迅过迈迎运近返还这进远违连迟迦迩迪迫迭述迳迷迸迹追退送" - + "适逃逆选逊透逐递途通逝逞速造逢逮逸逻逼遁遇遍遏道遗遣遥遨遭遮" - + "避邀還那邦邪邬邸郊郎部都鄙酋配酒酬酷酸酿醉醒采釉释里重野量金" - + "鉴针钉钓钗钙钜钝钟钢钥钦钨钩钮钯钱钳钵钻钽铁铃铅铎铜铠铬铭铲" - + "银铸铺链销锁锄锅锈锋锐错锡锢锤锥锦锭键锯锻镇镖镜镬镰镶长間闇" - + "门闩闪闭问闯闲间闷闸闹闻阀阁阅队阱防阳阴阵阶阻阿陀附际陆陋降" - + "限院除陨险陪陲陵陶陷隆随隐隔隘障隧隶隼难雀雄雅集雇雏雕雨雪雯" - + "雳零雷雹雾需霆震霉霍霓霖霜霞霰露霸霹青靖静非靠靡面革靴靶鞍鞑" - + "鞭韧音韵韶页顶项顺须顽顾顿颂预颅领颈颊题颚颜额颠颤风飒飓飘飙" - + "飞食餍餐餮饕饥饭饮饰饱饵饶饿馆馈馐馑首香馨马驭驮驯驰驱驳驹驻" - + "驼驽驾驿骁骂骄骆骇验骏骐骑骗骚骤骨骰骷骸骼髅髓高鬃鬓鬣鬼魁魂" - + "魄魅魇魈魏魔鰴鱼鲁鲜鲤鲨鲮鲸鲽鳃鳄鳍鳐鳗鳝鳞鸟鸠鸡鸢鸣鸦鸽鹅" - + "鹉鹊鹏鹗鹞鹤鹦鹫鹭鹰鹿麋麒麟麦麻黄黎黏黑默黛黜點黠黯鼎鼓鼠鼬" - + "鼹鼻齐齑齿龇龙龟!(),/:;?~"; + + "威娃娅娜婆婉婪婴婶媒嫁嫩嬉子孑孔孕字存孚孢季孤学孪孳孵孽宁它" + + "宅宇守安完宏宗官宙定宜宝实宠审客宣室宪宫宰害宴家容宾宿寂寄密" + + "寇富寒寓寝察寡寨寰寸对寺寻导封射将尉尊小少尔尖尘尚尝尤尬就尸" + + "尹尺尼尽尾局层居屈屋屏屑展属屠履屯山屹岁岑岔岖岗岚岛岩岭岱岳" + + "岸峡峭峰峻崇崎崔崖崩崽嵌巅巍川巡巢工左巧巨巩巫差己已巳巴巷巾" + + "币市布帅帆师希帕帖帘帚帜帝带席帮帷常帼帽幅幔幕干平年并幸幻幼" + + "幽广庄庆庇床序库应底店庙府庞废度座庭庶廉廊延建开异弃弄弊式弑" + + "弓引弗弘弟张弥弦弧弩弯弱張弹强归当录彗形彩彰影役彻彼往征径待" + + "很徊律後徒徕得徘徙從御復循微徵德徽心必忆忌忍忒志忘忠忧快忱念" + + "忽忾忿怀态怒怖思急性怨怪怯总恋恍恐恒恕恢恣恨恩恫恭息恰恳恶恸" + + "恼悉悍悔悖悟患悦您悬悯悲悼情惊惑惘惚惠惧惨惩惫惰想惹愁愈愎意" + + "愚感愣愤愧愿慈慌慎慑慕慢慧慨慰慷憎憩懦戈戍戏成我戒戕或战戟截" + + "戮戳戴户戾房所扁扇扈手才扎扑扒打托扣执扩扫扬扭扮扯扰找承技抄" + + "抉把抑抓投抖抗折抚抛抢护报披抱抵抹押抽拂拆拉拍拒拓拔拖拘招拜" + + "拟拣拥拦拧拨择括拯拱拳拷拼拽拾拿持挂指按挑挖挚挟挠挡挣挥挪挫" + + "振挺挽捆捉捍捕捞损换捣捧据捷捻掀授掉掌掐排掘掠探接控推掩措掮" + + "掳掷揍描提插握揭援揽搁搅搏搐搜搞搬搭携摄摆摇摘摧摩摸摹撒撕撞" + + "撤撬播撵撼擅操擎擒擞擦攀攫支收改攻放政故效敌敏救敕教敞敢散敦" + + "敬数敲整文斐斑斓斗斤斥斧斩断斯新方施旁旅旋族旗无既日旧旨早旭" + + "时旷旸旺昂昆昌明昏易昔昙星映春昨昭是昵昼显晃晋晓晕晖晚晨普景" + + "晰晴晶晷智暂暗暮暴曙曜曝曦曲曳更曼曾替最月有服朗望朝期木未末" + + "本札术朵机朽杀杂权杉李村杖杜束条来杨杯杰松板极构析林枚果枝枢" + + "枪枭枯架枷柄柏某染柜查柩柯柱柳栅标栈栋栏树栓栖栗株样核根格栽" + + "桂框案桌桎桑桓桠档桥桨桩桶梁梅梓梢梣梦梧梨梭梯械检棄棍棒棕棘" + + "棚森棱棺椁植椎椒椽楂楔楚楣楼概榄榆榔榨榴槌槛模横樱樵橇橡橫檀" + + "檐次欢欣欧欲欺歇歌止正此步武歪死歼殁殆殇殉殊残殍殒殓殖殡殴段" + + "殷殿毁毅母每毒比毕毛毡氅氏民氓气氤氦氧氲水永汀汁求汇汉汐汗汛" + + "池污汤汨汪汰汲汹汽沃沈沉沌沐沙沟没沥沦沮河沸油治沼沾沿泄泉泊" + + "法泛泞泡波泣泥注泪泯泰泽洁洋洒洗洛洞津洪洲活洼派流浅浆浇浊测" + + "济浑浓浚浩浪浮浴海浸涅消涉涌涎涛涟涡涤润涨涩液涵淋淘淤淬深混" + + "淹添清渊渎渐渔渗渝渠渡渣渥温港渲渴游湍湖湛湮湾湿溃溅源溜溢溪" + + "溯溶溺滋滑滓滔滚滞满滤滥滨滩滴漂漏演漠漩漫潘潜潭潮澄澈澹激濑" + + "濒瀑瀚灌火灭灯灰灵灶灼灾灿炉炎炙炫炬炭炮炸点炼炽烁烂烈烙烛烟" + + "烤烦烧烫烬热烽焉焊焚焦焰然煌煎煞煤照煮煽熄熊熏熔熟熠熵燃燎燕" + + "燧爆爪爬爱爵父片版牌牒牙牛牝牡牢牦牧物牲牵特牺犀犁犄犧犬犯状" + + "狂狄狈狐狗狙狞狡狩独狭狮狰狱狷狸狼猁猎猛猜猪猫献猴猿獒獠獾玄" + + "率玉王玖玛玩玫环现玷玻珀珂珊珍珠班球理琉琐琥琳琴琵琼瑕瑙瑚瑞" + + "瑟瑰璃璞璧瓜瓣瓦瓮瓯瓶瓷甘甜生用甩甫田由甲电男画畅界畏留略畸" + + "畿疆疏疑疗疚疡疣疤疫疮疯疲疵疹疽疾病症痕痛痞痢痨痪痴痹瘟瘠瘤" + + "瘫瘴癣癫癸登白百的皆皇皈皮皱皿盆盈盐监盒盔盖盗盘盛盟目盲直相" + + "盾省看真眠眨眩眷眺眼着睁睡督睥睨睿瞄瞒瞥瞪瞬瞭瞰瞳矛矢知矫短" + + "矮石矾矿码砂砍研砖砦砧破砸砾础硕硫硬确碍碎碑碟碧碰碳碻碾磁磊" + + "磨磷磺礁示礼社祀祈祖祝神祟祠祥票祭祷祸禁禄福离禽私秃秉秋种科" + + "秘秣秤秩积称移秽稀程税稚稳稻穆穗穴究穷穹空穿突窃窍窒窖窗窘窜" + + "窝窟窥立竖站竞章童竭端竹笏笑笔笛笞符第笼等筑筒答策筛筝筹签简" + + "箔算箝管箭箱篓篮篱篷簇簧簪籍米类粉粒粗粘粮粹精糊糙糟系素索紧" + + "紫累繁纂纠红约级纪纬纯纱纳纵纶纷纸纹纺纽线练组绅细织终绊绍经" + + "绒结绕绘给绚络绝绞统绥继绩绪续绮绯绳维绵综绽绿缀缄缅缆缇缉缎" + + "缓缕编缘缚缝缠缩缪缰缸缺罅网罔罗罚罡罩罪置羁羊美羚羞群羽翁翅" + + "翎翔翠翡翰翱翻翼耀老考者而耍耐耕耗耘耙耳耶耸职联聚聪肃肆肇肉" + + "肌肖肝肠肢肤肥肩肯育肴肺肿胀胁胃胆背胎胖胜胞胡胧胫胶胸能脂脆" + + "脉脊脏脑脓脚脱脸腐腔腕腥腱腹腾腿膂膏膛膜膝臂臃臣自臭至致舌舍" + + "舒舞舟航般舰舱船艇良艰色艺艾节芒芙芜芥芬芭芮花芳芽苇苍苏苔苗" + + "苛苜苟若苦英茁茂范茉茎茜茧茨茫茸荆草荒荚荡荣荨荫药荷莉莎莓莫" + + "莱莲莳获莽菁菇菊菌菜菲萃萌萍萎萝营萦萧萨萼落著葛葬葵蒂蒙蒸蓄" + + "蓑蓝蓟蓿蔑蔓蔚蔷蔻蔽蕈蕊蕨蕴蕾薄薇薙薪藏藐藓藤藻虎虏虐虑虔虚" + + "虫虱虹蚀蚁蚊蚋蚣蚺蛆蛇蛊蛋蛎蛙蛛蛞蛭蛮蛰蛸蛾蜂蜈蜉蜒蜕蜗蜘蜜" + + "蜡蜥蜴蜷蜿蝇蝎蝓蝗蝙蝠蝣蝾螂螅融螫螳螺蟀蟋蟑蟒蟹蠕蠢血行衍街" + + "衡衣补表衫衰袂袋袍袖被袭裁裂装裔裘褐褛褪褫褴褶襄西要覆见观规" + + "觅视览觉觊角解触言詹誉誓警计认讧讨让训议讯记讲许论讽设访诀证" + + "评诅识诈诉词译试诗诘诚诛话诞诡该详诫语误诱诲说诵请诸诺读谀谁" + + "调谆谈谊谋谍谐谕谗谜谟谢谣谦谧谨谬谭谱谴谵谷豁豆象豪豹豺貂貌" + + "贝贞负贡财责贤败货质贩贪贫贬购贮贯贱贴贵贷贸费贺贼贾贿赂赃资" + + "赋赌赎赏赐赖赘赛赞赠赢赤赦赫走赶起趁超越趋足跃跑跖跚跛距跟跨" + + "路跳践跺踏踝踢踩踪踵踽蹂蹄蹊蹋蹒蹦蹬躁躏身躯躲車车轨轩转轭轮" + + "软轰轴轻载较辉辑输辖辗辙辛辜辞辟辨辩辫辰辱边达迁迂迅过迈迎运" + + "近返还这进远违连迟迦迩迪迫迭述迳迷迸迹追退送适逃逆选逊透逐递" + + "途通逝逞速造逡逢逮逸逻逼遁遂遇遍遏道遗遣遥遨遭遮遵避邀還邑那" + + "邦邪邬邸郊郎部都鄙酋配酒酬酷酸酿醉醒采釉释里重野量金鉴针钉钓" + + "钗钙钜钝钟钢钥钦钨钩钮钯钱钳钵钻钽铁铃铅铎铜铠铬铭铲银铸铺链" + + "销锁锄锅锈锋锐错锡锢锤锥锦锭键锯锻镇镖镜镬镰镶长間闇门闩闪闭" + + "问闯闲间闷闸闹闻阀阁阅队阱防阳阴阵阶阻阿陀附际陆陋降限院除陨" + + "险陪陲陵陶陷隆随隐隔隘障隧隶隼难雀雄雅集雇雉雏雕雨雪雯雳零雷" + + "雹雾需霆震霉霍霓霖霜霞霰露霸霹青靖静非靠靡面革靴靶鞋鞍鞑鞭韧" + + "音韵韶页顶项顺须顽顾顿颂预颅领颈颊题颚颜额颠颤风飒飓飘飙飞食" + + "餍餐餮饕饥饭饮饰饱饵饶饼饿馆馈馐馑首香馨马驭驮驯驰驱驳驹驻驼" + + "驽驾驿骁骂骄骆骇验骏骐骑骗骚骤骨骰骷骸骼髅髓高鬃鬓鬣鬼魁魂魄" + + "魅魇魈魏魔鰴鱼鲁鲜鲤鲨鲮鲸鲽鳃鳄鳍鳐鳗鳝鳞鸟鸠鸡鸢鸣鸦鸽鹅鹉" + + "鹊鹏鹗鹞鹤鹦鹫鹭鹰鹿麋麒麟麦麻黄黎黏黑默黛黜點黠黯鼎鼓鼠鼬鼹" + + "鼻齐齑齿龇龙龟伸!(),/:;?~"; final PixmapPacker packer = new PixmapPacker(pageSize, pageSize, Pixmap.Format.RGBA8888, 2, false); final FreeTypeFontParameter parameter = new FreeTypeFontParameter(); diff --git a/forge-gui-mobile/src/forge/assets/FSkinImage.java b/forge-gui-mobile/src/forge/assets/FSkinImage.java index 7048fe68698..cdaaceeaaf7 100644 --- a/forge-gui-mobile/src/forge/assets/FSkinImage.java +++ b/forge-gui-mobile/src/forge/assets/FSkinImage.java @@ -282,6 +282,9 @@ public enum FSkinImage implements FImage { IMG_ABILITY_HEXPROOF_UB (FSkinProp.IMG_ABILITY_HEXPROOF_UB, SourceFile.ABILITIES), //token icon IMG_ABILITY_TOKEN (FSkinProp.IMG_ABILITY_TOKEN, SourceFile.ABILITIES), + //border + IMG_BORDER_BLACK (FSkinProp.IMG_BORDER_BLACK, SourceFile.BORDERS), + IMG_BORDER_WHITE (FSkinProp.IMG_BORDER_WHITE, SourceFile.BORDERS), //PROTECT ICONS IMG_ABILITY_PROTECT_ALL (FSkinProp.IMG_ABILITY_PROTECT_ALL, SourceFile.ABILITIES), IMG_ABILITY_PROTECT_B (FSkinProp.IMG_ABILITY_PROTECT_B, SourceFile.ABILITIES), @@ -308,6 +311,7 @@ public enum FSkinImage implements FImage { OLD_FOILS(ForgeConstants.SPRITE_OLD_FOILS_FILE), TROPHIES(ForgeConstants.SPRITE_TROPHIES_FILE), ABILITIES(ForgeConstants.SPRITE_ABILITY_FILE), + BORDERS(ForgeConstants.SPRITE_BORDER_FILE), MANAICONS(ForgeConstants.SPRITE_MANAICONS_FILE), PLANAR_CONQUEST(ForgeConstants.SPRITE_PLANAR_CONQUEST_FILE); diff --git a/forge-gui-mobile/src/forge/assets/ImageCache.java b/forge-gui-mobile/src/forge/assets/ImageCache.java index 6245e4ef2a4..af1013a6a86 100644 --- a/forge-gui-mobile/src/forge/assets/ImageCache.java +++ b/forge-gui-mobile/src/forge/assets/ImageCache.java @@ -18,21 +18,25 @@ package forge.assets; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Pixmap.Format; import com.badlogic.gdx.graphics.Texture; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.LoadingCache; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import forge.ImageKeys; +import forge.card.CardEdition; +import forge.game.card.CardView; import forge.game.player.IHasIcon; +import forge.item.IPaperCard; import forge.item.InventoryItem; +import forge.model.FModel; import forge.properties.ForgeConstants; import forge.util.ImageUtil; import org.apache.commons.lang3.StringUtils; +import org.cache2k.Cache; +import org.cache2k.Cache2kBuilder; import java.util.HashSet; import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; /** * This class stores ALL card images in a cache with soft values. this means @@ -52,11 +56,16 @@ public class ImageCache { // short prefixes to save memory private static final Set missingIconKeys = new HashSet<>(); - private static final LoadingCache cache = CacheBuilder.newBuilder() - .maximumSize(400) - .expireAfterAccess(15,TimeUnit.MINUTES) - .build(new ImageLoader()); + private static final Cache cache = new Cache2kBuilder() {} + .name("cache") + .eternal(true) + .permitNullValues(true) + .disableStatistics(true) + .loader(new ImageLoader()) + .build(); public static final Texture defaultImage; + public static FImage BlackBorder = FSkinImage.IMG_BORDER_BLACK; + public static FImage WhiteBorder = FSkinImage.IMG_BORDER_WHITE; private static boolean imageLoaded, delayLoadRequested; public static void allowSingleLoad() { @@ -76,7 +85,7 @@ public class ImageCache { } public static void clear() { - cache.invalidateAll(); + cache.clear(); missingIconKeys.clear(); } @@ -125,7 +134,8 @@ public class ImageCache { Texture image; if (useDefaultIfNotFound) { // Load from file and add to cache if not found in cache initially. - image = cache.getIfPresent(imageKey); + image = cache.get(imageKey); + if (image != null) { return image; } if (imageLoaded) { //prevent loading more than one image each render for performance @@ -139,15 +149,7 @@ public class ImageCache { imageLoaded = true; } - try { - image = cache.get(imageKey); - } - catch (final ExecutionException ex) { - if (!(ex.getCause() instanceof NullPointerException)) { - ex.printStackTrace(); - } - image = null; - } + try { image = cache.get(imageKey); } catch (final Exception ex) { image = null; } @@ -162,4 +164,120 @@ public class ImageCache { } return image; } + public static void preloadCache(Iterable keys) { + cache.getAll(keys); + } + public static TextureRegion croppedBorderImage(Texture image, boolean fullborder) { + if (!fullborder) + return new TextureRegion(image); + float rscale = 0.96f; + int rw = Math.round(image.getWidth()*rscale); + int rh = Math.round(image.getHeight()*rscale); + int rx = Math.round((image.getWidth() - rw)/2); + int ry = Math.round((image.getHeight() - rh)/2)-2; + TextureRegion rimage = new TextureRegion(image, rx, ry, rw, rh); + return rimage; + } + public static boolean isWhiteBordered(IPaperCard c) { + if (c == null) + return false; + + CardEdition ed = FModel.getMagicDb().getEditions().get(c.getEdition()); + if (ed != null && ed.isWhiteBorder()) + return true; + return false; + } + public static boolean isWhiteBordered(CardView c) { + if (c == null) + return false; + + CardView.CardStateView state = c.getCurrentState(); + CardEdition ed = FModel.getMagicDb().getEditions().get(state.getSetCode()); + if (ed != null && ed.isWhiteBorder() && state.getFoilIndex() == 0) + return true; + return false; + } + public static Color borderColor(IPaperCard c) { + if (c == null) + return Color.valueOf("#171717"); + + CardEdition ed = FModel.getMagicDb().getEditions().get(c.getEdition()); + if (ed != null && ed.isWhiteBorder()) + return Color.valueOf("#fffffd"); + return Color.valueOf("#171717"); + } + public static Color borderColor(CardView c) { + if (c == null) + return Color.valueOf("#171717"); + + CardView.CardStateView state = c.getCurrentState(); + CardEdition ed = FModel.getMagicDb().getEditions().get(state.getSetCode()); + if (ed != null && ed.isWhiteBorder() && state.getFoilIndex() == 0) + return Color.valueOf("#fffffd"); + return Color.valueOf("#171717"); + } + public static int getFSkinBorders(CardView c) { + if (c == null) + return 0; + + CardView.CardStateView state = c.getCurrentState(); + CardEdition ed = FModel.getMagicDb().getEditions().get(state.getSetCode()); + if (ed != null && ed.isWhiteBorder() && state.getFoilIndex() == 0) + return 1; + return 0; + } + public static boolean isExtendedArt(CardView c) { + if (c == null) + return false; + + CardView.CardStateView state = c.getCurrentState(); + if (state.getSetCode().contains("MPS_")) + return true; + return false; + } + public static boolean isExtendedArt(IPaperCard c) { + if (c == null) + return false; + + if (c.getEdition().contains("MPS_")) + return true; + return false; + } + public static FImage getBorderImage(CardView c, boolean canshow) { + if (!canshow) + return BlackBorder; + if (isWhiteBordered(c)) + return WhiteBorder; + return BlackBorder; + } + public static FImage getBorderImage(IPaperCard c) { + if (isWhiteBordered(c)) + return WhiteBorder; + return BlackBorder; + } + public static Color getTint(CardView c) { + if (c == null) + return Color.CLEAR; + if (c.isFaceDown()) + return Color.CLEAR; + + CardView.CardStateView state = c.getCurrentState(); + if (state.getColors().isColorless()) //Moonlace -> target spell or permanent becomes colorless. + return Color.valueOf("#A0A6A4"); + else if (state.getColors().isMonoColor()) { + if (state.getColors().hasBlack()) + return Color.valueOf("#48494a"); + else if (state.getColors().hasBlue()) + return Color.valueOf("#62b5f8"); + else if (state.getColors().hasRed()) + return Color.valueOf("#f6532d"); + else if (state.getColors().hasGreen()) + return Color.valueOf("#66cb35"); + else if (state.getColors().hasWhite()) + return Color.valueOf("#EEEBE1"); + } + else if (state.getColors().isMulticolor()) + return Color.valueOf("#F9E084"); + return Color.CLEAR; + } } diff --git a/forge-gui-mobile/src/forge/assets/ImageLoader.java b/forge-gui-mobile/src/forge/assets/ImageLoader.java index e8668c6862f..5f33d4c44c9 100644 --- a/forge-gui-mobile/src/forge/assets/ImageLoader.java +++ b/forge-gui-mobile/src/forge/assets/ImageLoader.java @@ -3,37 +3,39 @@ package forge.assets; import java.io.File; import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.Pixmap; import com.badlogic.gdx.graphics.Texture; -import com.google.common.cache.CacheLoader; +import com.badlogic.gdx.graphics.TextureData; +import com.badlogic.gdx.graphics.glutils.PixmapTextureData; +import forge.FThreads; +import org.cache2k.integration.CacheLoader; import forge.Forge; import forge.ImageKeys; final class ImageLoader extends CacheLoader { + Texture n; @Override public Texture load(String key) { + boolean extendedArt = false; + boolean textureFilter = Forge.isTextureFilteringEnabled(); + if (key.length() > 4){ + if ((key.substring(0,4).contains("MPS_"))) //MPS_ sets + extendedArt = true; + else if ((key.substring(0,3).contains("UST"))) //Unstable Set + extendedArt = true; + } File file = ImageKeys.getImageFile(key); if (file != null) { FileHandle fh = new FileHandle(file); try { - if (Forge.isTextureFilteringEnabled()) { - Texture t = new Texture(fh, true); + Texture t = new Texture(fh, textureFilter); + if (textureFilter) t.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); - - /* // Optional experimental feature: Anisotropic filtering - GL20 gl = Gdx.gl20; - if (gl != null && Gdx.graphics.supportsExtension("GL_EXT_texture_filter_anisotropic")) { - FloatBuffer buffer = BufferUtils.newFloatBuffer(16); - gl.glGetFloatv(GL20.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, buffer); - float maxAniso = buffer.get(0); - - t.bind(); - gl.glTexParameterf(GL20.GL_TEXTURE_2D, GL20.GL_TEXTURE_MAX_ANISOTROPY_EXT, maxAniso); - } */ - return t; - } else { - return new Texture(fh); - } + if (extendedArt) + return generateTexture(fh, t, textureFilter); + return t; } catch (Exception ex) { Forge.log("Could not read image file " + fh.path() + "\n\nException:\n" + ex.toString()); @@ -41,4 +43,67 @@ final class ImageLoader extends CacheLoader { } return null; } + + public Texture generateTexture(FileHandle fh, Texture t, boolean textureFilter) { + if (t == null || fh == null) + return t; + FThreads.invokeInEdtNowOrLater(new Runnable() { + @Override + public void run() { + Pixmap pImage = new Pixmap(fh); + int w = pImage.getWidth(); + int h = pImage.getHeight(); + int radius = (h - w) / 8; + Pixmap pMask = createRoundedRectangle(w, h, radius, Color.RED); + drawPixelstoMask(pImage, pMask); + TextureData textureData = new PixmapTextureData( + pMask, //pixmap to use + Pixmap.Format.RGBA8888, + textureFilter, //use mipmaps + false, true); + n = new Texture(textureData); + if (textureFilter) + n.setFilter(Texture.TextureFilter.MipMapLinearLinear, Texture.TextureFilter.Linear); + pImage.dispose(); + pMask.dispose(); + } + }); + return n; + } + public Pixmap createRoundedRectangle(int width, int height, int cornerRadius, Color color) { + Pixmap pixmap = new Pixmap(width, height, Pixmap.Format.RGBA8888); + Pixmap ret = new Pixmap(width, height, Pixmap.Format.RGBA8888); + pixmap.setColor(color); + //round corners + pixmap.fillCircle(cornerRadius, cornerRadius, cornerRadius); + pixmap.fillCircle(width - cornerRadius - 1, cornerRadius, cornerRadius); + pixmap.fillCircle(cornerRadius, height - cornerRadius - 1, cornerRadius); + pixmap.fillCircle(width - cornerRadius - 1, height - cornerRadius - 1, cornerRadius); + //two rectangle parts + pixmap.fillRectangle(cornerRadius, 0, width - cornerRadius * 2, height); + pixmap.fillRectangle(0, cornerRadius, width, height - cornerRadius * 2); + //draw rounded rectangle + ret.setColor(color); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + if (pixmap.getPixel(x, y) != 0) ret.drawPixel(x, y); + } + } + pixmap.dispose(); + return ret; + } + public void drawPixelstoMask(Pixmap pixmap, Pixmap mask){ + int pixmapWidth = mask.getWidth(); + int pixmapHeight = mask.getHeight(); + Color pixelColor = new Color(); + for (int x=0; x 0) { - CardFaceSymbols.drawOther(g, String.format("foil%02d", foil), x, y, w, h, rotateSplit); + CardFaceSymbols.drawOther(g, String.format("foil%02d", foil), new_x, new_y, new_w, new_h, rotateSplit); } } } diff --git a/forge-gui-mobile/src/forge/card/GameEntityPicker.java b/forge-gui-mobile/src/forge/card/GameEntityPicker.java index d26f262d259..d327202aac1 100644 --- a/forge-gui-mobile/src/forge/card/GameEntityPicker.java +++ b/forge-gui-mobile/src/forge/card/GameEntityPicker.java @@ -20,6 +20,7 @@ import forge.toolbox.FOptionPane; import forge.toolbox.FTextField; import forge.toolbox.FEvent.FEventHandler; import forge.util.Callback; +import forge.util.Localizer; public class GameEntityPicker extends TabPageScreen { private final FOptionPane optionPane; @@ -73,7 +74,7 @@ public class GameEntityPicker extends TabPageScreen { super(caption0 + " (" + items.size() + ")", icon0); txtSearch = add(new FTextField()); txtSearch.setFont(FSkinFont.get(12)); - txtSearch.setGhostText("Search"); + txtSearch.setGhostText(Localizer.getInstance().getMessage("lblSearch")); txtSearch.setChangedHandler(new FEventHandler() { @Override public void handleEvent(FEvent e) { diff --git a/forge-gui-mobile/src/forge/deck/FDeckChooser.java b/forge-gui-mobile/src/forge/deck/FDeckChooser.java index b62ea91d363..ccbe174bc3b 100644 --- a/forge-gui-mobile/src/forge/deck/FDeckChooser.java +++ b/forge-gui-mobile/src/forge/deck/FDeckChooser.java @@ -149,6 +149,7 @@ public class FDeckChooser extends FScreen { @Override public void handleEvent(FEvent e) { if (selectedDeckType != DeckType.STANDARD_COLOR_DECK && selectedDeckType != DeckType.STANDARD_CARDGEN_DECK + && selectedDeckType != DeckType.PIONEER_CARDGEN_DECK && selectedDeckType != DeckType.MODERN_CARDGEN_DECK && selectedDeckType != DeckType.LEGACY_CARDGEN_DECK && selectedDeckType != DeckType.VINTAGE_CARDGEN_DECK && selectedDeckType != DeckType.MODERN_COLOR_DECK && selectedDeckType != DeckType.COLOR_DECK && selectedDeckType != DeckType.THEME_DECK @@ -172,6 +173,9 @@ public class FDeckChooser extends FScreen { else if (selectedDeckType == DeckType.STANDARD_CARDGEN_DECK){ DeckgenUtil.randomSelect(lstDecks); } + else if (selectedDeckType == DeckType.PIONEER_CARDGEN_DECK){ + DeckgenUtil.randomSelect(lstDecks); + } else if (selectedDeckType == DeckType.MODERN_CARDGEN_DECK){ DeckgenUtil.randomSelect(lstDecks); } @@ -296,6 +300,7 @@ public class FDeckChooser extends FScreen { case RANDOM_CARDGEN_COMMANDER_DECK: case RANDOM_COMMANDER_DECK: case MODERN_CARDGEN_DECK: + case PIONEER_CARDGEN_DECK: case LEGACY_CARDGEN_DECK: case VINTAGE_CARDGEN_DECK: case MODERN_COLOR_DECK: @@ -486,6 +491,7 @@ public class FDeckChooser extends FScreen { cmbDeckTypes.addItem(DeckType.STANDARD_COLOR_DECK); if(FModel.isdeckGenMatrixLoaded()) { cmbDeckTypes.addItem(DeckType.STANDARD_CARDGEN_DECK); + cmbDeckTypes.addItem(DeckType.PIONEER_CARDGEN_DECK); cmbDeckTypes.addItem(DeckType.MODERN_CARDGEN_DECK); cmbDeckTypes.addItem(DeckType.LEGACY_CARDGEN_DECK); cmbDeckTypes.addItem(DeckType.VINTAGE_CARDGEN_DECK); @@ -698,6 +704,14 @@ public class FDeckChooser extends FScreen { } config = ItemManagerConfig.STRING_ONLY; break; + case PIONEER_CARDGEN_DECK: + maxSelections = 1; + pool= new ArrayList<>(); + if(FModel.isdeckGenMatrixLoaded()) { + pool = ArchetypeDeckGenerator.getMatrixDecks(FModel.getFormats().getPioneer(), isAi); + } + config = ItemManagerConfig.STRING_ONLY; + break; case MODERN_CARDGEN_DECK: maxSelections = 1; pool= new ArrayList<>(); @@ -1077,6 +1091,7 @@ public class FDeckChooser extends FScreen { DeckType.STANDARD_COLOR_DECK, DeckType.STANDARD_CARDGEN_DECK, DeckType.MODERN_COLOR_DECK, + DeckType.PIONEER_CARDGEN_DECK, DeckType.MODERN_CARDGEN_DECK, DeckType.LEGACY_CARDGEN_DECK, DeckType.VINTAGE_CARDGEN_DECK, @@ -1085,6 +1100,7 @@ public class FDeckChooser extends FScreen { ); if (!FModel.isdeckGenMatrixLoaded()) { deckTypes.remove(DeckType.STANDARD_CARDGEN_DECK); + deckTypes.remove(DeckType.PIONEER_CARDGEN_DECK); deckTypes.remove(DeckType.MODERN_CARDGEN_DECK); deckTypes.remove(DeckType.LEGACY_CARDGEN_DECK); deckTypes.remove(DeckType.VINTAGE_CARDGEN_DECK); diff --git a/forge-gui-mobile/src/forge/deck/FDeckEditor.java b/forge-gui-mobile/src/forge/deck/FDeckEditor.java index 4df93c636c4..3ce30db0621 100644 --- a/forge-gui-mobile/src/forge/deck/FDeckEditor.java +++ b/forge-gui-mobile/src/forge/deck/FDeckEditor.java @@ -10,11 +10,7 @@ import com.google.common.collect.ImmutableList; import forge.Forge; import forge.Forge.KeyInputAdapter; import forge.Graphics; -import forge.assets.FImage; -import forge.assets.FSkin; -import forge.assets.FSkinFont; -import forge.assets.FSkinImage; -import forge.assets.FTextureRegionImage; +import forge.assets.*; import forge.card.CardDb; import forge.card.CardEdition; import forge.card.CardPreferences; @@ -37,26 +33,14 @@ import forge.planarconquest.ConquestUtil; import forge.properties.ForgePreferences.FPref; import forge.screens.FScreen; import forge.screens.TabPageScreen; -import forge.toolbox.FContainer; -import forge.toolbox.FEvent; +import forge.toolbox.*; import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FEvent.FEventType; -import forge.toolbox.FLabel; -import forge.toolbox.FOptionPane; -import forge.toolbox.GuiChoose; -import forge.util.Callback; -import forge.util.ItemPool; -import forge.util.Lang; -import forge.util.Localizer; -import forge.util.Utils; +import forge.util.*; import forge.util.storage.IStorage; import org.apache.commons.lang3.StringUtils; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.Map.Entry; public class FDeckEditor extends TabPageScreen { @@ -189,6 +173,7 @@ public class FDeckEditor extends TabPageScreen { new DeckSectionPage(DeckSection.Sideboard) }; case Draft: + case QuestDraft: return new DeckEditorPage[] { new DraftPackPage(), new DeckSectionPage(DeckSection.Main), @@ -231,12 +216,6 @@ public class FDeckEditor extends TabPageScreen { new DeckSectionPage(DeckSection.Main, ItemManagerConfig.QUEST_DECK_EDITOR), new DeckSectionPage(DeckSection.Sideboard, ItemManagerConfig.QUEST_DECK_EDITOR) }; - case QuestDraft: - return new DeckEditorPage[] { - new DraftPackPage(), - new DeckSectionPage(DeckSection.Main), - new DeckSectionPage(DeckSection.Sideboard, ItemManagerConfig.DRAFT_POOL) - }; case PlanarConquest: return new DeckEditorPage[] { new CatalogPage(ItemManagerConfig.CONQUEST_COLLECTION, localizer.getMessage("lblCollection"), FSkinImage.SPELLBOOK), @@ -779,6 +758,12 @@ public class FDeckEditor extends TabPageScreen { } else { max = (limit == CardLimit.Singleton ? 1 : FModel.getPreferences().getPrefInt(FPref.DECK_DEFAULT_CARD_LIMIT)); + + Integer cardCopies = DeckFormat.canHaveSpecificNumberInDeck(card); + if (cardCopies != null) { + max = cardCopies; + } + max -= deck.getMain().count(card); if (deck.has(DeckSection.Sideboard)) { max -= deck.get(DeckSection.Sideboard).count(card); @@ -1741,6 +1726,7 @@ public class FDeckEditor extends TabPageScreen { DeckPreferences.setPlanarDeck(deckStr); break; case Draft: + case QuestDraft: DeckPreferences.setDraftDeck(deckStr); break; case Sealed: @@ -1750,10 +1736,6 @@ public class FDeckEditor extends TabPageScreen { FModel.getQuest().setCurrentDeck(model.toString()); FModel.getQuest().save(); break; - case QuestDraft: - FModel.getQuest().setCurrentDeck(model.toString()); - FModel.getQuest().save(); - break; default: break; } diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/FormatFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/FormatFilter.java index fe9483f34cb..72eba51f635 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/FormatFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/FormatFilter.java @@ -19,6 +19,7 @@ import forge.toolbox.FGroupList; import forge.toolbox.FList; import forge.toolbox.FEvent.FEventHandler; import forge.util.Callback; +import forge.util.Localizer; import forge.util.TextUtil; import forge.util.Utils; @@ -40,13 +41,14 @@ public abstract class FormatFilter extends ItemFilter itemManager0) { super(itemManager0); + final Localizer localizer = Localizer.getInstance(); cbxFormats.setFont(FSkinFont.get(12)); - cbxFormats.addItem("All Sets/Formats"); + cbxFormats.addItem(localizer.getMessage("lblAllSetsFormats")); for (GameFormat format : FModel.getFormats().getFilterList()) { cbxFormats.addItem(format); } - cbxFormats.addItem("Other Formats..."); - cbxFormats.addItem("Choose Sets..."); + cbxFormats.addItem(localizer.getMessage("lblOtherFormats")); + cbxFormats.addItem(localizer.getMessage("lblChooseSets")); selectedFormat = cbxFormats.getText(); cbxFormats.setChangedHandler(new FEventHandler() { diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/HistoricFormatSelect.java b/forge-gui-mobile/src/forge/itemmanager/filters/HistoricFormatSelect.java index ad7831603fa..80bae301afb 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/HistoricFormatSelect.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/HistoricFormatSelect.java @@ -12,6 +12,7 @@ import forge.screens.settings.SettingsScreen; import forge.toolbox.FGroupList; import forge.toolbox.FList; import forge.util.Callback; +import forge.util.Localizer; import forge.util.Utils; import java.util.Arrays; @@ -32,7 +33,7 @@ public class HistoricFormatSelect extends FScreen { private Runnable onCloseCallBack; public HistoricFormatSelect() { - super("Choose Format"); + super(Localizer.getInstance().getMessage("lblChooseFormat")); for (GameFormat.FormatType group:GameFormat.FormatType.values()){ if (group == GameFormat.FormatType.Historic){ for (GameFormat.FormatSubType subgroup:GameFormat.FormatSubType.values()){ diff --git a/forge-gui-mobile/src/forge/itemmanager/filters/TextSearchFilter.java b/forge-gui-mobile/src/forge/itemmanager/filters/TextSearchFilter.java index c2cac6fdcdf..b0f6b1844d5 100644 --- a/forge-gui-mobile/src/forge/itemmanager/filters/TextSearchFilter.java +++ b/forge-gui-mobile/src/forge/itemmanager/filters/TextSearchFilter.java @@ -13,6 +13,7 @@ import forge.toolbox.FDisplayObject; import forge.toolbox.FEvent; import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FTextField; +import forge.util.Localizer; public class TextSearchFilter extends ItemFilter { @@ -78,10 +79,10 @@ public class TextSearchFilter extends ItemFilter { } public String getCaption() { - return txtSearch.getGhostText().substring("Search ".length()); + return txtSearch.getGhostText().substring((Localizer.getInstance().getMessage("lblSearch") + " ").length()); } public void setCaption(String caption0) { - txtSearch.setGhostText("Search " + caption0); + txtSearch.setGhostText(Localizer.getInstance().getMessage("lblSearch") + " " + caption0); } protected class SearchField extends FTextField { @@ -89,7 +90,7 @@ public class TextSearchFilter extends ItemFilter { private SearchField() { setFont(FONT); - setGhostText("Search"); + setGhostText(Localizer.getInstance().getMessage("lblSearch")); setHeight(getDefaultHeight(DEFAULT_FONT)); //set height based on default filter font } diff --git a/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java b/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java index 663be9d606d..d061dbc78e1 100644 --- a/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java +++ b/forge-gui-mobile/src/forge/itemmanager/views/ImageView.java @@ -1,5 +1,6 @@ package forge.itemmanager.views; +import forge.Forge; import forge.Forge.KeyInputAdapter; import forge.Graphics; import forge.assets.FImage; @@ -143,8 +144,8 @@ public class ImageView extends ItemView { } } private final ExpandCollapseButton btnExpandCollapseAll = new ExpandCollapseButton(); - private final FComboBox cbGroupByOptions = new FComboBox<>("Groups: "); - private final FComboBox cbPileByOptions = new FComboBox<>("Piles: "); + private final FComboBox cbGroupByOptions = new FComboBox<>(Localizer.getInstance().getMessage("lblGroups") + " "); + private final FComboBox cbPileByOptions = new FComboBox<>(Localizer.getInstance().getMessage("lblPiles") + " "); public ImageView(ItemManager itemManager0, ItemManagerModel model0) { super(itemManager0, model0); @@ -181,7 +182,7 @@ public class ImageView extends ItemView { getPnlOptions().add(cbPileByOptions); Group group = new Group(""); //add default group - groups.add(group); + groups.add(group); getScroller().add(group); } @@ -300,7 +301,7 @@ public class ImageView extends ItemView { updateLayout(false); return; } - + float offsetTop = focalItem0.getTop() - getScrollValue(); updateLayout(false); setScrollValue(focalItem0.getTop() - offsetTop); @@ -669,7 +670,7 @@ public class ImageView extends ItemView { @Override public String getCaption() { - return "Image View"; + return Localizer.getInstance().getMessage("lblImageView"); } @Override @@ -891,7 +892,7 @@ public class ImageView extends ItemView { public void draw(Graphics g) { final float visibleTop = getScrollValue(); final float visibleBottom = visibleTop + getScroller().getHeight(); - + ItemInfo skippedItem = null; for (ItemInfo itemInfo : items) { if (itemInfo.getBottom() < visibleTop) { @@ -954,9 +955,18 @@ public class ImageView extends ItemView { final float w = getWidth(); final float h = getHeight(); - if (selected) { - g.fillRect(Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, - w + 2 * SEL_BORDER_SIZE, h + 2 * SEL_BORDER_SIZE); + if (selected) { //if round border is enabled, the select highlight is also rounded.. + if (Forge.enableUIMask) { + //fillroundrect has rough/aliased corner + g.fillRoundRect(Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, + w + 2 * SEL_BORDER_SIZE, h + 2 * SEL_BORDER_SIZE, (h - w) / 10); + //drawroundrect has GL_SMOOTH to `smoothen/faux` the aliased corner + g.drawRoundRect(1f, Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, + w + 1.5f * SEL_BORDER_SIZE, h + 1.5f * SEL_BORDER_SIZE, (h - w) / 10); + } + else //default rectangle highlight + g.fillRect(Color.GREEN, x - SEL_BORDER_SIZE, y - SEL_BORDER_SIZE, + w + 2 * SEL_BORDER_SIZE, h + 2 * SEL_BORDER_SIZE); } if (item instanceof PaperCard) { diff --git a/forge-gui-mobile/src/forge/itemmanager/views/ItemListView.java b/forge-gui-mobile/src/forge/itemmanager/views/ItemListView.java index 4db35625d0b..fe737babd46 100644 --- a/forge-gui-mobile/src/forge/itemmanager/views/ItemListView.java +++ b/forge-gui-mobile/src/forge/itemmanager/views/ItemListView.java @@ -34,6 +34,7 @@ import forge.toolbox.FDisplayObject; import forge.toolbox.FList; import com.badlogic.gdx.math.Rectangle; +import forge.util.Localizer; import java.util.ArrayList; import java.util.Collections; @@ -81,7 +82,7 @@ public final class ItemListView extends ItemView { @Override public String getCaption() { - return "List View"; + return Localizer.getInstance().getMessage("lblListView"); } @Override diff --git a/forge-gui-mobile/src/forge/screens/constructed/AvatarSelector.java b/forge-gui-mobile/src/forge/screens/constructed/AvatarSelector.java index 5fa5dfac739..a4de6366815 100644 --- a/forge-gui-mobile/src/forge/screens/constructed/AvatarSelector.java +++ b/forge-gui-mobile/src/forge/screens/constructed/AvatarSelector.java @@ -37,7 +37,7 @@ public class AvatarSelector extends FScreen { } private static final float PADDING = Utils.scale(5); - private static final int COLUMNS = 4; + private static final int COLUMNS = 5; private final int currentIndex; private final List usedAvatars; diff --git a/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java b/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java index 31685d17257..7ecde4cd371 100644 --- a/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java +++ b/forge-gui-mobile/src/forge/screens/constructed/LobbyScreen.java @@ -4,6 +4,7 @@ import java.util.Arrays; import java.util.ArrayList; import java.util.List; +import forge.GuiBase; import forge.deck.CardPool; import forge.deck.Deck; import forge.deck.DeckSection; @@ -301,13 +302,20 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { } /** Saves avatar prefs for players one and two. */ - void updateAvatarPrefs() { + void updateAvatarPrefs() { int pOneIndex = playerPanels.get(0).getAvatarIndex(); int pTwoIndex = playerPanels.get(1).getAvatarIndex(); prefs.setPref(FPref.UI_AVATARS, pOneIndex + "," + pTwoIndex); prefs.save(); } + void updateSleevePrefs() { + int pOneIndex = playerPanels.get(0).getSleeveIndex(); + int pTwoIndex = playerPanels.get(1).getSleeveIndex(); + + prefs.setPref(FPref.UI_SLEEVES, pOneIndex + "," + pTwoIndex); + prefs.save(); + } /** Updates the avatars from preferences on update. */ private void updatePlayersFromPrefs() { @@ -320,6 +328,13 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { playerPanels.get(i).setAvatarIndex(avatarIndex); } + // Sleeves + String[] sleevePrefs = prefs.getPref(FPref.UI_SLEEVES).split(","); + for (int i = 0; i < sleevePrefs.length; i++) { + int sleeveIndex = Integer.parseInt(sleevePrefs[i]); + playerPanels.get(i).setSleeveIndex(sleeveIndex); + } + // Name String prefName = prefs.getPref(FPref.PLAYER_NAME); playerPanels.get(0).setPlayerName(StringUtils.isBlank(prefName) ? Localizer.getInstance().getMessage("lblHuman") : prefName); @@ -334,6 +349,15 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { return usedAvatars; } + List getUsedSleeves() { + List usedSleeves = Arrays.asList(-1,-1,-1,-1,-1,-1,-1,-1); + int i = 0; + for (PlayerPanel pp : playerPanels) { + usedSleeves.set(i++, pp.getSleeveIndex()); + } + return usedSleeves; + } + List getPlayerNames() { List names = new ArrayList<>(); for (PlayerPanel pp : playerPanels) { @@ -350,6 +374,10 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { return playerPanels.get(i).getAvatarIndex(); } + public int getPlayerSleeve(int i) { + return playerPanels.get(i).getSleeveIndex(); + } + ///////////////////////////////////////////// //========== Various listeners in build order @@ -448,6 +476,7 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { DeckType selectedDeckType = deckChooser.getSelectedDeckType(); switch (selectedDeckType){ case STANDARD_CARDGEN_DECK: + case PIONEER_CARDGEN_DECK: case MODERN_CARDGEN_DECK: case LEGACY_CARDGEN_DECK: case VINTAGE_CARDGEN_DECK: @@ -498,6 +527,9 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { updateVariantSelection(); final boolean allowNetworking = lobby.isAllowNetworking(); + + GuiBase.setNetworkplay(allowNetworking); + for (int i = 0; i < cbPlayerCount.getSelectedItem(); i++) { final boolean hasPanel = i < playerPanels.size(); if (i < playerCount) { @@ -527,8 +559,18 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { final LobbySlotType type = slot.getType(); panel.setType(type); - panel.setPlayerName(slot.getName()); - panel.setAvatarIndex(slot.getAvatarIndex()); + if (type != LobbySlotType.AI) { + panel.setPlayerName(slot.getName()); + panel.setAvatarIndex(slot.getAvatarIndex()); + panel.setSleeveIndex(slot.getSleeveIndex()); + } else { + //AI: this one overrides the setplayername if blank + if (panel.getPlayerName().isEmpty()) + panel.setPlayerName(slot.getName()); + //AI: override settings if somehow player changes it for AI + slot.setAvatarIndex(panel.getAvatarIndex()); + slot.setSleeveIndex(panel.getSleeveIndex()); + } panel.setTeam(slot.getTeam()); panel.setIsReady(slot.isReady()); panel.setIsDevMode(slot.isDevMode()); @@ -631,6 +673,18 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { } } + void updateAvatar(final int index, final int avatarIndex) { + if (playerChangeListener != null) { + playerChangeListener.update(index, UpdateLobbyPlayerEvent.avatarUpdate(avatarIndex)); + } + } + + void updateSleeve(final int index, final int sleeveIndex) { + if (playerChangeListener != null) { + playerChangeListener.update(index, UpdateLobbyPlayerEvent.sleeveUpdate(sleeveIndex)); + } + } + void setReady(final int index, final boolean ready) { if (ready) { updateDeck(index); @@ -667,7 +721,7 @@ public abstract class LobbyScreen extends LaunchScreen implements ILobbyView { private UpdateLobbyPlayerEvent getSlot(final int index) { final PlayerPanel panel = playerPanels.get(index); - return UpdateLobbyPlayerEvent.create(panel.getType(), panel.getPlayerName(), panel.getAvatarIndex(), panel.getTeam(), panel.isArchenemy(), panel.isReady(), panel.isDevMode(), panel.getAiOptions()); + return UpdateLobbyPlayerEvent.create(panel.getType(), panel.getPlayerName(), panel.getAvatarIndex(), panel.getSleeveIndex(), panel.getTeam(), panel.isArchenemy(), panel.isReady(), panel.isDevMode(), panel.getAiOptions()); } public List getPlayerPanels() { diff --git a/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java b/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java index a2540d55f25..028a274db9a 100644 --- a/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java +++ b/forge-gui-mobile/src/forge/screens/constructed/PlayerPanel.java @@ -59,7 +59,8 @@ public class PlayerPanel extends FContainer { private final FLabel nameRandomiser; private final FLabel avatarLabel = new FLabel.Builder().opaque(true).iconScaleFactor(0.99f).alphaComposite(1).iconInBackground(true).build(); - private int avatarIndex; + private final FLabel sleeveLabel = new FLabel.Builder().opaque(true).iconScaleFactor(0.99f).alphaComposite(1).iconInBackground(true).build(); + private int avatarIndex, sleeveIndex; final Localizer localizer = Localizer.getInstance(); private final FTextField txtPlayerName = new FTextField(localizer.getMessage("lblPlayerName")); @@ -98,6 +99,7 @@ public class PlayerPanel extends FContainer { setType(slot.getType()); setPlayerName(slot.getName()); setAvatarIndex(slot.getAvatarIndex()); + setSleeveIndex(slot.getSleeveIndex()); devModeSwitch = new FToggleSwitch(localizer.getMessage("lblNormal"), localizer.getMessage("lblDevMode")); devModeSwitch.setVisible(isNetworkHost()); @@ -189,6 +191,9 @@ public class PlayerPanel extends FContainer { createAvatar(); add(avatarLabel); + createSleeve(); + add(sleeveLabel); + createNameEditor(); add(newLabel(localizer.getMessage("lblName") + ":")); add(txtPlayerName); @@ -299,12 +304,16 @@ public class PlayerPanel extends FContainer { float y = PADDING; float fieldHeight = txtPlayerName.getHeight(); float avatarSize = 2 * fieldHeight + PADDING; + float sleeveSize = 2 * fieldHeight + PADDING; + float sleeveSizeW = (sleeveSize/4)*3; float dy = fieldHeight + PADDING; avatarLabel.setBounds(x, y, avatarSize, avatarSize); x += avatarSize + PADDING; + sleeveLabel.setBounds(x, y, sleeveSizeW, sleeveSize); + x += sleeveSizeW + PADDING; float w = width - x - fieldHeight - 2 * PADDING; - txtPlayerName.setBounds(x, y, w, fieldHeight); + txtPlayerName.setBounds(x, y, w, fieldHeight); //add space for card back x += w + PADDING; nameRandomiser.setBounds(x, y, fieldHeight, fieldHeight); @@ -312,8 +321,8 @@ public class PlayerPanel extends FContainer { humanAiSwitch.setSize(humanAiSwitch.getAutoSizeWidth(fieldHeight), fieldHeight); x = width - humanAiSwitch.getWidth() - PADDING; humanAiSwitch.setPosition(x, y); - w = x - avatarSize - 3 * PADDING; - x = avatarSize + 2 * PADDING; + w = x - (avatarSize+sleeveSizeW+PADDING) - 3 * PADDING; + x = (avatarSize+sleeveSizeW+PADDING) + 2 * PADDING; if (cbArchenemyTeam.isVisible()) { cbArchenemyTeam.setBounds(x, y, w, fieldHeight); } @@ -411,6 +420,7 @@ public class PlayerPanel extends FContainer { //update may edit in-case it changed as a result of the AI change setMayEdit(screen.getLobby().mayEdit(index)); setAvatarIndex(slot.getAvatarIndex()); + setSleeveIndex(slot.getSleeveIndex()); setPlayerName(slot.getName()); } } @@ -470,6 +480,7 @@ public class PlayerPanel extends FContainer { setAvatarIndex(result); if (index < 2) { + screen.updateAvatar(index, result); screen.updateAvatarPrefs(); } if (allowNetworking) { @@ -480,6 +491,26 @@ public class PlayerPanel extends FContainer { } }; + private FEventHandler sleeveCommand = new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + SleevesSelector.show(getPlayerName(), sleeveIndex, screen.getUsedSleeves(), new Callback() { + @Override + public void run(Integer result) { + setSleeveIndex(result); + + if (index < 2) { + screen.updateSleeve(index, result); + screen.updateSleevePrefs(); + } + if (allowNetworking) { + screen.firePlayerChangeListener(index); + } + } + }); + } + }; + public void setDeckSelectorButtonText(String text) { btnDeck.setText(text); } @@ -664,6 +695,17 @@ public class PlayerPanel extends FContainer { avatarLabel.setCommand(avatarCommand); } + private void createSleeve() { + String[] currentPrefs = prefs.getPref(FPref.UI_SLEEVES).split(","); + if (index < currentPrefs.length) { + setSleeveIndex(Integer.parseInt(currentPrefs[index])); + } + else { + setSleeveIndex(SleevesSelector.getRandomSleeves(screen.getUsedSleeves())); + } + sleeveLabel.setCommand(sleeveCommand); + } + public void setAvatarIndex(int newAvatarIndex) { avatarIndex = newAvatarIndex; if (avatarIndex != -1) { @@ -674,10 +716,24 @@ public class PlayerPanel extends FContainer { } } + public void setSleeveIndex(int newSleeveIndex) { + sleeveIndex = newSleeveIndex; + if (sleeveIndex != -1) { + sleeveLabel.setIcon(new FTextureRegionImage(FSkin.getSleeves().get(newSleeveIndex))); + } + else { + sleeveLabel.setIcon(null); + } + } + public int getAvatarIndex() { return avatarIndex; } + public int getSleeveIndex() { + return sleeveIndex; + } + public void setPlayerName(String string) { txtPlayerName.setText(string); } @@ -759,6 +815,7 @@ public class PlayerPanel extends FContainer { if (mayEdit == mayEdit0) { return; } mayEdit = mayEdit0; avatarLabel.setEnabled(mayEdit); + sleeveLabel.setEnabled(mayEdit); txtPlayerName.setEnabled(mayEdit); nameRandomiser.setEnabled(mayEdit); humanAiSwitch.setEnabled(mayEdit); diff --git a/forge-gui-mobile/src/forge/screens/constructed/SleevesSelector.java b/forge-gui-mobile/src/forge/screens/constructed/SleevesSelector.java new file mode 100644 index 00000000000..523edea21b8 --- /dev/null +++ b/forge-gui-mobile/src/forge/screens/constructed/SleevesSelector.java @@ -0,0 +1,119 @@ +package forge.screens.constructed; + +import forge.Forge; +import forge.assets.FImage; +import forge.assets.FSkin; +import forge.assets.FSkinImage; +import forge.assets.FTextureRegionImage; +import forge.screens.FScreen; +import forge.toolbox.FDisplayObject; +import forge.toolbox.FEvent; +import forge.toolbox.FEvent.FEventHandler; +import forge.toolbox.FLabel; +import forge.toolbox.FScrollPane; +import forge.util.Callback; +import forge.util.MyRandom; +import forge.util.Utils; + +import java.util.List; +import java.util.Map; + +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.utils.Align; + +public class SleevesSelector extends FScreen { + public static int getRandomSleeves(List usedSleeves) { + int random = 0; + do { + random = MyRandom.getRandom().nextInt(FSkin.getSleeves().size()); + } while (usedSleeves.contains(random)); + return random; + } + + public static void show(final String playerName, final int currentIndex0, final List usedSleeves0, final Callback callback0) { + SleevesSelector selector = new SleevesSelector(playerName, currentIndex0, usedSleeves0, callback0); + Forge.openScreen(selector); + } + + private static final float PADDING = Utils.scale(5); + private static final int COLUMNS = 5; + + private final int currentIndex; + private final List usedSleeves; + private final Callback callback; + private final FScrollPane scroller = new FScrollPane() { + @Override + protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) { + int rowCount = 0; + float x = PADDING; + float y = PADDING; + float labelSize = (visibleWidth - (COLUMNS + 1) * PADDING) / COLUMNS; + for (FDisplayObject lbl : scroller.getChildren()) { + if (rowCount == COLUMNS) { //wrap to next line + x = PADDING; + y += labelSize + PADDING; + rowCount = 0; + } + lbl.setBounds(x, y, labelSize, labelSize); + x += labelSize + PADDING; + rowCount++; + } + return new ScrollBounds(visibleWidth, y + labelSize + PADDING); + } + }; + + private SleevesSelector(final String playerName, final int currentIndex0, final List usedSleeves0, final Callback callback0) { + super("Select Sleeves for " + playerName); + + currentIndex = currentIndex0; + usedSleeves = usedSleeves0; + callback = callback0; + + //add label for selecting random sleeves first + addSleevesLabel(FSkinImage.UNKNOWN, -1); + + //add label for currently selected sleeves next + final Map sleeveMap = FSkin.getSleeves(); + addSleevesLabel(new FTextureRegionImage(sleeveMap.get(currentIndex)), currentIndex); + + //add label for remaining sleeves + for (final Integer i : sleeveMap.keySet()) { + if (currentIndex != i) { + addSleevesLabel(new FTextureRegionImage(sleeveMap.get(i)), i); + } + } + + add(scroller); + } + + private void addSleevesLabel(final FImage img, final int index) { + final FLabel lbl = new FLabel.Builder().icon(img).iconScaleFactor(0.99f).align(Align.center) + .iconInBackground(true).selectable(true).selected(currentIndex == index) + .build(); + + if (index == -1) { + lbl.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + callback.run(getRandomSleeves(usedSleeves)); + Forge.back(); + } + }); + } + else { + lbl.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + callback.run(index); + Forge.back(); + } + }); + } + scroller.add(lbl); + } + + @Override + protected void doLayout(float startY, float width, float height) { + scroller.setBounds(0, startY, width, height - startY); + } +} diff --git a/forge-gui-mobile/src/forge/screens/gauntlet/NewGauntletScreen.java b/forge-gui-mobile/src/forge/screens/gauntlet/NewGauntletScreen.java index ad7b5de1967..2388dc0758f 100644 --- a/forge-gui-mobile/src/forge/screens/gauntlet/NewGauntletScreen.java +++ b/forge-gui-mobile/src/forge/screens/gauntlet/NewGauntletScreen.java @@ -23,15 +23,18 @@ import forge.toolbox.FTextArea; import forge.toolbox.GuiChoose; import forge.toolbox.ListChooser; import forge.util.Callback; +import forge.util.Localizer; import forge.util.Utils; public class NewGauntletScreen extends LaunchScreen { private static final float PADDING = Utils.scale(10); + private final Localizer localizer = Localizer.getInstance(); + private final FTextArea lblDesc = add(new FTextArea(false, - "In Gauntlet mode, you select a deck and play against multiple opponents.\n\n" + - "Configure how many opponents you wish to face and what decks or types of decks they will play.\n\n" + - "Then, try to beat all AI opponents without losing a match.")); + localizer.getMessage("lblGauntletText1") + "\n\n" + + localizer.getMessage("lblGauntletText2") + "\n\n" + + localizer.getMessage("lblGauntletText3"))); public NewGauntletScreen() { super(null, NewGameMenu.getMenu()); @@ -51,44 +54,41 @@ public class NewGauntletScreen extends LaunchScreen { @Override protected void startMatch() { - GuiChoose.oneOrNone("Select a Gauntlet Type", new String[] { - "Quick Gauntlet", - "Custom Gauntlet", - "Gauntlet Contest", + GuiChoose.oneOrNone(localizer.getMessage("lblSelectGauntletType"), new String[] { + localizer.getMessage("lblQuickGauntlet"), + localizer.getMessage("lblCustomGauntlet"), + localizer.getMessage("lblGauntletContest"), }, new Callback() { @Override public void run(String result) { if (result == null) { return; } - switch (result) { - case "Quick Gauntlet": + if (localizer.getMessage("lblQuickGauntlet").equals(result)) { createQuickGauntlet(); - break; - case "Custom Gauntlet": + } else if(localizer.getMessage("lblCustomGauntlet").equals(result)) { createCustomGauntlet(); - break; - default: + } else { createGauntletContest(); - break; } } }); } private void createQuickGauntlet() { - GuiChoose.getInteger("How many opponents are you willing to face?", 3, 50, new Callback() { + GuiChoose.getInteger(localizer.getMessage("lblHowManyOpponents"), 3, 50, new Callback() { @Override public void run(final Integer numOpponents) { if (numOpponents == null) { return; } ListChooser chooser = new ListChooser<>( - "Choose allowed deck types for opponents", 0, 11, Arrays.asList(DeckType.CUSTOM_DECK, + localizer.getMessage("lblChooseAllowedDeckTypeOpponents"), 0, 11, Arrays.asList(DeckType.CUSTOM_DECK, DeckType.PRECONSTRUCTED_DECK, DeckType.QUEST_OPPONENT_DECK, DeckType.COLOR_DECK, DeckType.STANDARD_COLOR_DECK, DeckType.STANDARD_CARDGEN_DECK, DeckType.MODERN_COLOR_DECK, + DeckType.PIONEER_CARDGEN_DECK, DeckType.MODERN_CARDGEN_DECK, DeckType.LEGACY_CARDGEN_DECK, DeckType.VINTAGE_CARDGEN_DECK, @@ -99,7 +99,7 @@ public class NewGauntletScreen extends LaunchScreen { return; } - FDeckChooser.promptForDeck("Select Your Deck", GameType.Gauntlet, false, new Callback() { + FDeckChooser.promptForDeck(localizer.getMessage("lblSelectYourDeck"), GameType.Gauntlet, false, new Callback() { @Override public void run(Deck userDeck) { if (userDeck == null) { @@ -118,7 +118,7 @@ public class NewGauntletScreen extends LaunchScreen { } private void createCustomGauntlet() { - GuiChoose.getInteger("How many opponents are you willing to face?", 3, 50, new Callback() { + GuiChoose.getInteger(localizer.getMessage("lblHowManyOpponents"), 3, 50, new Callback() { @Override public void run(final Integer numOpponents) { if (numOpponents == null) { return; } @@ -132,7 +132,7 @@ public class NewGauntletScreen extends LaunchScreen { private void promptForAiDeck(final GauntletData gauntlet, final int numOpponents) { final int opponentNum = gauntlet.getDecks().size() + 1; - FDeckChooser.promptForDeck("Select Deck for Opponent " + opponentNum + " / " + numOpponents, GameType.Gauntlet, true, new Callback() { + FDeckChooser.promptForDeck(localizer.getMessage("lblSelectDeckForOpponent") + " " + opponentNum + " / " + numOpponents, GameType.Gauntlet, true, new Callback() { @Override public void run(Deck aiDeck) { if (aiDeck == null) { return; } @@ -145,7 +145,7 @@ public class NewGauntletScreen extends LaunchScreen { } else { //once all ai decks have been selected, prompt for user deck - FDeckChooser.promptForDeck("Select Your Deck", GameType.Gauntlet, false, new Callback() { + FDeckChooser.promptForDeck(localizer.getMessage("lblSelectYourDeck"), GameType.Gauntlet, false, new Callback() { @Override public void run(Deck userDeck) { if (userDeck == null) { return; } @@ -170,12 +170,12 @@ public class NewGauntletScreen extends LaunchScreen { } } - GuiChoose.oneOrNone("Select Gauntlet Contest", contests, new Callback() { + GuiChoose.oneOrNone(localizer.getMessage("lblSelectGauntletContest"), contests, new Callback() { @Override public void run(final GauntletData contest) { if (contest == null) { return; } - FDeckChooser.promptForDeck("Select Your Deck", GameType.Gauntlet, false, new Callback() { + FDeckChooser.promptForDeck(localizer.getMessage("lblSelectYourDeck"), GameType.Gauntlet, false, new Callback() { @Override public void run(final Deck userDeck) { if (userDeck == null) { return; } diff --git a/forge-gui-mobile/src/forge/screens/home/LoadGameMenu.java b/forge-gui-mobile/src/forge/screens/home/LoadGameMenu.java index c38c3f6c48b..9e29a3addc1 100644 --- a/forge-gui-mobile/src/forge/screens/home/LoadGameMenu.java +++ b/forge-gui-mobile/src/forge/screens/home/LoadGameMenu.java @@ -19,15 +19,13 @@ import forge.toolbox.FEvent.FEventHandler; import forge.util.Localizer; public class LoadGameMenu extends FPopupMenu { - final static Localizer localizer = Localizer.getInstance(); - public enum LoadGameScreen { - BoosterDraft(localizer.getMessage("lblBoosterDraft"), FSkinImage.HAND, LoadDraftScreen.class), - SealedDeck(localizer.getMessage("lblSealedDeck"), FSkinImage.PACK, LoadSealedScreen.class), - QuestMode(localizer.getMessage("lblQuestMode"), FSkinImage.QUEST_ZEP, LoadQuestScreen.class), - PlanarConquest(localizer.getMessage("lblPlanarConquest"), FSkinImage.MULTIVERSE, LoadConquestScreen.class), - Gauntlet(localizer.getMessage("lblGauntlet"), FSkinImage.ALPHASTRIKE, LoadGauntletScreen.class); - + BoosterDraft("Booster Draft", FSkinImage.HAND, LoadDraftScreen.class), + SealedDeck("Sealed Deck", FSkinImage.PACK, LoadSealedScreen.class), + QuestMode("Quest Mode", FSkinImage.QUEST_ZEP, LoadQuestScreen.class), + PlanarConquest("Planar Conquest", FSkinImage.MULTIVERSE, LoadConquestScreen.class), + Gauntlet("Gauntlet", FSkinImage.ALPHASTRIKE, LoadGauntletScreen.class); + private final FMenuItem item; private final Class screenClass; private FScreen screen; @@ -47,7 +45,7 @@ public class LoadGameMenu extends FPopupMenu { if (screen == null) { //don't initialize screen until it's opened the first time try { screen = screenClass.newInstance(); - screen.setHeaderCaption(localizer.getMessage("lblLoadGame") + " - " + item.getText()); + screen.setHeaderCaption(Localizer.getInstance().getMessage("lblLoadGame") + " - " + item.getText()); } catch (Exception e) { e.printStackTrace(); diff --git a/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java b/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java index bc23e309633..a740859f49b 100644 --- a/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java +++ b/forge-gui-mobile/src/forge/screens/home/puzzle/PuzzleScreen.java @@ -18,6 +18,7 @@ import forge.toolbox.FOptionPane; import forge.toolbox.FTextArea; import forge.toolbox.GuiChoose; import forge.util.Callback; +import forge.util.Localizer; import forge.util.Utils; import java.util.ArrayList; import java.util.Collections; @@ -28,10 +29,9 @@ public class PuzzleScreen extends LaunchScreen { private static final float PADDING = Utils.scale(10); private final FTextArea lblDesc = add(new FTextArea(false, - "Puzzle Mode loads in a puzzle that you have to win in a predetermined time/way.\n\n" + - "To begin, press the Start button below, then select a puzzle from a list.\n\n" + - "Your objective will be displayed in a pop-up window when the puzzle starts and also " + - "specified on a special effect card which will be placed in your command zone.")); + Localizer.getInstance().getMessage("lblPuzzleText1") + "\n\n" + + Localizer.getInstance().getMessage("lblPuzzleText2") + "\n\n" + + Localizer.getInstance().getMessage("lblPuzzleText3"))); public PuzzleScreen() { super(null, NewGameMenu.getMenu()); @@ -54,10 +54,10 @@ public class PuzzleScreen extends LaunchScreen { final ArrayList puzzles = PuzzleIO.loadPuzzles(); Collections.sort(puzzles); - GuiChoose.one("Choose a puzzle", puzzles, new Callback() { + GuiChoose.one(Localizer.getInstance().getMessage("lblChooseAPuzzle"), puzzles, new Callback() { @Override public void run(final Puzzle chosen) { - LoadingOverlay.show("Loading the puzzle...", new Runnable() { + LoadingOverlay.show(Localizer.getInstance().getMessage("lblLoadingThePuzzle"), new Runnable() { @Override public void run() { // Load selected puzzle diff --git a/forge-gui-mobile/src/forge/screens/limited/LoadDraftScreen.java b/forge-gui-mobile/src/forge/screens/limited/LoadDraftScreen.java index b3ee50cfb08..0e0d3da2fbe 100644 --- a/forge-gui-mobile/src/forge/screens/limited/LoadDraftScreen.java +++ b/forge-gui-mobile/src/forge/screens/limited/LoadDraftScreen.java @@ -30,6 +30,7 @@ import forge.match.HostedMatch; import forge.model.FModel; import forge.player.GamePlayerUtil; import forge.toolbox.FComboBox; +import forge.util.Localizer; import forge.util.gui.SGuiChoose; import java.util.ArrayList; import java.util.List; @@ -37,20 +38,20 @@ import java.util.List; public class LoadDraftScreen extends LaunchScreen { private final DeckManager lstDecks = add(new DeckManager(GameType.Draft)); private final FLabel lblTip = add(new FLabel.Builder() - .text("Double-tap to edit deck (Long-press to view)") + .text(Localizer.getInstance().getMessage("lblDoubleTapToEditDeck")) .textColor(FLabel.INLINE_LABEL_COLOR) .align(Align.center).font(FSkinFont.get(12)).build()); private final FSkinFont GAME_MODE_FONT= FSkinFont.get(12); - private final FLabel lblMode = add(new FLabel.Builder().text("Mode:").font(GAME_MODE_FONT).build()); + private final FLabel lblMode = add(new FLabel.Builder().text(Localizer.getInstance().getMessage("lblMode")).font(GAME_MODE_FONT).build()); private final FComboBox cbMode = add(new FComboBox<>()); public LoadDraftScreen() { super(null, LoadGameMenu.getMenu()); cbMode.setFont(GAME_MODE_FONT); - cbMode.addItem("Gauntlet"); - cbMode.addItem("Single Match"); + cbMode.addItem(Localizer.getInstance().getMessage("lblGauntlet")); + cbMode.addItem(Localizer.getInstance().getMessage("lblSingleMatch")); lstDecks.setup(ItemManagerConfig.DRAFT_DECKS); lstDecks.setItemActivateHandler(new FEventHandler() { @@ -98,17 +99,18 @@ public class LoadDraftScreen extends LaunchScreen { FThreads.invokeInBackgroundThread(new Runnable() { @Override public void run() { + Localizer localizer = Localizer.getInstance(); final DeckProxy humanDeck = lstDecks.getSelectedItem(); if (humanDeck == null) { - FOptionPane.showErrorDialog("You must select an existing deck or build a deck from a new booster draft game.", "No Deck"); + FOptionPane.showErrorDialog(localizer.getMessage("lblYouMustSelectExistingDeck"), localizer.getMessage("lblNoDeck")); return; } // TODO: if booster draft tournaments are supported in the future, add the possibility to choose them here - final boolean gauntlet = cbMode.getSelectedItem().equals("Gauntlet"); + final boolean gauntlet = cbMode.getSelectedItem().equals(localizer.getMessage("lblGauntlet")); if (gauntlet) { - final Integer rounds = SGuiChoose.getInteger("How many opponents are you willing to face?", + final Integer rounds = SGuiChoose.getInteger(localizer.getMessage("lblHowManyOpponents"), 1, FModel.getDecks().getDraft().get(humanDeck.getName()).getAiDecks().size()); if (rounds == null) { return; @@ -121,7 +123,7 @@ public class LoadDraftScreen extends LaunchScreen { return; } - LoadingOverlay.show("Loading new game...", new Runnable() { + LoadingOverlay.show(localizer.getMessage("lblLoadingNewGame"), new Runnable() { @Override public void run() { FModel.getGauntletMini().resetGauntletDraft(); @@ -131,7 +133,7 @@ public class LoadDraftScreen extends LaunchScreen { } }); } else { - final Integer aiIndex = SGuiChoose.getInteger("Which opponent would you like to face?", + final Integer aiIndex = SGuiChoose.getInteger(localizer.getMessage("lblWhichOpponentWouldYouLikeToFace"), 1, FModel.getDecks().getDraft().get(humanDeck.getName()).getAiDecks().size()); if (aiIndex == null) { return; // Cancel was pressed @@ -146,7 +148,7 @@ public class LoadDraftScreen extends LaunchScreen { FThreads.invokeInEdtLater(new Runnable() { @Override public void run() { - LoadingOverlay.show("Loading new game...", new Runnable() { + LoadingOverlay.show(localizer.getMessage("lblLoadingNewGame"), new Runnable() { @Override public void run() { if (!checkDeckLegality(humanDeck)) { @@ -177,7 +179,7 @@ public class LoadDraftScreen extends LaunchScreen { if (FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY)) { String errorMessage = GameType.Draft.getDeckFormat().getDeckConformanceProblem(humanDeck.getDeck()); if (errorMessage != null) { - FOptionPane.showErrorDialog("Your deck " + errorMessage + "\nPlease edit or choose a different deck.", "Invalid Deck"); + FOptionPane.showErrorDialog(Localizer.getInstance().getMessage("lblInvalidDeckDesc").replace("%n", errorMessage), Localizer.getInstance().getMessage("lblInvalidDeck")); return false; } } diff --git a/forge-gui-mobile/src/forge/screens/limited/NewDraftScreen.java b/forge-gui-mobile/src/forge/screens/limited/NewDraftScreen.java index b7ca199b0e2..9e96be6cb4e 100644 --- a/forge-gui-mobile/src/forge/screens/limited/NewDraftScreen.java +++ b/forge-gui-mobile/src/forge/screens/limited/NewDraftScreen.java @@ -11,6 +11,7 @@ import forge.screens.LoadingOverlay; import forge.screens.home.NewGameMenu; import forge.toolbox.FLabel; import forge.toolbox.FTextArea; +import forge.util.Localizer; import forge.util.ThreadUtil; import forge.util.Utils; import forge.util.gui.SGuiChoose; @@ -19,9 +20,9 @@ public class NewDraftScreen extends LaunchScreen { private static final float PADDING = Utils.scale(10); private final FTextArea lblDesc = add(new FTextArea(false, - "In Draft mode, three booster packs are rotated around eight players.\n\n" + - "Build a deck from the cards you choose. The AI will do the same.\n\n" + - "Then, play against any number of the AI opponents.")); + Localizer.getInstance().getMessage("lblDraftText1") + "\n\n" + + Localizer.getInstance().getMessage("lblDraftText2") + "\n\n" + + Localizer.getInstance().getMessage("lblDraftText3"))); public NewDraftScreen() { super(null, NewGameMenu.getMenu()); @@ -44,7 +45,7 @@ public class NewDraftScreen extends LaunchScreen { ThreadUtil.invokeInGameThread(new Runnable() { //must run in game thread to prevent blocking UI thread @Override public void run() { - final LimitedPoolType poolType = SGuiChoose.oneOrNone("Choose Draft Format", LimitedPoolType.values()); + final LimitedPoolType poolType = SGuiChoose.oneOrNone(Localizer.getInstance().getMessage("lblChooseDraftFormat"), LimitedPoolType.values()); if (poolType == null) { return; } final BoosterDraft draft = BoosterDraft.createDraft(poolType); @@ -53,7 +54,7 @@ public class NewDraftScreen extends LaunchScreen { FThreads.invokeInEdtLater(new Runnable() { @Override public void run() { - LoadingOverlay.show("Loading new draft...", new Runnable() { + LoadingOverlay.show(Localizer.getInstance().getMessage("lblLoadingNewDraft"), new Runnable() { @Override public void run() { Forge.openScreen(new DraftingProcessScreen(draft, EditorType.Draft, null)); diff --git a/forge-gui-mobile/src/forge/screens/limited/NewSealedScreen.java b/forge-gui-mobile/src/forge/screens/limited/NewSealedScreen.java index 9207742cb8f..5b0914d515b 100644 --- a/forge-gui-mobile/src/forge/screens/limited/NewSealedScreen.java +++ b/forge-gui-mobile/src/forge/screens/limited/NewSealedScreen.java @@ -12,6 +12,7 @@ import forge.screens.LaunchScreen; import forge.screens.home.NewGameMenu; import forge.toolbox.FLabel; import forge.toolbox.FTextArea; +import forge.util.Localizer; import forge.util.ThreadUtil; import forge.util.Utils; @@ -19,9 +20,9 @@ public class NewSealedScreen extends LaunchScreen { private static final float PADDING = Utils.scale(10); private final FTextArea lblDesc = add(new FTextArea(false, - "In Sealed mode, you build a deck from booster packs (maximum 10).\n\n" + - "Build a deck from the cards you receive. A number of AI opponents will do the same.\n\n" + - "Then, play against each of the AI opponents.")); + Localizer.getInstance().getMessage("lblSealedText2") + "\n\n" + + Localizer.getInstance().getMessage("lblSealedText3") + "\n\n" + + Localizer.getInstance().getMessage("lblSealedText4"))); public NewSealedScreen() { super(null, NewGameMenu.getMenu()); diff --git a/forge-gui-mobile/src/forge/screens/match/MatchController.java b/forge-gui-mobile/src/forge/screens/match/MatchController.java index 8bc333ceb91..cc8e860572a 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchController.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchController.java @@ -7,6 +7,8 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import forge.FThreads; +import forge.assets.FSkinImage; import forge.util.Localizer; import org.apache.commons.lang3.StringUtils; @@ -68,6 +70,8 @@ public class MatchController extends AbstractGuiGame { private static final Map avatarImages = new HashMap<>(); + private static final Map sleeveImages = new HashMap<>(); + private static HostedMatch hostedMatch; private static MatchScreen view; @@ -100,14 +104,38 @@ public class MatchController extends AbstractGuiGame { return avatar; } + public static FImage getPlayerSleeve(final PlayerView p) { + if (p == null) + return FSkinImage.UNKNOWN; + final String lp = p.getLobbyPlayerName(); + FImage sleeve = sleeveImages.get(lp); + if (sleeve == null) { + sleeve = new FTextureRegionImage(FSkin.getSleeves().get(p.getSleeveIndex())); + } + return sleeve; + } + @Override public void refreshCardDetails(final Iterable cards) { //ensure cards appear in the correct row of the field for (final VPlayerPanel pnl : view.getPlayerPanels().values()) { - pnl.getField().update(); + pnl.getField().update(true); } } + @Override + public void refreshField() { + if(!GuiBase.isNetworkplay()) //TODO alternate method for update Netplay... + return; + if(getGameView() == null) + return; + if(getGameView().getPhase() == null) + return; + if (getGameView().getPhase().phaseforUpdateField()) + for (final VPlayerPanel pnl : view.getPlayerPanels().values()) + pnl.getField().update(false); + } + public boolean hotSeatMode() { return FModel.getPreferences().getPrefBoolean(FPref.MATCH_HOT_SEAT_MODE); } @@ -363,6 +391,42 @@ public class MatchController extends AbstractGuiGame { } } + @Override + public void setSelectables(final Iterable cards) { + super.setSelectables(cards); + // update zones on tabletop and floating zones - non-selectable cards may be rendered differently + FThreads.invokeInEdtNowOrLater(new Runnable() { + @Override public final void run() { + for (final PlayerView p : getGameView().getPlayers()) { + if ( p.getCards(ZoneType.Battlefield) != null ) { + updateCards(p.getCards(ZoneType.Battlefield)); + } + if ( p.getCards(ZoneType.Hand) != null ) { + updateCards(p.getCards(ZoneType.Hand)); + } + } + } + }); + } + + @Override + public void clearSelectables() { + super.clearSelectables(); + // update zones on tabletop and floating zones - non-selectable cards may be rendered differently + FThreads.invokeInEdtNowOrLater(new Runnable() { + @Override public final void run() { + for (final PlayerView p : getGameView().getPlayers()) { + if ( p.getCards(ZoneType.Battlefield) != null ) { + updateCards(p.getCards(ZoneType.Battlefield)); + } + if ( p.getCards(ZoneType.Hand) != null ) { + updateCards(p.getCards(ZoneType.Hand)); + } + } + } + }); + } + @Override public void afterGameEnd() { Forge.back(); diff --git a/forge-gui-mobile/src/forge/screens/match/MatchScreen.java b/forge-gui-mobile/src/forge/screens/match/MatchScreen.java index 4682dec6ac8..bd61f09d006 100644 --- a/forge-gui-mobile/src/forge/screens/match/MatchScreen.java +++ b/forge-gui-mobile/src/forge/screens/match/MatchScreen.java @@ -376,6 +376,14 @@ public class MatchScreen extends FScreen { TargetingOverlay.drawArrow(g, blocker, attacker); } } + //player + if (is4Player() || is3Player()) { + int numplayers = is3Player() ? 3 : 4; + for (final PlayerView p : game.getPlayers()) { + if (combat.getAttackersOf(p).contains(attacker)) + TargetingOverlay.drawArrow(g, attacker, p, numplayers); + } + } } } @@ -395,7 +403,7 @@ public class MatchScreen extends FScreen { return getActivePrompt().getBtnCancel().trigger(); //trigger Cancel if can't trigger OK case Keys.ESCAPE: if (!FModel.getPreferences().getPrefBoolean(FPref.UI_ALLOW_ESC_TO_END_TURN)) { - if (getActivePrompt().getBtnCancel().getText().equals("End Turn")) { + if (getActivePrompt().getBtnCancel().getText().equals(Localizer.getInstance().getMessage("lblEndTurn"))) { return false; } } diff --git a/forge-gui-mobile/src/forge/screens/match/TargetingOverlay.java b/forge-gui-mobile/src/forge/screens/match/TargetingOverlay.java index 658c844acef..3c28401be23 100644 --- a/forge-gui-mobile/src/forge/screens/match/TargetingOverlay.java +++ b/forge-gui-mobile/src/forge/screens/match/TargetingOverlay.java @@ -79,6 +79,11 @@ public class TargetingOverlay { CardAreaPanel.get(endCard).getTargetingArrowOrigin(), connects); } + public static void drawArrow(Graphics g, CardView startCard, PlayerView targetPlayer, int numplayers) { + drawArrow(g, CardAreaPanel.get(startCard).getTargetingArrowOrigin(), + MatchController.getView().getPlayerPanel(targetPlayer).getAvatar().getTargetingArrowOrigin(numplayers), + ArcConnection.FoesAttacking); + } public static void drawArrow(Graphics g, Vector2 start, CardView targetCard, ArcConnection connects) { drawArrow(g, start, CardAreaPanel.get(targetCard).getTargetingArrowOrigin(), diff --git a/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java b/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java index e8b112f01e3..57d1baaad5b 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VAvatar.java @@ -45,10 +45,15 @@ public class VAvatar extends FDisplayObject { } public Vector2 getTargetingArrowOrigin() { + return getTargetingArrowOrigin(2); + } + public Vector2 getTargetingArrowOrigin(int numplayers) { Vector2 origin = new Vector2(screenPos.x, screenPos.y); - origin.x += WIDTH * 0.75f; - if (origin.y < MatchController.getView().getHeight() / 2) { + float modx = numplayers > 2 ? 0.25f : 0.75f; + + origin.x += WIDTH * modx; + if (origin.y < MatchController.getView().getHeight() / numplayers) { origin.y += HEIGHT * 0.75f; //target bottom right corner if on top half of screen } else { diff --git a/forge-gui-mobile/src/forge/screens/match/views/VField.java b/forge-gui-mobile/src/forge/screens/match/views/VField.java index 20ce926a90b..1447408b257 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VField.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VField.java @@ -40,8 +40,11 @@ public class VField extends FContainer { return cardPanels; } - public void update() { - FThreads.invokeInEdtNowOrLater(updateRoutine); + public void update(boolean invokeInEdtNowOrLater) { + if (invokeInEdtNowOrLater) + FThreads.invokeInEdtNowOrLater(updateRoutine); + else + FThreads.invokeInEdtLater(updateRoutine); } private final Runnable updateRoutine = new Runnable() { @@ -107,21 +110,40 @@ public class VField extends FContainer { } final String cardName = card.getCurrentState().getName(); for (CardView c : cardsOfType) { - if (!c.hasCardAttachments() && - cardName.equals(c.getCurrentState().getName()) && - card.hasSameCounters(c) && - card.getCurrentState().getKeywordKey().equals(c.getCurrentState().getKeywordKey()) && - card.isTapped() == c.isTapped() && // don't stack tapped tokens on untapped tokens - card.isSick() == c.isSick() && //don't stack sick tokens on non sick - card.isToken() == c.isToken()) { //don't stack tokens on top of non-tokens - CardAreaPanel cPanel = CardAreaPanel.get(c); - while (cPanel.getNextPanelInStack() != null) { - cPanel = cPanel.getNextPanelInStack(); + if (c.getCurrentState().isCreature()) { + if (!c.hasCardAttachments() && + cardName.equals(c.getCurrentState().getName()) && + card.hasSameCounters(c) && + card.getCurrentState().getKeywordKey().equals(c.getCurrentState().getKeywordKey()) && + card.isTapped() == c.isTapped() && // don't stack tapped tokens on untapped tokens + card.isSick() == c.isSick() && //don't stack sick tokens on non sick + card.isToken() == c.isToken()) { //don't stack tokens on top of non-tokens + CardAreaPanel cPanel = CardAreaPanel.get(c); + while (cPanel.getNextPanelInStack() != null) { + cPanel = cPanel.getNextPanelInStack(); + } + CardAreaPanel cardPanel = CardAreaPanel.get(card); + cPanel.setNextPanelInStack(cardPanel); + cardPanel.setPrevPanelInStack(cPanel); + return true; + } + } else { + if (!c.hasCardAttachments() && + cardName.equals(c.getCurrentState().getName()) && + card.hasSameCounters(c) && + card.getCurrentState().getKeywordKey().equals(c.getCurrentState().getKeywordKey()) && + card.getCurrentState().getColors() == c.getCurrentState().getColors() && + card.isSick() == c.isSick() && //don't stack sick tokens on non sick + card.isToken() == c.isToken()) { //don't stack tokens on top of non-tokens + CardAreaPanel cPanel = CardAreaPanel.get(c); + while (cPanel.getNextPanelInStack() != null) { + cPanel = cPanel.getNextPanelInStack(); + } + CardAreaPanel cardPanel = CardAreaPanel.get(card); + cPanel.setNextPanelInStack(cardPanel); + cardPanel.setPrevPanelInStack(cPanel); + return true; } - CardAreaPanel cardPanel = CardAreaPanel.get(card); - cPanel.setNextPanelInStack(cardPanel); - cardPanel.setPrevPanelInStack(cPanel); - return true; } } return false; diff --git a/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java b/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java index 870e99ffdb0..ee7e4c40967 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VPlayerPanel.java @@ -176,7 +176,7 @@ public class VPlayerPanel extends FContainer { public void updateZone(ZoneType zoneType) { if (zoneType == ZoneType.Battlefield ) { - field.update(); + field.update(true); } else if (zoneType == ZoneType.Command) { commandZone.update(); diff --git a/forge-gui-mobile/src/forge/screens/match/views/VStack.java b/forge-gui-mobile/src/forge/screens/match/views/VStack.java index 100b9cc46b2..d37c64f4c8c 100644 --- a/forge-gui-mobile/src/forge/screens/match/views/VStack.java +++ b/forge-gui-mobile/src/forge/screens/match/views/VStack.java @@ -38,6 +38,7 @@ import forge.toolbox.FDisplayObject; import forge.toolbox.FEvent; import forge.toolbox.FEvent.FEventHandler; import forge.toolbox.FLabel; +import forge.util.Localizer; import forge.util.collect.FCollectionView; import forge.util.Utils; @@ -98,7 +99,7 @@ public class VStack extends FDropDown { if (stackSize != stack.size()) { int oldStackSize = stackSize; stackSize = stack.size(); - getMenuTab().setText("Stack (" + stackSize + ")"); + getMenuTab().setText(Localizer.getInstance().getMessage("lblStack") + " (" + stackSize + ")"); if (stackSize > 0) { if (!isVisible()) { @@ -133,7 +134,7 @@ public class VStack extends FDropDown { final FCollectionView stack = MatchController.instance.getGameView().getStack(); if (stack.isEmpty()) { //show label if stack empty - FLabel label = add(new FLabel.Builder().text("[Empty]").font(FONT).align(Align.center).build()); + FLabel label = add(new FLabel.Builder().text("[" + Localizer.getInstance().getMessage("lblEmpty") + "]").font(FONT).align(Align.center).build()); float height = Math.round(label.getAutoSizeBounds().height) + 2 * PADDING; label.setBounds(x, y, width, height); diff --git a/forge-gui-mobile/src/forge/screens/match/winlose/ControlWinLose.java b/forge-gui-mobile/src/forge/screens/match/winlose/ControlWinLose.java index bd01ad00cd7..6cc7a757de3 100644 --- a/forge-gui-mobile/src/forge/screens/match/winlose/ControlWinLose.java +++ b/forge-gui-mobile/src/forge/screens/match/winlose/ControlWinLose.java @@ -53,21 +53,24 @@ public class ControlWinLose { view.hide(); saveOptions(); - MatchController.getHostedMatch().continueMatch(); + try { MatchController.getHostedMatch().continueMatch(); + } catch (NullPointerException e) {} } /** Action performed when "restart" button is pressed in default win/lose UI. */ public void actionOnRestart() { view.hide(); saveOptions(); - MatchController.getHostedMatch().restartMatch(); + try { MatchController.getHostedMatch().restartMatch(); + } catch (NullPointerException e) {} } /** Action performed when "quit" button is pressed in default win/lose UI. */ public void actionOnQuit() { // Reset other stuff saveOptions(); - MatchController.getHostedMatch().endCurrentGame(); + try { MatchController.getHostedMatch().endCurrentGame(); + } catch (NullPointerException e) {} view.hide(); } diff --git a/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java b/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java index 7f6f23af1aa..ec41c7ea9a8 100644 --- a/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java +++ b/forge-gui-mobile/src/forge/screens/settings/SettingsPage.java @@ -260,7 +260,7 @@ public class SettingsPage extends TabPage { TabPageScreen.COMPACT_TABS = FModel.getPreferences().getPrefBoolean(FPref.UI_COMPACT_TABS); parentScreen.revalidate(); } - }, 4); + },4); lstSettings.addItem(new BooleanSetting(FPref.UI_COMPACT_LIST_ITEMS, localizer.getMessage("lblCompactListItems"), localizer.getMessage("nlCompactListItems")), @@ -301,15 +301,43 @@ public class SettingsPage extends TabPage { localizer.getMessage("lblDisableCardEffect"), localizer.getMessage("nlDisableCardEffect")), 4); - + lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_BORDER_MASKING, + localizer.getMessage("lblEnableRoundBorder"), + localizer.getMessage("nlEnableRoundBorder")){ + @Override + public void select() { + super.select(); + //update + Forge.enableUIMask = FModel.getPreferences().getPrefBoolean(FPref.UI_ENABLE_BORDER_MASKING); + } + },4); + lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_PRELOAD_EXTENDED_ART, + localizer.getMessage("lblPreloadExtendedArtCards"), + localizer.getMessage("nlPreloadExtendedArtCards")){ + @Override + public void select() { + super.select(); + //update + Forge.enablePreloadExtendedArt = FModel.getPreferences().getPrefBoolean(FPref.UI_ENABLE_PRELOAD_EXTENDED_ART); + } + },4); + lstSettings.addItem(new BooleanSetting(FPref.UI_SHOW_FPS, + localizer.getMessage("lblShowFPSDisplay"), + localizer.getMessage("nlShowFPSDisplay")){ + @Override + public void select() { + super.select(); + //update + Forge.showFPS = FModel.getPreferences().getPrefBoolean(FPref.UI_SHOW_FPS); + } + },4); lstSettings.addItem(new CustomSelectSetting(FPref.UI_CARD_COUNTER_DISPLAY_TYPE, - localizer.getMessage("cbpCounterDisplayType"), - localizer.getMessage("nlCounterDisplayType"), - new String[]{ - ForgeConstants.CounterDisplayType.TEXT.getName(), ForgeConstants.CounterDisplayType.IMAGE.getName(), - ForgeConstants.CounterDisplayType.HYBRID.getName(), ForgeConstants.CounterDisplayType.OLD_WHEN_SMALL.getName()}), + localizer.getMessage("cbpCounterDisplayType"), + localizer.getMessage("nlCounterDisplayType"), + new String[]{ + ForgeConstants.CounterDisplayType.TEXT.getName(), ForgeConstants.CounterDisplayType.IMAGE.getName(), + ForgeConstants.CounterDisplayType.HYBRID.getName(), ForgeConstants.CounterDisplayType.OLD_WHEN_SMALL.getName()}), 4); - //Card Overlays lstSettings.addItem(new BooleanSetting(FPref.UI_SHOW_CARD_OVERLAYS, localizer.getMessage("lblShowCardOverlays"), @@ -335,7 +363,6 @@ public class SettingsPage extends TabPage { localizer.getMessage("lblShowAbilityIconsOverlays"), localizer.getMessage("nlShowAbilityIconsOverlays")), 5); - //Vibration Options lstSettings.addItem(new BooleanSetting(FPref.UI_VIBRATE_ON_LIFE_LOSS, localizer.getMessage("lblVibrateWhenLosingLife"), @@ -345,7 +372,6 @@ public class SettingsPage extends TabPage { localizer.getMessage("lblVibrateAfterLongPress"), localizer.getMessage("nlVibrateAfterLongPress")), 6); - //Sound Options lstSettings.addItem(new BooleanSetting(FPref.UI_ENABLE_SOUNDS, localizer.getMessage("cbEnableSounds"), @@ -360,7 +386,7 @@ public class SettingsPage extends TabPage { //update background music when this setting changes SoundSystem.instance.changeBackgroundTrack(); } - }, 7); + },7); /*lstSettings.addItem(new BooleanSetting(FPref.UI_ALT_SOUND_SYSTEM, "Use Alternate Sound System", "Use the alternate sound system (only use if you have issues with sound not playing or disappearing)."), diff --git a/forge-gui/pom.xml b/forge-gui/pom.xml index 3549e6bda43..c981b823696 100644 --- a/forge-gui/pom.xml +++ b/forge-gui/pom.xml @@ -4,7 +4,7 @@ forge forge - 1.6.30-SNAPSHOT + 1.6.31-SNAPSHOT forge-gui @@ -39,28 +39,33 @@ com.google.guava guava - 24.1-android + 28.1-android com.thoughtworks.xstream xstream - 1.4.10 + 1.4.11.1 org.apache.commons commons-lang3 - 3.7 + 3.8.1 io.netty netty-all - 4.0.25.Final + 4.1.43.Final compile - log4j - log4j - 1.2.17 + org.apache.logging.log4j + log4j-api + 2.11.2 + + + org.apache.logging.log4j + log4j-core + 2.11.2 org.fourthline.cling @@ -72,6 +77,11 @@ slf4j-simple 1.7.22 + + org.mapdb + elsa + 3.0.0-M7 + diff --git a/forge-gui/release-files/ANNOUNCEMENTS.txt b/forge-gui/release-files/ANNOUNCEMENTS.txt index e86bf9c00fc..83c75c41d02 100644 --- a/forge-gui/release-files/ANNOUNCEMENTS.txt +++ b/forge-gui/release-files/ANNOUNCEMENTS.txt @@ -1,6 +1,8 @@ #Add one announcement per line -Throne of Eldraine pre-release! -Updated Libgdx from 1.5.5 to 1.9.10 ([url=https://github.com/libgdx/libgdx/blob/master/CHANGES]detailed changes are here[/url]). +Throne of Eldraine fixes +Pioneer is here! +Some fancy looking UI stuff was added. Card Sleeves and Keyword Icons +Continued work on Translations [b]Forge now requires Java 8 (or newer). You will not be able to start the game if you are not yet running Java 8.[/b] For some reason Oracle hates Forge and version 1.8.0_211 does bad things with Forge for unknown reasons. Downgrade to 202 for a beter time. https://www.oracle.com/technetwork/java/javase/downloads/java-archive-javase8-2177648.html diff --git a/forge-gui/release-files/CONTRIBUTORS.txt b/forge-gui/release-files/CONTRIBUTORS.txt index 2ff5c065a82..e8072d2e3d0 100644 --- a/forge-gui/release-files/CONTRIBUTORS.txt +++ b/forge-gui/release-files/CONTRIBUTORS.txt @@ -10,7 +10,9 @@ Hanmac Indigo Dragon Jamin Collins kevlahnota +klaxnek KrazyTheFox +leriomaggio Luke Marek14 mcrawford620 @@ -19,6 +21,7 @@ Myrd nefigah OgreBattlecruiser pfps +Ryan1729 Seravy Sirspud Sloth diff --git a/forge-gui/res/cardsfolder/a/autumn_willow.txt b/forge-gui/res/cardsfolder/a/autumn_willow.txt index 4ec308f4e5b..b9df47db469 100644 --- a/forge-gui/res/cardsfolder/a/autumn_willow.txt +++ b/forge-gui/res/cardsfolder/a/autumn_willow.txt @@ -3,7 +3,7 @@ ManaCost:4 G G Types:Legendary Creature Avatar PT:4/4 K:Shroud -A:AB$ Pump | Cost$ G | ValidTgts$ Player | Defined$ Targeted | TgtPrompt$ Select target player to be able to target Autumn Willow | KW$ Can target CardUIDSource with spells and abilities as though it didn't have shroud. | DefinedKW$ CardUIDSource | StackDescription$ Until end of turn, {p:Targeted} can target CARDNAME as though it didn't have shroud. | SpellDescription$ Until end of turn, Autumn Willow can be the target of spells and abilities controlled by target player as though it didn't have shroud. +A:AB$ Pump | Cost$ G | ValidTgts$ Player | Defined$ Targeted | TgtPrompt$ Select target player to be able to target Autumn Willow | KW$ IgnoreShroud:Card.CardUIDSource | DefinedKW$ CardUIDSource | UntilHostLeavesPlayOrEOT$ True | StackDescription$ Until end of turn, {p:Targeted} can target CARDNAME as though it didn't have shroud. | SpellDescription$ Until end of turn, Autumn Willow can be the target of spells and abilities controlled by target player as though it didn't have shroud. AI:RemoveDeck:All SVar:Picture:http://www.wizards.com/global/images/magic/general/autumn_willow.jpg Oracle:Shroud (This creature can't be the target of spells or abilities.)\n{G}: Until end of turn, Autumn Willow can be the target of spells and abilities controlled by target player as though it didn't have shroud. diff --git a/forge-gui/res/cardsfolder/b/blow_your_house_down.txt b/forge-gui/res/cardsfolder/b/blow_your_house_down.txt index 94decc095c2..25d448380e4 100644 --- a/forge-gui/res/cardsfolder/b/blow_your_house_down.txt +++ b/forge-gui/res/cardsfolder/b/blow_your_house_down.txt @@ -1,6 +1,7 @@ Name:Blow Your House Down ManaCost:2 R Types:Sorcery -A:SP$ Pump | Cost$ 2 R | ValidTgts$ Creature | TargetMin$ 0 | TargetMax$ 3 | KW$ HIDDEN CARDNAME can't block. | IsCurse$ True | TgtPrompt$ Select target creature | SubAbility$ DBDestroy | SpellDescription$ Up to three target creatures can't block this turn. Destroy any of them that are Walls. -SVar:DBDestroy:DB$ DestroyAll | ValidCards$ Targeted.Wall +A:SP$ Pump | Cost$ 2 R | ValidTgts$ Creature | TargetMin$ 0 | TargetMax$ 3 | RememberTargets$ True | KW$ HIDDEN CARDNAME can't block. | IsCurse$ True | TgtPrompt$ Select target creature | SubAbility$ DBDestroy | SpellDescription$ Up to three target creatures can't block this turn. Destroy any of them that are Walls. +SVar:DBDestroy:DB$ DestroyAll | ValidCards$ Wall.IsRemembered | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True Oracle:Up to three target creatures can't block this turn. Destroy any of them that are Walls. diff --git a/forge-gui/res/cardsfolder/d/dance_of_the_manse.txt b/forge-gui/res/cardsfolder/d/dance_of_the_manse.txt index b9d1a86e96f..a999663808e 100644 --- a/forge-gui/res/cardsfolder/d/dance_of_the_manse.txt +++ b/forge-gui/res/cardsfolder/d/dance_of_the_manse.txt @@ -1,7 +1,7 @@ Name:Dance of the Manse ManaCost:X W U Types:Sorcery -A:SP$ ChangeZone | Cost$ X W U | Announce$ X | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Artifact.cmcLEX,Enchantment.cmcLEX | TgtPrompt$ Select target artifact or enchantment in your graveyard | TargetMin$ 0 | TargetMax$ X | SubAbility$ DBAnimate | SpellDescription$ Return up to X target artifact and/or non-Aura enchantment cards with converted mana cost X or less from your graveyard to the battlefield. If X is 6 or more, those permanents are 4/4 creatures in addition to their other types. +A:SP$ ChangeZone | Cost$ X W U | Announce$ X | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Artifact.cmcLEX+YouOwn,Enchantment.cmcLEX+YouOwn+nonAura | TgtPrompt$ Select target artifact or non-Aura enchantment in your graveyard | TargetMin$ 0 | TargetMax$ X | SubAbility$ DBAnimate | SpellDescription$ Return up to X target artifact and/or non-Aura enchantment cards with converted mana cost X or less from your graveyard to the battlefield. If X is 6 or more, those permanents are 4/4 creatures in addition to their other types. SVar:DBAnimate:DB$ Animate | Defined$ Targeted | Types$ Creature | Power$ 4 | Toughness$ 4 | Permanent$ True | ConditionCheckSVar$ X | ConditionSVarCompare$ GE6 | References$ X SVar:X:Count$xPaid AI:RemoveDeck:All diff --git a/forge-gui/res/cardsfolder/d/disintegrate.txt b/forge-gui/res/cardsfolder/d/disintegrate.txt index edcc0398227..bd0b86d9319 100644 --- a/forge-gui/res/cardsfolder/d/disintegrate.txt +++ b/forge-gui/res/cardsfolder/d/disintegrate.txt @@ -1,8 +1,8 @@ Name:Disintegrate ManaCost:X R Types:Sorcery -A:SP$ DealDamage | Cost$ X R | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ X | SubAbility$ DB | References$ X | ReplaceDyingDefined$ Targeted | SpellDescription$ CARDNAME deals X damage to any target. That creature can't be regenerated this turn. If the creature would die this turn, exile it instead. +A:SP$ DealDamage | Cost$ X R | ValidTgts$ Creature,Player,Planeswalker | TgtPrompt$ Select any target | NumDmg$ X | SubAbility$ DB | References$ X | ReplaceDyingDefined$ Targeted.Creature | SpellDescription$ CARDNAME deals X damage to any target. That creature can't be regenerated this turn. If the creature would die this turn, exile it instead. +SVar:DB:DB$ Pump | KW$ HIDDEN CARDNAME can't be regenerated. | Defined$ Targeted.Creature SVar:X:Count$xPaid -SVar:DB:DB$Pump | KW$ HIDDEN CARDNAME can't be regenerated. | Defined$ Targeted SVar:Picture:http://www.wizards.com/global/images/magic/general/disintegrate.jpg -Oracle:Disintegrate deals X damage to any target. That creature can't be regenerated this turn. If the creature would die this turn, exile it instead. \ No newline at end of file +Oracle:Disintegrate deals X damage to any target. If it's a creature, it can't be regenerated this turn, and if it would die this turn, exile it instead. diff --git a/forge-gui/res/cardsfolder/d/dread_warlock.txt b/forge-gui/res/cardsfolder/d/dread_warlock.txt index 07a5d4d785f..aaacbfb9fb3 100644 --- a/forge-gui/res/cardsfolder/d/dread_warlock.txt +++ b/forge-gui/res/cardsfolder/d/dread_warlock.txt @@ -1,6 +1,6 @@ Name:Dread Warlock ManaCost:1 B B -Types:Creature Human Wizard +Types:Creature Human Wizard Warlock PT:2/2 K:CantBeBlockedBy Creature.nonBlack SVar:Picture:http://www.wizards.com/global/images/magic/general/dread_warlock.jpg diff --git a/forge-gui/res/cardsfolder/m/memory_theft.txt b/forge-gui/res/cardsfolder/m/memory_theft.txt index a51ef072bd6..3b783a6b690 100644 --- a/forge-gui/res/cardsfolder/m/memory_theft.txt +++ b/forge-gui/res/cardsfolder/m/memory_theft.txt @@ -1,6 +1,6 @@ Name:Memory Theft ManaCost:2 B Types:Sorcery -A:SP$ Discard | Cost$ 2 B | ValidTgts$ Opponent | Mode$ RevealYouChoose | NumCards$ 1 | SubAbility$ DBChangeZone | SpellDescription$ Target opponent reveals their hand. You choose a nonland card from it. That player discards that card. You may put a card that has an Adventure that player owns from exile into that player's graveyard. +A:SP$ Discard | Cost$ 2 B | ValidTgts$ Opponent | Mode$ RevealYouChoose | NumCards$ 1 | DiscardValid$ Card.nonLand | SubAbility$ DBChangeZone | SpellDescription$ Target opponent reveals their hand. You choose a nonland card from it. That player discards that card. You may put a card that has an Adventure that player owns from exile into that player's graveyard. SVar:DBChangeZone:DB$ ChangeZone | ChangeType$ Card.AdventureCard+TargetedPlayerCtrl | Origin$ Exile | Destination$ Graveyard | Hidden$ True Oracle:Target opponent reveals their hand. You choose a nonland card from it. That player discards that card. You may put a card that has an Adventure that player owns from exile into that player's graveyard. diff --git a/forge-gui/res/cardsfolder/p/peace_talks.txt b/forge-gui/res/cardsfolder/p/peace_talks.txt index 37e12faf05b..a3305e52628 100644 --- a/forge-gui/res/cardsfolder/p/peace_talks.txt +++ b/forge-gui/res/cardsfolder/p/peace_talks.txt @@ -4,6 +4,6 @@ Types:Sorcery A:SP$ Effect | Cost$ 1 W | Name$ Peace Talks Effect | StaticAbilities$ STCantAttack,STCantTarget,STCantTargetPlayer | Duration$ ThisTurnAndNextTurn | SpellDescription$ This turn and next turn, creatures can't attack, and players and permanents can't be the targets of spells or activated abilities. SVar:STCantAttack:Mode$ CantAttack | EffectZone$ Command | ValidCard$ Creature | Description$ Creatures can't attack. SVar:STCantTarget:Mode$ CantTarget | ValidCard$ Permanent | EffectZone$ Command | ValidSA$ Spell,Activated | Description$ Permanents can't be the targets of spells or activated abilities. -SVar:STCantTargetPlayer:Mode$ Continuous | Affected$ Player | EffectZone$ Command | AddKeyword$ You can't be the targets of spells or activated abilities | Description$ Players can't be the targets of spells or activated abilities. +SVar:STCantTargetPlayer:Mode$ CantTarget | ValidPlayer$ Player | EffectZone$ Command | ValidSA$ Spell,Activated | Description$Players can't be the targets of spells or activated abilities. SVar:Picture:http://www.wizards.com/global/images/magic/general/peace_talks.jpg Oracle:This turn and next turn, creatures can't attack, and players and permanents can't be the targets of spells or activated abilities. diff --git a/forge-gui/res/cardsfolder/p/proteus_staff.txt b/forge-gui/res/cardsfolder/p/proteus_staff.txt index 61ac6e7a2ba..c63a1a5a58d 100644 --- a/forge-gui/res/cardsfolder/p/proteus_staff.txt +++ b/forge-gui/res/cardsfolder/p/proteus_staff.txt @@ -1,8 +1,9 @@ Name:Proteus Staff ManaCost:3 Types:Artifact -A:AB$ ChangeZone | Cost$ 2 U T | SorcerySpeed$ True | ValidTgts$ Creature | TgtPrompt$ Select target creature | AILogic$ Polymorph | Origin$ Battlefield | Destination$ Library | LibraryPosition$ -1 | SubAbility$ DBDigUntil | SpellDescription$ Put target creature on the bottom of its owner's library. That creature's controller reveals cards from the top of their library until they reveal a creature card. The player puts that card onto the battlefield and the rest on the bottom of their library in any order. Activate this ability only any time you could cast a sorcery. -SVar:DBDigUntil:DB$ DigUntil | Defined$ TargetedController | Valid$ Creature | ValidDescription$ creature | FoundDestination$ Battlefield | RevealedDestination$ Library | RevealedLibraryPosition$ -1 +A:AB$ ChangeZone | Cost$ 2 U T | SorcerySpeed$ True | Origin$ Battlefield | Destination$ Library | LibraryPosition$ -1 | ValidTgts$ Creature | AILogic$ Polymorph | RememberLKI$ True | TgtPrompt$ Select target creature | SubAbility$ DBDigUntil | SpellDescription$ Put target creature on the bottom of its owner's library. That creature's controller reveals cards from the top of their library until they reveal a creature card. The player puts that card onto the battlefield and the rest on the bottom of their library in any order. Activate this ability only any time you could cast a sorcery. +SVar:DBDigUntil:DB$ DigUntil | Defined$ RememberedController | Valid$ Creature | ValidDescription$ creature | FoundDestination$ Battlefield | RevealedDestination$ Library | RevealedLibraryPosition$ -1 | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True AI:RemoveDeck:All AI:RemoveDeck:Random DeckNeeds:Color$Blue diff --git a/forge-gui/res/cardsfolder/q/questing_beast.txt b/forge-gui/res/cardsfolder/q/questing_beast.txt index 5887abf709c..8bc09495eb9 100644 --- a/forge-gui/res/cardsfolder/q/questing_beast.txt +++ b/forge-gui/res/cardsfolder/q/questing_beast.txt @@ -7,7 +7,7 @@ K:Deathtouch K:Haste K:CantBeBlockedBy Creature.powerLE2 S:Mode$ CantPreventDamage | IsCombat$ True | ValidSource$ Creature.YouCtrl | Description$ Combat damage that would be dealt by creatures you control can’t be prevented. -T:Mode$ DamageDone | ValidSource$ Creature.YouCtrl | ValidTarget$ Opponent | CombatDamage$ True | TriggerZones$ Battlefield | Execute$ MoreDamage | TriggerDescription$ Whenever CARDNAME deals combat damage to an opponent, it deals that much damage to target planeswalker that player controls. +T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Opponent | CombatDamage$ True | TriggerZones$ Battlefield | Execute$ MoreDamage | TriggerDescription$ Whenever CARDNAME deals combat damage to an opponent, it deals that much damage to target planeswalker that player controls. SVar:MoreDamage:DB$ DealDamage | ValidTgts$ Planeswalker.ControlledBy TriggeredTarget | TgtPrompt$ Select target planeswalker that player controls | NumDmg$ X | References$ X SVar:X:TriggerCount$DamageAmount Oracle:Vigilance, deathtouch, haste\nQuesting Beast can’t be blocked by creatures with power 2 or less.\nCombat damage that would be dealt by creatures you control can’t be prevented.\nWhenever Questing Beast deals combat damage to an opponent, it deals that much damage to target planeswalker that player controls. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/r/resolute_rider.txt b/forge-gui/res/cardsfolder/r/resolute_rider.txt index 0ceaa245b83..8e754b53ca8 100644 --- a/forge-gui/res/cardsfolder/r/resolute_rider.txt +++ b/forge-gui/res/cardsfolder/r/resolute_rider.txt @@ -3,6 +3,6 @@ ManaCost:W/B W/B W/B W/B Types:Creature Human Knight PT:4/2 A:AB$ Pump | Cost$ W/B W/B | KW$ Lifelink | Defined$ Self | SpellDescription$ CARDNAME gains lifelink until end of turn. -A:AB$ Pump | Cost$ W/B W/B W/B W/B | KW$ Indestructible | Defined$ Self | SpellDescription$ CARDNAME gains indestructible until end of turn. +A:AB$ Pump | Cost$ W/B W/B W/B | KW$ Indestructible | Defined$ Self | SpellDescription$ CARDNAME gains indestructible until end of turn. DeckHas:Ability$LifeGain -Oracle:{W/B}{W/B}: Resolute Rider gains lifelink until end of turn.\n{W/B}{W/B}{W/B}{W/B}: Resolute Rider gains indestructible until end of turn. +Oracle:{W/B}{W/B}: Resolute Rider gains lifelink until end of turn.\n{W/B}{W/B}{W/B}: Resolute Rider gains indestructible until end of turn. diff --git a/forge-gui/res/cardsfolder/s/seedguide_ash.txt b/forge-gui/res/cardsfolder/s/seedguide_ash.txt index f4d69b07f55..413091fdc92 100644 --- a/forge-gui/res/cardsfolder/s/seedguide_ash.txt +++ b/forge-gui/res/cardsfolder/s/seedguide_ash.txt @@ -2,7 +2,7 @@ Name:Seedguide Ash ManaCost:4 G Types:Creature Treefolk Druid PT:4/4 -T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | TriggerZones$ Graveyard | Execute$ TrigChange | OptionalDecider$ TriggeredCardController | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, you may search your library for up to three Forest cards and put them onto the battlefield tapped. If you do, shuffle your library. +T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Card.Self | Execute$ TrigChange | OptionalDecider$ TriggeredCardController | TriggerController$ TriggeredCardController | TriggerDescription$ When CARDNAME dies, you may search your library for up to three Forest cards and put them onto the battlefield tapped. If you do, shuffle your library. SVar:TrigChange:DB$ChangeZone | Origin$ Library | Destination$ Battlefield | ChangeType$ Forest | Tapped$ True | ChangeNum$ 3 | ShuffleNonMandatory$ True SVar:Picture:http://www.wizards.com/global/images/magic/general/seedguide_ash.jpg Oracle:When Seedguide Ash dies, you may search your library for up to three Forest cards and put them onto the battlefield tapped. If you do, shuffle your library. diff --git a/forge-gui/res/cardsfolder/s/seven_dwarves.txt b/forge-gui/res/cardsfolder/s/seven_dwarves.txt new file mode 100644 index 00000000000..3e5e8db3f09 --- /dev/null +++ b/forge-gui/res/cardsfolder/s/seven_dwarves.txt @@ -0,0 +1,11 @@ +Name:Seven Dwarves +ManaCost:1 R +Types:Creature Dwarf +PT:2/2 +K:A deck can have up to seven cards named CARDNAME. +S:Mode$ Continuous | Affected$ Card.Self | AddPower$ X | AddToughness$ X | References$ X | Description$ CARDNAME gets +1/+1 for each other creature named Seven Dwarves you control. +SVar:X:Count$Valid Creature.namedSeven Dwarves+Other +SVar:BuffedBy:Creature.namedSeven Dwarves +SVar:PlayMain1:TRUE +DeckNeeds:Name$Seven Dwarves +Oracle:Seven Dwarves gets +1/+1 for each other creature named Seven Dwarves you control.\nA deck can have up to seven cards named Seven Dwarves. \ No newline at end of file diff --git a/forge-gui/res/cardsfolder/s/spectral_shield.txt b/forge-gui/res/cardsfolder/s/spectral_shield.txt index f37807ffe07..ee34f2530c8 100644 --- a/forge-gui/res/cardsfolder/s/spectral_shield.txt +++ b/forge-gui/res/cardsfolder/s/spectral_shield.txt @@ -3,6 +3,7 @@ ManaCost:1 W U Types:Enchantment Aura K:Enchant creature A:SP$ Attach | Cost$ 1 W U | ValidTgts$ Creature | AILogic$ Pump -S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddToughness$ 2 | AddHiddenKeyword$ CARDNAME can't be the target of spells. | Description$ Enchanted creature gets +0/+2 and can't be the target of spells. +S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddToughness$ 2 | Description$ Enchanted creature gets +0/+2. +S:Mode$ CantTarget | ValidCard$ Creature.EnchantedBy | ValidSA$ Spell | Description$ Enchanted creature can't be the target of spells. SVar:Picture:http://www.wizards.com/global/images/magic/general/spectral_shield.jpg Oracle:Enchant creature\nEnchanted creature gets +0/+2 and can't be the target of spells. diff --git a/forge-gui/res/cardsfolder/v/veil_of_summer.txt b/forge-gui/res/cardsfolder/v/veil_of_summer.txt index 54941da97e1..d0124692772 100644 --- a/forge-gui/res/cardsfolder/v/veil_of_summer.txt +++ b/forge-gui/res/cardsfolder/v/veil_of_summer.txt @@ -1,8 +1,8 @@ Name:Veil of Summer ManaCost:G Types:Instant -A:SP$ Draw | Cost$ G | Defined$ You | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | SubAbility$ DBEffect | SpellDescription$ Draw a card if an opponent has cast a blue or black spell this turn. Spells you control can't be countered this turn. You and permanents you control gain hexproof from blue and from black until end of turn. (You and they can't be the targets of blue or black spells or abilities your opponents control.) -SVar:DBEffect:DB$ Effect | Name$ CARDNAME Effect | StaticAbilities$ AntiMagic | SubAbility$ DBPump +A:SP$ Draw | Cost$ G | Defined$ You | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 |References$ X | SubAbility$ DBEffect | StackDescription$ SpellDescription | SpellDescription$ Draw a card if an opponent has cast a blue or black spell this turn. Spells you control can't be countered this turn. You and permanents you control gain hexproof from blue and from black until end of turn. (You and they can't be the targets of blue or black spells or abilities your opponents control.) +SVar:DBEffect:DB$ Effect | StaticAbilities$ AntiMagic | SubAbility$ DBPump SVar:AntiMagic:Mode$ Continuous | Affected$ Card.YouCtrl | AffectedZone$ Stack | EffectZone$ Command | AddHiddenKeyword$ CARDNAME can't be countered. | Description$ Spells you control can't be countered this turn. SVar:DBPump:DB$ Pump | Defined$ You | KW$ Hexproof:Card.Black:black & Hexproof:Card.Blue:blue | SubAbility$ DBPumpAll SVar:DBPumpAll:DB$ PumpAll | ValidCards$ Permanent.YouCtrl | KW$ Hexproof:Card.Black:black & Hexproof:Card.Blue:blue diff --git a/forge-gui/res/deckgendecks/Modern.lda.dat b/forge-gui/res/deckgendecks/Modern.lda.dat index 480a9ac7021..eea4ae5a26f 100644 Binary files a/forge-gui/res/deckgendecks/Modern.lda.dat and b/forge-gui/res/deckgendecks/Modern.lda.dat differ diff --git a/forge-gui/res/deckgendecks/Modern.raw.dat b/forge-gui/res/deckgendecks/Modern.raw.dat index 2376da4ab0d..02144e71b62 100644 Binary files a/forge-gui/res/deckgendecks/Modern.raw.dat and b/forge-gui/res/deckgendecks/Modern.raw.dat differ diff --git a/forge-gui/res/deckgendecks/Pioneer.lda.dat b/forge-gui/res/deckgendecks/Pioneer.lda.dat new file mode 100644 index 00000000000..ca93fcd3304 Binary files /dev/null and b/forge-gui/res/deckgendecks/Pioneer.lda.dat differ diff --git a/forge-gui/res/deckgendecks/Pioneer.raw.dat b/forge-gui/res/deckgendecks/Pioneer.raw.dat new file mode 100644 index 00000000000..a6708549976 Binary files /dev/null and b/forge-gui/res/deckgendecks/Pioneer.raw.dat differ diff --git a/forge-gui/res/deckgendecks/Standard.lda.dat b/forge-gui/res/deckgendecks/Standard.lda.dat index e5487bcf6bd..47c728694e2 100644 Binary files a/forge-gui/res/deckgendecks/Standard.lda.dat and b/forge-gui/res/deckgendecks/Standard.lda.dat differ diff --git a/forge-gui/res/deckgendecks/Standard.raw.dat b/forge-gui/res/deckgendecks/Standard.raw.dat index cf78609fe0a..aa9172da44e 100644 Binary files a/forge-gui/res/deckgendecks/Standard.raw.dat and b/forge-gui/res/deckgendecks/Standard.raw.dat differ diff --git a/forge-gui/res/editions/Deckmasters Garfield vs. Finkel.txt b/forge-gui/res/editions/Deckmasters Garfield vs. Finkel.txt index 874827ceca6..e9933ade52b 100644 --- a/forge-gui/res/editions/Deckmasters Garfield vs. Finkel.txt +++ b/forge-gui/res/editions/Deckmasters Garfield vs. Finkel.txt @@ -4,6 +4,7 @@ Date=2001-12 Name=Deckmasters: Garfield vs. Finkel MciCode=dm Type=Other +Border=White [cards] 1 U Abyssal Specter diff --git a/forge-gui/res/formats/Casual/Brawl.txt b/forge-gui/res/formats/Casual/Brawl.txt index 37076234c9a..78fa086854a 100644 --- a/forge-gui/res/formats/Casual/Brawl.txt +++ b/forge-gui/res/formats/Casual/Brawl.txt @@ -4,4 +4,4 @@ Order:101 Type:Casual Subtype:Commander Sets:GRN, RNA, WAR, M20, ELD -Banned: \ No newline at end of file +Banned:Oko, Thief of Crowns diff --git a/forge-gui/res/formats/Casual/pauper.txt b/forge-gui/res/formats/Casual/pauper.txt index 9a7d7f51d72..91762248c40 100644 --- a/forge-gui/res/formats/Casual/pauper.txt +++ b/forge-gui/res/formats/Casual/pauper.txt @@ -4,4 +4,4 @@ Order:108 Subtype:Custom Type:Casual Rarities:L, C -Banned:Gush;Gitaxian Probe;Daze +Banned:Gush;Gitaxian Probe;Daze;Arcum's Astrolabe diff --git a/forge-gui/res/formats/Sanctioned/Legacy.txt b/forge-gui/res/formats/Sanctioned/Legacy.txt index 08eda419476..404a575f8cd 100644 --- a/forge-gui/res/formats/Sanctioned/Legacy.txt +++ b/forge-gui/res/formats/Sanctioned/Legacy.txt @@ -3,4 +3,4 @@ Name:Legacy Order:105 Subtype:Legacy 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; 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; 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 diff --git a/forge-gui/res/formats/Sanctioned/Modern.txt b/forge-gui/res/formats/Sanctioned/Modern.txt index 92e7a97a367..86de24b81fb 100644 --- a/forge-gui/res/formats/Sanctioned/Modern.txt +++ b/forge-gui/res/formats/Sanctioned/Modern.txt @@ -1,6 +1,6 @@ [format] Name:Modern -Order:102 +Order:103 Subtype:Modern 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 diff --git a/forge-gui/res/formats/Sanctioned/Pioneer.txt b/forge-gui/res/formats/Sanctioned/Pioneer.txt new file mode 100644 index 00000000000..554ca459915 --- /dev/null +++ b/forge-gui/res/formats/Sanctioned/Pioneer.txt @@ -0,0 +1,7 @@ +[format] +Name:Pioneer +Order:102 +Subtype:Pioneer +Type:Sanctioned +Sets:RTR, GTC, DGM, M14, THS, BNG, JOU, M15, KTK, FRF, DTK, ORI, BFZ, OGW, SOI, EMN, KLD, AER, AKH, HOU, XLN, RIX, DOM, M19, GRN, RNA, WAR, M20, ELD +Banned:Bloodstained Mire; Flooded Strand; Polluted Delta; Windswept Heath; Wooded Foothills; Felidar Guardian; Leyline of Abundance; Oath of Nissa; Veil of Summer diff --git a/forge-gui/res/formats/Sanctioned/Standard.txt b/forge-gui/res/formats/Sanctioned/Standard.txt index 9a0f5f86109..7d5010aee29 100644 --- a/forge-gui/res/formats/Sanctioned/Standard.txt +++ b/forge-gui/res/formats/Sanctioned/Standard.txt @@ -4,4 +4,4 @@ Order:101 Subtype:Standard Type:Sanctioned Sets:GRN, RNA, WAR, M20, ELD -Banned: +Banned:Field of the Dead; Oko, Thief of Crowns; Once Upon a Time; Veil of Summer diff --git a/forge-gui/res/formats/Sanctioned/Vintage.txt b/forge-gui/res/formats/Sanctioned/Vintage.txt index 8d31690ff2d..4295dbb432e 100644 --- a/forge-gui/res/formats/Sanctioned/Vintage.txt +++ b/forge-gui/res/formats/Sanctioned/Vintage.txt @@ -4,5 +4,5 @@ Order:104 Subtype:Vintage Type:Sanctioned Banned:Adriana's Valor; Advantageous Proclamation; Assemble the Rank and Vile; Backup Plan; Brago's Favor; Double Stroke; Echoing Boon; Emissary's Ploy; 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; Chaos Orb; Falling Star; Shahrazad -Restricted:Ancestral Recall; Balance; Black Lotus; Brainstorm; Chalice of the Void; Channel; Demonic Consultation; Demonic Tutor; Dig Through Time; Flash; Gitaxian Probe; Golgari Grave-Troll; Gush; Imperial Seal; Karn, the Great Creator; Library of Alexandria; Lion's Eye Diamond; Lodestone Golem; Lotus Petal; Mana Crypt; Mana Vault; Memory Jar; Mental Misstep; Merchant Scroll; Mind's Desire; Monastery Mentor; Mox Emerald; Mox Jet; Mox Pearl; Mox Ruby; Mox Sapphire; Mystic Forge; Mystical Tutor; Necropotence; Ponder; Sol Ring; Strip Mine; Thorn of Amethyst; Time Vault; Time Walk; Timetwister; Tinker; Tolarian Academy; Treasure Cruise; Trinisphere; Vampiric Tutor; Wheel of Fortune; Windfall; Yawgmoth's Will +Restricted:Ancestral Recall; Balance; Black Lotus; Brainstorm; Chalice of the Void; Channel; Demonic Consultation; Demonic Tutor; Dig Through Time; Flash; Gitaxian Probe; Golgari Grave-Troll; Gush; Imperial Seal; Karn, the Great Creator; Library of Alexandria; Lion's Eye Diamond; Lodestone Golem; Lotus Petal; Mana Crypt; Mana Vault; Memory Jar; Mental Misstep; Merchant Scroll; Mind's Desire; Monastery Mentor; Mox Emerald; Mox Jet; Mox Pearl; Mox Ruby; Mox Sapphire; Mystic Forge; Mystical Tutor; Narset, Parter of Veils; Necropotence; Ponder; Sol Ring; Strip Mine; Thorn of Amethyst; Time Vault; Time Walk; Timetwister; Tinker; Tolarian Academy; Treasure Cruise; Trinisphere; Vampiric Tutor; Wheel of Fortune; Windfall; Yawgmoth's Will diff --git a/forge-gui/res/languages/cardnames-de-DE.txt b/forge-gui/res/languages/cardnames-de-DE.txt index ef3c66483f4..53241199039 100644 --- a/forge-gui/res/languages/cardnames-de-DE.txt +++ b/forge-gui/res/languages/cardnames-de-DE.txt @@ -373,6 +373,7 @@ Altar of the Brood|Altar der Brut|Artefakt|Immer wenn eine andere bleibende Kart Altar of the Lost|Altar der Verlorenen|Artefakt|Der Altar der Verlorenen kommt getappt ins Spiel.\n{T}: Erhöhe deinen Manavorrat um zwei Mana einer beliebigen Farbkombination. Verwende dieses Mana nur, um Zaubersprüche mit Rückblende aus einem Friedhof zu wirken. Altar's Light|Licht des Altars|Spontanzauber|Entferne eine Artefakt oder eine Verzauberung deiner Wahl ganz aus dem Spiel. Altar's Reap|Ernte des Altars|Spontanzauber|Opfere eine Kreatur als zusätzliche Kosten, um die Ernte des Altars zu wirken.Ziehe zwei Karten. +Alter Fate|Geändertes Los|Hexerei — Abenteuer|Bringe eine Kreaturenkarte deiner Wahl aus deinem Friedhof auf deine Hand zurück. (Schicke diese Karte dann ins Exil. Du kannst sie später als Kreatur aus dem Exil wirken.) Alter Reality|Veränderte Realität|Spontanzauber|Verändere den Text einer bleibenden Karte oder eines Zauberspruchs deiner Wahl, indem du im Text alle Vorkommen einer Farbe (eines Farbwortes) mit einer anderen Farbe ersetzt. (Dieser Effekt endet nicht am Ende des Zuges.)\nRückblende {1}{U} (Du kannst diese Karte aus deinem Friedhof für ihre Rückblendekosten spielen. Entferne sie dann ganz aus dem Spiel.) Altered Ego|Das veränderte Ich|Kreatur — Gestaltwandler|Das veränderte Ich kann nicht neutralisiert werden.\nDu kannst Das veränderte Ich als Kopie einer beliebigen Kreatur im Spiel ins Spiel kommen lassen, außer dass es mit X zusätzlichen +1/+1-Marken ins Spiel kommt. Aluren|Magischer Hain|Verzauberung|Jeder Spieler kann Kreaturenkarten mit Gesamtspruchkosten von 3 oder weniger sprechen, wann immer er ein Spontanzauber sprechen könnte und ohne die Spruchkosten zu bezahlen. @@ -3449,6 +3450,7 @@ Damping Sphere|Dämpfende Sphäre|Artefakt|Falls ein Land für zwei oder mehr Ma Dance of Many|Der große Tanz|Verzauberung|Zahle während Deiner Versorgungsphase UU oder begrabe den großen Tanz.\nWähle eine Beschwörungskarte im Spiel, wenn Du den großen Tanz sprichst. Wenn der große Tanz ins Spiel kommt, bringe eine Spielsteinkreatur ins Spiel und behandle diese wie eine genaue Kopie dieser Beschwörungskarte.\nWenn der große Tanz das Spiel verlässt, begrabe die Spielsteinkreatur und umgekehrt. Dance of Shadows|Schattentanz|Hexerei - Arkan|Kreaturen, die du kontrollierst, erhalten +1/+0 und verursachen bis zum Ende des Zuges Furcht. Dance of the Dead|Totentanz|Verzaubere eine tote Kreatur|Nimm eine Kreatur Deiner Wahl von irgendeinem Friedhof und bringe sie getappt unter Deiner Kontrolle mit +1/+1 direkt ins Spiel. Behandele diese Kreatur, als sei sie gerade beschworen worden. Diese Kreatur enttappt nicht während der Enttapp-Phase ihres Beherrschers. Am Ende seiner Versorgungsphase kann der Beherrscher zusätzlich 1B Bezahlen, um sie zu enttappen. Wenn der Totentanz entfernt wird, begrabe auch die Kreatur auf dem Friedhof ihres Besitzers. +Dance of the Manse|Tanz im Herrenhaus|Hexerei|Bringe bis zu X Artefakt- und/oder Nicht-Aura-Verzauberungskarten deiner Wahl mit jeweils umgewandelten Manakosten von X oder weniger aus deinem Friedhof ins Spiel zurück. Falls X gleich 6 oder mehr ist, sind jene bleibenden Karten zusätzlich zu ihren anderen Typen 4/4-Kreaturen. Dance of the Skywise|Tanz der Himmelsweisen|Spontanzauber|Bis zum Ende des Zuges wird eine Kreatur deiner Wahl, die du kontrollierst, zu einer blauen (Drache, Illusion)-Kreatur mit Basis-Stärke und -Widerstandskraft 4/4, verliert alle Fähigkeiten und erhält Flugfähigkeit. Dance with Devils|Tanz der Teufel|Spontanzauber|Bringe zwei 1/1 rote Teufel-Kreaturenspielsteine ins Spiel. Sie haben „Wenn diese Kreatur stirbt, fügt sie einer Kreatur oder einem Spieler deiner Wahl 1 Schadenspunkt zu." Dancing Scimitar|Tanzender Krummsäbel|Artefaktkreatur — Geist|Fliegend (Diese Kreatur kann nur von fliegenden Kreaturen geblockt werden.) @@ -4176,6 +4178,7 @@ Domri, City Smasher|Domri der Zerstörer|Legendärer Planeswalker — Domri|+2: Donate|Schenkung|Hexerei|Ein Spieler Deiner Wahl erhält die Kontrolle über eine bleibende Karte Deiner Wahl, die Du kontrollierst. Doom Blade|Klinge des Schicksals|Spontanzauber|Zerstöre eine nichtschwarze Kreatur deiner Wahl. Doom Cannon|Schicksalskanone|Artefakt|Bestimme einen Kreaturentyp, sowie die Schicksalskanone ins Spiel kommt.{3}, {T}, opfere eine Kreatur dieses bestimmten Typs: Die Schicksalskanone fügt einer Kreatur oder einem Spieler deiner Wahl 3 Schadenspunkte zu. +Doom Foretold|Vorhergesagte Verdammnis|Verzauberung|Zu Beginn des Versorgungssegments jedes Spielers opfert jener Spieler eine bleibende Karte, die weder ein Land noch ein Spielstein ist. Falls der Spieler dies nicht kann, wirft er eine Karte ab und verliert 2 Lebenspunkte, du ziehst eine Karte, erhältst 2 Lebenspunkte dazu, erzeugst einen 2/2 weißen Ritter-Kreaturenspielstein mit Wachsamkeit und opferst dann die Vorhergesagte Verdammnis. Doom Whisperer|Verkünder des Untergangs|Kreatur — Nachtmahr, Dämon|Fliegend, verursacht Trampelschaden\nBezahle 2 Lebenspunkte: Überwachen 2. (Schaue dir die obersten zwei Karten deiner Bibliothek an. Lege dann eine beliebige Anzahl davon auf deinen Friedhof und den Rest in beliebiger Reihenfolge oben auf deine Bibliothek.) Doomed Artisan|Todgeweihter Bildhauer|Kreatur — Mensch, Handwerker|Skulpturen, die du kontrollierst, können nicht angreifen oder blocken.\nZu Beginn deines Endsegments erzeugst du einen farblosen Skulptur-Artefaktkreaturenspielstein mit „Stärke und Widerstandskraft dieser Kreatur sind gleich der Anzahl an Skulpturen, die du kontrollierst." Doomed Dissenter|Todgeweihter Abtrünniger|Kreatur — Mensch|Wenn der Todgeweihte Abtrünnige stirbt, erzeuge einen 2/2 schwarzen Zombie-Kreaturenspielstein. @@ -4408,6 +4411,7 @@ Drove of Elves|Elfenschar|Kreatur — Elf|Fluchsicher\nStärke und Widerstandskr Drover of the Mighty|Hirte der Kolosse|Kreatur — Mensch, Druide|Der Hirte der Kolosse erhält +2/+2, solange du einen Dinosaurier kontrollierst.\n{T}: Erhöhe deinen Manavorrat um ein Mana einer beliebigen Farbe. Drown in Filth|Im Dreck ertrinken|Hexerei|Bestimme eine Kreatur deiner Wahl. Lege die obersten vier Karten deiner Bibliothek auf deinen Friedhof, dann erhält die bestimmte Kreatur für jede Länderkarte in deinem Friedhof -1/-1 bis zum Ende des Zuges. Drown in Sorrow|Im Leid ertrinken|Hexerei|Alle Kreaturen erhalten -2/-2 bis zum Ende des Zuges. Hellsicht 1. (Schaue dir die oberste Karte deiner Bibliothek an. Du kannst diese Karte unter deine Bibliothek legen.) +Drown in the Loch|Im See ertrinken|Spontanzauber|Bestimme eines —\n• Neutralisiere einen Zauberspruch deiner Wahl mit umgewandelten Manakosten kleiner oder gleich der Anzahl an Karten im Friedhof seines Beherrschers.\n• Zerstöre eine Kreatur deiner Wahl mit umgewandelten Manakosten kleiner oder gleich der Anzahl an Karten im Friedhof ihres Beherrschers. Drowned Catacomb|Versunkene Katakomben|Land|Die Versunkenen Katakomben kommen getappt ins Spiel, es sei denn, du kontrollierst eine Insel oder einen Sumpf.\n{T}: Erhöhe deinen Manavorrat um {U} oder {B}. Drowned Rusalka|Ertränkte Rusalka|Kreatur — Geist|{U}, opfere eine Kreatur: Wirf eine Karte aus deiner Hand ab und ziehe dann eine Karte. Drowned Secrets|Versunkene Geheimnisse|Verzauberung|Immer wenn du einen blauen Zauberspruch wirkst, legt ein Spieler deiner Wahl die obersten zwei Karten seiner Bibliothek auf seinen Friedhof. @@ -4598,6 +4602,7 @@ Edge of Autumn|Herbstanfang|Hexerei|Kontrollierst du vier oder weniger Länder, Edge of Malacol|Rand von Malacol|Welt — Belenon|Falls eine Kreatur, die du kontrollierst, während deines Enttappsegments enttappen würde, lege stattdessen zwei +1/+1-Marken auf sie.\nImmer wenn du chaos würfelst, enttappe alle Kreaturen, die du kontrollierst. Edge of the Divinity|Zwiefalt der Gottheit|Verzauberung — Aura|Kreaturenverzauberung\nSolange die verzauberte Kreatur weiß ist, erhält sie +1/+2.\nSolange die verzauberte Kreatur schwarz ist, erhält sie +2/+1. Edgewalker|Gratwanderer|Kreatur — Kleriker|Klerikerzauber, die du spielst, kosten beim Ausspielen {W}{B} weniger. Dieser Effekt reduziert nur die Menge an farbigem Mana, das du bezahlst. (Spielst du zum Beispiel einen Kleriker mit Manakosten von {1}{W}, kostet er nur {1} beim Ausspielen.) +Edgewall Innkeeper|Wirt von Wallstädt|Kreatur — Mensch, Gesinde|Immer wenn du einen Kreaturenzauber mit einem Abenteuer wirkst, ziehe eine Karte. (Die Kreatur muss das Abenteuer nicht erlebt haben.) Edifice of Authority|Bauwerk der Autorität|Artefakt|{1}, {T}: Eine Kreatur deiner Wahl kann in diesem Zug nicht angreifen. Lege eine Ziegelmarke auf das Bauwerk der Autorität.\n{1}, {T}: Bis zu deinem nächsten Zug kann eine Kreatur deiner Wahl nicht angreifen oder blocken und ihre aktivierten Fähigkeiten können nicht aktiviert werden. Aktiviere diese Fähigkeit nur, falls sich drei oder mehr Ziegelmarken auf dem Bauwerk der Autorität befinden. Edric, Spymaster of Trest|Edric, Meisterspion von Trest|Legendäre Kreatur — Elf, Räuber|Immer wenn eine Kreatur einem deiner Gegner Kampfschaden zufügt, kann ihr Beherrscher eine Karte ziehen. Eel Umbra|Schattenhafter Aal|Verzauberung — Aura|Aufblitzen (Du kannst diesen Zauberspruch zu jedem Zeitpunkt wirken, zu dem du einen Spontanzauber wirken könntest.)\nKreaturenverzauberung\nDie verzauberte Kreatur erhält +1/+1.\nTotembeistand (Falls die verzauberte Kreatur zerstört würde, entferne stattdessen allen Schaden von ihr und zerstöre diese Aura.) @@ -4964,6 +4969,7 @@ Ertai, the Corrupted|Ertai, der Verführte|Kreatur — Zauberer, Legende|{U}, {T Erupting Dreadwolf|Aufberstender Schreckenswolf|Kreatur — Eldrazi, Werwolf|Immer wenn der Aufberstende Schreckenswolf angreift, fügt er einer Kreatur oder einem Spieler deiner Wahl 2 Schadenspunkte zu. Escape Artist|Entfesselungskünstler|Kreatur — Zauberer|Der Entfesselungskünstler ist unblockbar.\n{U}, wirf eine Karte aus deiner Hand ab: Bringe den Entfesselungskünstler auf die Hand seines Besitzers zurück. Escape Routes|Fluchtwege|Verzauberung|{2}{U}: Bringe eine weiße oder schwarze Kreatur, die Du kontrollierst, auf die Hand ihres Besitzers zurück. +Escape to the Wilds|Flucht in die Wildnis|Hexerei|Schicke die obersten fünf Karten deiner Bibliothek ins Exil. Du kannst Karten, die auf diese Weise ins Exil geschickt wurden, bis zum Ende deines nächsten Zuges spielen.\nDu darfst in diesem Zug ein zusätzliches Land spielen. Escaped Null|Entflohene Null|Kreatur — Zombie, Berserker|Lebensverknüpfung\nImmer wenn die Entflohene Null blockt oder geblockt wird, erhält sie +5/+0 bis zum Ende des Zuges. Escaped Shapeshifter|Entflohener Gestaltwandler|Beschwörung eines Gestaltwandlers|Solange Deine Gegner fliegende Kreaturen kontrollieren, erhält auch der Geflohene Gestaltwandler Flugfähigkeit. Das Gleiche gilt für Erstschlag, Trampeln und Schutz vor einer beliebigen Farbe. Esper Battlemage|Kampfmagierin aus Esper|Artefaktkreatur — Mensch, Zauberer|{W}, {T}: Verhindere die nächsten 2 Schadenspunkte, die dir in diesem Zug zugefügt würden.\n{B}, {T}: Eine Kreatur deiner Wahl erhält -1/-1 bis zum Ende des Zuges. @@ -5180,7 +5186,8 @@ Fact or Fiction|Fakt oder Fiktion|Spontanzauber|Decke die obersten fünf Karten Fade Away|Dahinschwinden|Hexerei|Für jede Kreatur bezahlt der Spieler, der sie kontrolliert, 1 oder opfert eine bleibende Karte. Fade from Memory|Verblassende Erinnerung|Spontanzauber|Entferne eine Karte deiner Wahl aus einem Friedhof ganz aus dem Spiel.\nUmwandlung {B} ({B}, wirf diese Karte aus deiner Hand ab: Ziehe eine Karte.) Fade into Antiquity|In Vergessenheit geraten|Hexerei|Schicke ein Artefakt oder eine Verzauberung deiner Wahl ins Exil. -Fae of Wishes|Gewährt|Hexerei — Abenteuer|Du kannst eine Nichtkreatur-Karte bestimmen, die du besitzt und die sich außerhalb der Partie befindet, sie offen vorzeigen und auf deine Hand nehmen. +Fae of Wishes|Feen der Wünsche|Kreatur — Feenwesen, Zauberer|Fliegend\n{1}{U}, wirf zwei Karten ab: Bringe die Feen der Wünsche auf die Hand ihres Besitzers zurück. +Faeburrow Elder|Feenheim-Älteste|Kreatur — Baumhirte, Druide|Wachsamkeit\nDie Feenheim-Älteste erhält +1/+1 für jede Farbe unter den bleibenden Karten, die du kontrollierst.\n{T}: Erzeuge für jede Farbe unter den bleibenden Karten, die du kontrollierst, ein Mana der entsprechenden Farbe. Faerie Artisans|Feen-Handwerker|Kreatur — Feenwesen, Handwerker|Fliegend\nImmer wenn eine Nichtspielsteinkreatur unter der Kontrolle eines Gegners ins Spiel kommt, erzeuge einen Spielstein, der eine Kopie jener Kreatur ist, außer dass er zusätzlich zu seinen anderen Typen auch ein Artefakt ist. Schicke dann alle anderen mit den Feen-Handwerkern erzeugten Spielsteine ins Exil. Faerie Conclave|Feenkonklave|Land|Das Feenkonklave kommt getappt ins Spiel.\n{T}: Erhöhe deinen Manavorrat um {U}.\n{1}{U}: Das Feenkonklave wird zu einer 2/1 blauen Feenwesen-Kreatur mit Flugfähigkeit bis zum Ende des Zuges. Es ist immer noch ein Land. Faerie Duelist|Feenwesen-Duellant|Kreatur — Feenwesen, Räuber|Aufblitzen\nFliegend\nWenn der Feenwesen-Duellant ins Spiel kommt, erhält eine Kreatur deiner Wahl, die ein Gegner kontrolliert, -2/-0 bis zum Ende des Zuges. @@ -5321,6 +5328,7 @@ Feast of the Unicorn|Einhornschlachtfest|Kreaturenverzauberung|Die verzauberte K Feast on the Fallen|Leichenschmaus|Verzauberung|Lege zu Beginn jedes Versorgungssegments, falls ein Gegner im letzten Zug Lebenspunkte verloren hat, eine +1/+1-Marke auf eine Kreatur deiner Wahl, die du kontrollierst. Feast or Famine|Um Leben und Tod|Spontanzauber|Begrabe eine nicht-schwarze Nicht-Artefaktkreatur Deiner Wahl, oder bringe einen Zombie-Spielstein ins Spiel. Behandle diesen Spielstein wie eine 2/2 schwarze Kreatur. Feaster of Fools|Narrenfresser|Kreatur — Dämon|Einberufen (Deine Kreaturen können dir helfen, diesen Zauberspruch zu wirken. Mit jeder Kreatur, die du tappst, während du diesen Zauberspruch wirkst, bezahlst du für {1} oder ein Mana der Farbe jener Kreatur.)\nFliegend\nVerschlingen 2 (Sowie diese Karte ins Spiel kommt, kannst du eine beliebige Anzahl an Kreaturen opfern. Diese Kreatur kommt mit doppelt so vielen +1/+1-Marken ins Spiel.) +Feasting Troll King|Schmausender Trollkönig|Kreatur — Troll, Adliger|Wachsamkeit, verursacht Trampelschaden\nWenn der Schmausende Trollkönig ins Spiel kommt und falls du ihn aus deiner Hand gewirkt hast, erzeuge drei Speise-Spielsteine.\nOpfere drei Speisen: Bringe den Schmausenden Trollkönig aus deinem Friedhof ins Spiel zurück. Aktiviere diese Fähigkeit nur während deines Zuges. Feat of Resistance|Tapferer Widerstand|Spontanzauber|Lege eine +1/+1-Marke auf eine Kreatur deiner Wahl, die du kontrollierst. Sie erhält bis zum Ende des Zuges Schutz vor einer Farbe, die du bestimmst. Feather, the Redeemed|Feder, geläuterter Engel|Legendäre Kreatur — Engel|Fliegend\nImmer wenn du einen Spontanzauber oder eine Hexerei wirkst, der bzw. die eine Kreatur, die du kontrollierst, als Ziel hat, schicke jene Karte ins Exil, statt sie auf deinen Friedhof zu legen, sowie sie verrechnet wird. Falls du dies tust, bringe sie zu Beginn des nächsten Endsegments auf deine Hand zurück. Fecundity|Guter Dünger|Verzauberung|Immer wenn eine Kreatur aus dem Spiel auf dem Friedhof landet, kann der Beherrscher der Kreatur eine Karte ziehen. @@ -5347,6 +5355,7 @@ Fell Flagship|Unheilvolles Flaggschiff|Artefakt — Fahrzeug|Piraten, die du kon Fell Shepherd|Grausamer Hirte|Kreatur — Avatar|Immer wenn der Grausame Hirte einem Spieler Kampfschaden zufügt, kannst du alle Kreaturenkarten, die in diesem Zug aus dem Spiel auf deinen Friedhof gelegt wurden, auf deine Hand zurückbringen.{B}, opfere eine andere Kreatur: Eine Kreatur deiner Wahl erhält -2/-2 bis zum Ende des Zuges. Fell Specter|Bestialisches Gespenst|Kreatur — Specter|Fliegend\nWenn das Bestialische Gespenst ins Spiel kommt, wirft ein Gegner deiner Wahl eine Karte ab.\nImmer wenn ein Gegner eine Karte abwirft, verliert er 2 Lebenspunkte. Fell the Mighty|Die Mächtigen stürzen|Hexerei|Zerstöre alle Kreaturen, deren Stärke größer ist als die Stärke einer Kreatur deiner Wahl. +Fell the Pheasant|Fasanenjagd|Spontanzauber|Die Fasanenjagd fügt einer fliegenden Kreatur deiner Wahl 5 Schadenspunkte zu. Erzeuge einen Speise-Spielstein. (Er ist ein Artefakt mit „{2}, {T}, opfere dieses Artefakt: Du erhältst 3 Lebenspunkte dazu.") Fellwar Stone|Fellwarstein|Artefakt|{T}: Erhöhe Deinen Manavorrat um ein Mana eines Typs, den ein Land eines Gegners produzieren kann. Spiele diese Fähigkeit wie eine Manaquelle. Femeref Archers|Bogenschützen der Femeref|Beschwörung von Bogenschützen|{T}: Die Bogenschützen der Femeref fügen einer angreifenden fliegenden Zielkreatur 4 Schadenspunkte zu. Femeref Enchantress|Zauberin der Femeref|Beschwörung einer Naturzauberin|Immer, wenn eine Verzauberung aus dem Spiel auf dem Friedhof landet, ziehe eine Karte. @@ -5433,6 +5442,7 @@ Fiend of the Shadows|Unhold aus den Schatten|Kreatur — Vampir, Zauberer|Immer Fiendslayer Paladin|Unholdjagender Paladin|Kreatur — Mensch, Ritter|Erstschlag (Diese Kreatur fügt Kampfschaden vor Kreaturen ohne Erstschlag zu.) Lebensverknüpfung (Schaden, der von dieser Kreatur zugefügt wird, lässt dich ebenso viele Lebenspunkte dazuerhalten.)Der Unholdjagende Paladin kann nicht das Ziel von schwarzen oder roten Zaubersprüchen sein, die deine Gegner kontrollieren. Fierce Empath|Grimmiger Empath|Kreatur — Elf|Wenn der Grimmige Empath ins Spiel kommt, kannst du deine Bibliothek nach einer Kreaturenkarte mit umgewandelten Manakosten von 6 oder mehr durchsuchen, sie deinem Gegner zeigen und auf deine Hand nehmen. Mische danach deine Bibliothek. Fierce Invocation|Wütende Anrufung|Hexerei|Manifestiere die oberste Karte deiner Bibliothek und lege dann zwei +1/+1-Marken auf sie. (Um eine Karte zu manifestieren, bringe sie als eine 2/2 Kreatur verdeckt ins Spiel. Decke sie zu einem beliebigen Zeitpunkt für ihre Manakosten auf, falls es eine Kreaturenkarte ist.) +Fierce Witchstalker|Erbitterter Hexenjäger|Kreatur — Wolf|Verursacht Trampelschaden\nWenn der Erbitterte Hexenjäger ins Spiel kommt, erzeuge einen Speise-Spielstein. (Er ist ein Artefakt mit „{2}, {T}, opfere dieses Artefakt: Du erhältst 3 Lebenspunkte dazu.") Fiery Bombardment|Feuriger Beschuss|Verzauberung|Farbwert {2}, opfere eine Kreatur: Der Feurige Beschuss fügt einer Kreatur oder einem Spieler deiner Wahl so viele Schadenspunkte zu, wie die Anzahl der roten Manasymbole in den Manakosten der geopferten Kreatur beträgt. Fiery Cannonade|Feurige Kanonade|Spontanzauber|Die Feurige Kanonade fügt jeder Nicht-Pirat-Kreatur 2 Schadenspunkte zu. Fiery Conclusion|Feuriges Ende|Spontanzauber|Opfere eine Kreatur als zusätzliche Kosten, um Feuriges Ende zu spielen.\nFeuriges Ende fügt einer Kreatur deiner Wahl 5 Schadenspunkte zu. @@ -5613,6 +5623,7 @@ Flashfires|Steppenbrand|Hexerei|Vernichte alle Ebenen im Spiel. Flashfreeze|Blitzeis|Spontanzauber|Neutralisiere einen roten oder grünen Zauberspruch deiner Wahl. Flash|Aufblitzen|Spontanzauber|Bringe eine Kreaturenkarte von Deiner Hand ins Spiel. Du kannst ihre Manakosten, verringert um bis zu 2, bezahlen. Wenn Du dies nicht tust, opfere die Kreatur. Flatten|Plattmachen|Spontanzauber|Eine Kreatur deiner Wahl erhält -4/-4 bis zum Ende des Zuges. +Flaxen Intruder|Flachsblonder Eindringling|Kreatur — Mensch, Berserker|Immer wenn der Flachsblonde Eindringling einem Spieler Kampfschaden zufügt, kannst du ihn opfern. Wenn du dies tust, zerstöre ein Artefakt oder eine Verzauberung deiner Wahl. Flayed Nim|Abgebalgter Nim|Kreatur — Skelett|Immer wenn der Abgebalgte Nim einer Kreatur Kampfschaden zufügt, verliert der Beherrscher dieser Kreatur ebenso viele Lebenspunkte.\n{2}{B}: Regeneriere den Abgebalgten Nim. Flayer Drone|Schinder-Drohne|Kreatur — Eldrazi, Drohne|Fahl (Diese Karte hat keine Farbe.)\nErstschlag\nImmer wenn eine andere farblose Kreatur unter deiner Kontrolle ins Spiel kommt, verliert ein Gegner deiner Wahl 1 Lebenspunkt. Flayer Husk|Schinderhülle|Artefakt — Ausrüstung|Lebende Waffe (Wenn diese Ausrüstung ins Spiel kommt, bringe einen 0/0 schwarzen Keim-Kreaturenspielstein ins Spiel und lege sie dann an ihn an.)\nDie ausgerüstete Kreatur erhält +1/+1.\nAusrüsten {2} @@ -5786,6 +5797,7 @@ Foresee|Voraussehen|Hexerei|Hellsicht 4, und ziehe dann zwei Karten. (Betrachte Foreshadow|Schatten der Zukunft|Spontanzauber|Nenne eine Karte. Lege die oberste Karte der Bibliothek eines Gegners Deiner Wahl auf seinen Friedhof. Wenn dies die genannte Karte ist, ziehe eine Karte.\nZiehe eine Karte zu Beginn der nächsten Versorgungsphase. Foresight|Vorsehung|Hexerei|Durchsuche Deine Bibliothek und entferne drei Karten daraus aus dem Spiel. Mische Deine Bibliothek danach neu.\nZiehe eine Karte zu Beginn der nächsten Versorgungsphase des nächsten Zuges. Forest|Wald|Land| +Forever Young|Ewige Jugend|Hexerei|Lege eine beliebige Anzahl an Kreaturenkarten deiner Wahl aus deinem Friedhof oben auf deine Bibliothek.\nZiehe eine Karte. Forfend|Verhüten|Spontanzauber|Verhindere allen Schaden, der Kreaturen in diesem Zug zugefügt würde. Forge Armor|Rüstungsschmiede|Spontanzauber|Opfere ein Artefakt als zusätzliche Kosten, um Rüstungsschmiede zu spielen.\nLege X +1/+1-Marken auf eine Kreatur deiner Wahl, wobei X gleich der umgewandelten Manakosten des geopferten Artefakts ist. Forge Devil|Schmelzenteufel|Kreatur — Teufel|Wenn der Schmelzenteufel ins Spiel kommt, fügt er einer Kreatur deiner Wahl 1 Schadenspunkt und dir 1 Schadenspunkt zu. @@ -5839,6 +5851,7 @@ Foul Renewal|Faulige Erneuerung|Spontanzauber|Bringe eine Kreaturenkarte deiner Foul Spirit|Geist der Fäulnis|Beschwörung eines Geistes|Fligend\nWenn der Geist der Fäulnis aus Deiner Hand ins Spiel kommt, zerstöre eines Deiner Länder. Foul-Tongue Invocation|Schandzungen-Anrufung|Spontanzauber|Als zusätzliche Kosten, um die Schandzungen-Anrufung zu wirken, kannst du eine Drache-Karte aus deiner Hand offen vorzeigen.\nEin Spieler deiner Wahl opfert eine Kreatur. Falls du eine Drache-Karte offen vorgezeigt oder einen Drachen kontrolliert hast, sowie du die Schandzungen-Anrufung gewirkt hast, erhältst du 4 Lebenspunkte dazu. Foul-Tongue Shriek|Schandzungen-Kreischen|Spontanzauber|Ein Gegner deiner Wahl verliert für jede angreifende Kreatur, die du kontrollierst, 1 Lebenspunkt. Du erhältst ebenso viele Lebenspunkte dazu. +Foulmire Knight|Faulschlamm-Ritter|Kreatur — Zombie, Ritter|Todesberührung Foundry Assembler|Gießerei-Monteur|Artefaktkreatur — Montagearbeiter|Improvisieren (Deine Artefakte können dir helfen, diesen Zauberspruch zu wirken. Mit jedem Artefakt, das du tappst, nachdem du mit dem Aktivieren deiner Manafähigkeiten fertig bist, bezahlst du {1}.) Foundry Champion|Champion der Schmelze|Kreatur — Elementarwesen, Soldat|Wenn der Champion der Schmelze ins Spiel kommt, fügt er einer Kreatur oder einem Spieler deiner Wahl so viele Schadenspunkte zu, wie du Kreaturen kontrollierst.\n{R}: Der Champion der Schmelze erhält +1/+0 bis zum Ende des Zuges.\n{W}: Der Champion der Schmelze erhält +0/+1 bis zum Ende des Zuges. Foundry Hornet|Gießerei-Hornisse|Kreatur — Insekt|Fliegend\nWenn die Gießerei-Hornisse ins Spiel kommt und falls du eine Kreatur mit einer +1/+1-Marke kontrollierst, erhalten Kreaturen, die deine Gegner kontrollieren, -1/-1 bis zum Ende des Zuges. @@ -6033,6 +6046,9 @@ Gang of Devils|Teufelsbande|Kreatur — Teufel|Wenn die Teufelsbande stirbt, fü Gang of Elk|Rotwildherde|Beschwörung von Rotwild|Immer wenn sie von einer Kreatur geblockt wird, erhält die Rotwildherde +2/+2 bis zum Ende des Zuges. Gangrenous Goliath|Blutloser Goliath|Kreatur — Zombie, Riese|Tappe drei ungetappte Kleriker, die du kontrollierst: Bringe den Blutlosen Goliath aus deinem Friedhof auf deine Hand zurück. Gangrenous Zombies|Blutlose Zombies|Beschwörung von Zombies|{T}: Opfere die Blutlosen Zombies, um jeder Kreatur und jedem Spieler 1 Schadenspunkt zuzufügen. Die Zombies fügen jeder Kreatur und jedem Spieler 2 Schadenspunkte zu, wenn Du verschneite Sümpfe beherrschst. +Garenbrig Carver|Garenbruck-Plattner|Kreatur — Mensch, Krieger| +Garenbrig Paladin|Garenbruck-Paladin|Kreatur — Riese, Ritter|Adamant — Falls drei oder mehr grüne Mana ausgegeben wurden, um diesen Zauberspruch zu wirken, kommt der Garenbruck-Paladin mit einer +1/+1-Marke ins Spiel.\nDer Garenbruck-Paladin kann von Kreaturen mit Stärke 2 oder weniger nicht geblockt werden. +Garenbrig Squire|Garenbruck-Junker|Kreatur — Mensch, Soldat|Immer wenn du einen Kreaturenzauber mit einem Abenteuer wirkst, erhält der Garenbruck-Junker +1/+1 bis zum Ende des Zuges. (Die Kreatur muss das Abenteuer nicht erlebt haben.) Gargantuan Gorilla|Gargantua-Gorilla|Beschwörung eines Gorillas|Opfere während Deiner Versorgungsphase einen Wald -oder begrabe den Gargantua-Gorilla und der Gargantua-Gorilla fügt Dir 7 Schadenspunkte zu.\nWenn Du einen verschneiten Wald auf diese Weise opferst, verursacht der Gargantua-Gorilla bis zum Ende des Zuges Trampelschaden.\n{T}: Der Gargantua-Gorilla fügt einer anderen Kreatur Deiner Wahl Schadenspunkte in Höhe seiner Stärke zu. Diese Kreatur fügt dem Gargantua-Gorilla Schadenspunkte in Höhe ihrer Stärke zu. Gargos, Vicious Watcher|Gargos, boshafter Behüter|Legendäre Kreatur — Hydra|Wachsamkeit\nHydra-Zaubersprüche, die du wirkst, kosten beim Wirken {4} weniger.\nImmer wenn eine Kreatur, die du kontrollierst, das Ziel eines Zauberspruchs wird, kämpft Gargos, boshafter Behüter, gegen bis zu eine Kreatur deiner Wahl, die du nicht kontrollierst. Gargoyle Castle|Schloss der Gargoyle|Land|{T}: Erhöhe deinen Manavorrat um {1}.\n{5}, {T}, opfere das Schloss der Gargoyle: Bringe einen 3/4 farblosen Gargoylen-Artefaktkreaturenspielstein mit Flugfähigkeit ins Spiel. @@ -6047,6 +6063,7 @@ Garruk's Horde|Garruks Horde|Kreatur — Bestie|Verursacht Trampelschaden (Diese Garruk's Packleader|Garruks Rudelführer|Kreatur — Bestie|Immer wenn eine andere Kreatur mit Stärke 3 oder mehr unter deiner Kontrolle ins Spiel kommt, kannst du eine Karte ziehen. Garruk, Apex Predator|Garruk, Oberstes Raubtier|Planeswalker — Garruk|+1: Zerstöre einen anderen Planeswalker deiner Wahl.\n+1: Bringe einen 3/3 schwarzen Bestie-Kreaturenspielstein mit Todesberührung ins Spiel.\n-3: Zerstöre eine Kreatur deiner Wahl. Du erhältst Lebenspunkte in Höhe ihrer Widerstandskraft dazu.\n-8: Ein Gegner deiner Wahl erhält ein Emblem mit „Immer wenn eine Kreatur dich angreift, erhält sie +5/+5 und verursacht Trampelschaden bis zum Ende des Zuges." Garruk, Caller of Beasts|Garruk, Rufer der Bestien|Planeswalker — Garruk|+1: Decke die obersten fünf Karten deiner Bibliothek auf. Nimm alle Kreaturenkarten, die auf diese Weise aufgedeckt wurden, auf deine Hand und lege den Rest der Karten in beliebiger Reihenfolge unter deine Bibliothek.-3: Du kannst eine grüne Kreaturenkarte aus deiner Hand ins Spiel bringen.-7: Du erhältst ein Emblem mit „Immer wenn du einen Kreaturenzauber wirkst, kannst du deine Bibliothek nach einer Kreaturenkarte durchsuchen, sie ins Spiel bringen und dann deine Bibliothek mischen." +Garruk, Cursed Huntsman|Garruk, verfluchter Jäger|Legendärer Planeswalker — Garruk|0: Erzeuge zwei 2/2 schwarze und grüne Wolf-Kreaturenspielsteine mit „Wenn diese Kreatur stirbt, lege eine Loyalitätsmarke auf jeden Garruk, den du kontrollierst."\n—3: Zerstöre eine Kreatur deiner Wahl. Ziehe eine Karte.\n—6: Du erhältst ein Emblem mit „Kreaturen, die du kontrollierst, erhalten +3/+3 und verursachen Trampelschaden." Garruk, Primal Hunter|Garruk der Urjäger|Legendärer Planeswalker — Garruk|+1: Erzeuge einen 3/3 grünen Bestie-Kreaturenspielstein.\n−3: Ziehe so viele Karten, wie die höchste Stärke unter den Kreaturen, die du kontrollierst, beträgt.\n−6: Erzeuge für jedes Land, das du kontrollierst, einen 6/6 grünen Wurm-Kreaturenspielstein. Garruk, the Veil-Cursed|Garruk der Schleierverfluchte|Planeswalker — Garruk|+1: Bringe einen 1/1 schwarzen Wolf-Kreaturenspielstein mit Todesberührung ins Spiel.\n-1: Opfere eine Kreatur. Falls du dies tust, durchsuche deine Bibliothek nach einer Kreatur-Karte, zeige sie offen vor, nimm sie auf deine Hand und mische dann deine Bibliothek.\n-3: Bis zum Ende des Zuges verursachen alle Kreaturen, die du kontrollierst, Trampelschaden und erhalten +X/+X, wobei X die Anzahl an Kreaturenkarten in deinem Friedhof ist. Garza Zol, Plague Queen|Garza Zol, Seuchenkönigin|Legendäre Kreatur — Vampir|Fliegend, Eile\nImmer wenn eine Kreatur, der in diesem Zug durch Garza Zol, Seuchenkönigin Schaden zugefügt wurde, auf einen Friedhof gelegt wird, lege eine +1/+1-Marke auf Garza Zol.\nImmer wenn Garza Zol einem Spieler Kampfschaden zufügt, kannst du eine Karte ziehen. @@ -6237,6 +6254,7 @@ Giant Harbinger|Riesen-Vorbote|Kreatur — Riese, Schamane|Wenn der Riesen-Vorbo Giant Killer|Riesentöter|Kreatur — Mensch, Gesinde|{1}{W}, {T}: Tappe eine Kreatur deiner Wahl. Giant Mantis|Riesengottesanbeterin|Beschwörung einer Gottesanbeterin|Die Riesengottesanbeterin kann fliegende Kreaturen blocken. Giant Octopus|Riesenkrake|Beschwörungszauber| +Giant Opportunity|Riesen-Gelegenheit|Hexerei|Du kannst zwei Speisen opfern. Falls du dies tust, erzeuge einen 7/7 grünen Riese-Kreaturenspielstein. Andernfalls erzeuge drei Speise-Spielsteine. (Sie sind Artefakte mit „{2}, {T}, opfere dieses Artefakt: Du erhältst 3 Lebenspunkte dazu.") Giant Oyster|Riesenauster|Beschwörung einer Auster|Du kannst wählen, ob Du die Riesenauster während Deiner Enttap-Phase enttappt oder nicht.\n{T}: Die getappte Zielkreatur enttappt nicht während der Enttap-Phase ihres Beherrschers, solange die Riesenauster getappt ist. Lege während Deiner Versorgungsphase eine -1/-1-Spielmarke auf diese Kreatur. Entferne alle diese -1/-1-Spielmarken von der Zielkreatur, wenn die Riesenauster enttappt wird oder das Spiel verlässt. Giant Scorpion|Riesenskorpion|Kreatur — Skorpion|Todesberührung (Eine beliebige Menge Schadenspunkte, die er einer Kreatur zufügt, sind ausreichend, um diese zu zerstören.) Giant Solifuge|Riesige Solifuge|Kreatur — Insekt|({R/G} kann entweder mit {R} oder mit {G} bezahlt werden.)\nVerursacht Trampelschaden, Eile\nDie Riesige Solifuge kann nicht das Ziel von Zaubersprüchen oder Fähigkeiten sein. @@ -6247,6 +6265,7 @@ Giant Tortoise|Riesenschildkröte|Beschwörung einer Schildkröte|Die Riesenschi Giant Trap Door Spider|Riesige Falltürspinne|Beschwörung einer Spinne|{1}{R}{G}, {T}: Entferne die Riesige Falltürspinne und eine nichtfliegende Kreatur Deiner Wahl, die Dich angreift, aus dem Spiel. Giant Warthog|Riesen-Warzenschwein|Kreatur — Bestie|Verursacht Trampelschaden Giant's Ire|Zorn des Riesen|Stammes-Hexerei — Riese|Zorn des Riesen fügt einem Spieler deiner Wahl 4 Schadenspunkte zu. Falls du einen Riesen kontrollierst, ziehe eine Karte. +Giant's Skewer|Bratspieß des Riesen|Artefakt — Ausrüstung|Die ausgerüstete Kreatur erhält +2/+1.\nImmer wenn die ausgerüstete Kreatur einer Kreatur Kampfschaden zufügt, erzeuge einen Speise-Spielstein. (Er ist ein Artefakt mit „{2}, {T}, opfere dieses Artefakt: Du erhältst 3 Lebenspunkte dazu.")\nAusrüsten {3} ({3}: Lege diese Karte an eine Kreatur deiner Wahl an, die du kontrollierst. Spiele Ausrüsten wie eine Hexerei.) Giantbaiting|Hetzjagd der Riesen|Hexerei|Bringe einen 4/4 roten und grünen (Riese, Krieger)-Kreaturenspielstein mit Eile ins Spiel. Entferne ihn am Ende des Zuges ganz aus dem Spiel.\nVerschwören (Sowie du diesen Zauberspruch spielst, kannst du zwei ungetappte Kreaturen tappen, die du kontrollierst und die mindestens eine Farbe mit dem Zauberspruch gemeinsam haben. Wenn du das tust, kopiere ihn.) Gibbering Descent|Lallender Niedergang|Verzauberung|Zu Beginn des Versorgungssegments jedes Spielers verliert dieser Spieler 1 Lebenspunkt und wirft eine Karte aus seiner Hand ab.\n Versessenheit Übergehe dein Enttapp-Segment, falls du keine Karten auf der Hand hast.\n Wahnsinn {2}{B}{B} (Falls du diese Karte aus deiner Hand abwirfst, kannst du sie für ihre Wahnsinn-Kosten spielen, anstatt sie auf deinen Friedhof zu legen.) Gibbering Fiend|Geifernder Unhold|Kreatur — Teufel|Wenn der Geifernde Unhold ins Spiel kommt, fügt er jedem Gegner 1 Schadenspunkt zu.\nDelirium — Zu Beginn des Versorgungssegments jedes Gegners und falls dein Friedhof vier oder mehr unterschiedliche Kartentypen enthält, fügt der Geifernde Unhold diesem Spieler 1 Schadenspunkt zu. @@ -6294,6 +6313,7 @@ Gigantosaurus|Gigantosaurus|Kreatur — Dinosaurier| Gigapede|Gigafüßler|Kreatur — Insekt|Der Gigafüßler kann nicht das Ziel von Zaubersprüchen oder Fähigkeiten sein.\nZu Beginn deines Versorgungssegments kannst du, falls der Gigafüßler in deinem Friedhof ist, eine Karte aus deiner Hand abwerfen. Falls du dies tust, bringe den Gigafüßler auf deine Hand zurück. Gilded Cerodon|Goldhorn-Cerodon|Kreatur — Bestie|Immer wenn das Goldhorn-Cerodon angreift und falls du eine Wüste kontrollierst oder sich eine Wüste-Karte in deinem Friedhof befindet, kann eine Kreatur deiner Wahl in diesem Zug nicht blocken. Gilded Drake|Güldener Sceada|Beschwörung eines Sceadas|Fliegend\nWenn der Güldene Sceada ins Spiel kommt, tausche die Kontrolle über den Güldenen Sceada mit einer Kreatur Deiner Wahl, die einer Deiner Gegner kontrolliert, oder opfere den Güldenen Sceada. +Gilded Goose|Goldene Gans|Kreatur — Vogel|Fliegend\nWenn die Goldene Gans ins Spiel kommt, erzeuge einen Speise-Spielstein. (Er ist ein Artefakt mit „{2}, {T}, opfere dieses Artefakt: Du erhältst 3 Lebenspunkte dazu.")\n{1}{G}, {T}: Erzeuge einen Speise-Spielstein.\n{T}, opfere eine Speise: Erzeuge ein Mana einer beliebigen Farbe. Gilded Light|Güldenes Licht|Spontanzauber|Du erhältst Verhülltheit bis zum Ende des Zuges. (Du kannst nicht das Ziel von Zaubersprüchen oder Fähigkeiten sein.)\nUmwandlung {2} ({2}, wirf diese Karte ab: Ziehe eine Karte.) Gilded Lotus|Vergoldeter Lotus|Artefakt|{T}: Erhöhe deinen Manavorrat um drei Mana einer beliebigen Farbe. Gilded Sentinel|Vergoldeter Wächter|Artefaktkreatur — Golem| @@ -6693,7 +6713,7 @@ Granite Gargoyle|Granitgargoyle|Beschwörung eines Speiers|Kann fliegen; {R}: +0 Granite Grip|Granitgriff|Kreaturenverzauberung|Die verzauberte Kreatur erhält +1/+0 für jedes Gebirge, das du kontrollierst. Granite Shard|Granitscherbe|Artefakt|{3}, {T} oder {R}, {T}: Die Granitscherbe fügt einer Kreatur oder einem Spieler deiner Wahl 1 Schadenspunkt zu. Granitic Titan|Granit-Titan|Kreatur — Elementarwesen|Bedrohlich\nUmwandlung {2} ({2}, wirf diese Karte ab: Ziehe eine Karte.) -Granted|Feen der Wünsche|Kreatur — Feenwesen, Zauberer|Fliegend\n{1}{U}, wirf zwei Karten ab: Bringe die Feen der Wünsche auf die Hand ihres Besitzers zurück. +Granted|Gewährt|Hexerei — Abenteuer|Du kannst eine Nichtkreatur-Karte bestimmen, die du besitzt und die sich außerhalb der Partie befindet, sie offen vorzeigen und auf deine Hand nehmen. Granulate|Granulieren|Hexerei|Zerstöre alle Artefakte, die kein Land sind und umgewandelte Manakosten von 4 oder weniger haben. Grapeshot Catapult|Kartätsche|Artefaktkreatur|{T}: Die Kartätsche fügt einer Kreatur mit Flugfähigkeit 1 Schadenspunkt zu. Grapeshot|Traubenkartusche|Hexerei|Die Traubenkartusche fügt einer Kreatur oder einem Spieler deiner Wahl 1 Schadenspunkt zu.\nSturm (Wenn du diesen Zauberspruch spielst, kopiere ihn einmal für jeden Zauberspruch, der in diesem Zug bereits gespielt wurde. Du kannst neue Ziele für die Kopien bestimmen.) @@ -6908,6 +6928,7 @@ Gruesome Fate|Grausiges Schicksal|Hexerei|Jeder Gegner verliert für jede Kreatu Gruesome Menagerie|Morbide Menagerie|Hexerei|Bestimme eine Kreaturenkarte mit umgewandelten Manakosten von 1 in deinem Friedhof. Mache dann dasselbe mit Kreaturenkarten mit umgewandelten Manakosten von 2 und 3. Bringe die bestimmten Karten ins Spiel zurück. Gruesome Scourger|Grausamer Auspeitscher|Kreatur — Ork, Krieger|Wenn der Grausame Auspeitscher ins Spiel kommt, fügt er einem Gegner oder Planeswalker deiner Wahl so viele Schadenspunkte zu, wie du Kreaturen kontrollierst. Gruesome Slaughter|Grausames Gemetzel|Hexerei|Farblose Kreaturen, die du kontrollierst, erhalten bis zum Ende des Zuges „{T}: Diese Kreatur fügt einer Kreatur deiner Wahl Schadenspunkte in Höhe ihrer Stärke zu." +Grumgully, the Generous|Grumgully der Großzügige|Legendäre Kreatur — Goblin, Schamane|Jede andere Nicht-Mensch-Kreatur, die du kontrollierst, kommt mit einer zusätzlichen +1/+1-Marke ins Spiel. Grunn, the Lonely King|Grunn, der einsame König|Legendäre Kreatur — Menschenaffe, Krieger|Bonus {3} (Du kannst zusätzlich {3} bezahlen, sowie du diesen Zauberspruch wirkst.)\nFalls die Bonuskosten von Grunn, dem einsamen König, bezahlt wurden, kommt er mit fünf +1/+1-Marken ins Spiel.\nImmer wenn Grunn alleine angreift, verdopple seine Stärke und Widerstandskraft bis zum Ende des Zuges. Gruul Beastmaster|Gruul-Bändigerin|Kreatur — Mensch, Schamane|Aufruhr (Du bestimmst, ob diese Kreatur mit einer +1/+1-Marke oder mit Eile ins Spiel kommt.)\nImmer wenn die Gruul-Bändigerin angreift, erhält eine andere Kreatur deiner Wahl, die du kontrollierst, +X/+0 bis zum Ende des Zuges, wobei X gleich der Stärke der Gruul-Bändigerin ist. Gruul Charm|Gruul-Amulett|Spontanzauber|Bestimme eines — Nichtfliegende Kreaturen können in diesem Zug nicht blocken; oder übernimm die Kontrolle über alle bleibenden Karten, die du besitzt; oder das Gruul-Amulett fügt jeder fliegenden Kreatur 3 Schadenspunkte zu. @@ -7200,6 +7221,7 @@ Heart of Kiran|Herz des Kiran|Legendäres Artefakt — Fahrzeug|Fliegend, Wachsa Heart of Light|Herz aus Licht|Kreaturenverzauberung|Verhindere allen Schaden, der der verzauberten Kreatur zugefügt und von ihr zugefügt würde. Heart of Ramos|Herz des Ramos|Artefakt|{T}: Erhöhe Deinen Manavorrat um ein rotes Mana.\nOpfere das Herz des Ramos: Erhöhe Deinen Manavorrat um ein rotes Mana. Heart of Yavimaya|Herz des Yavimaya-Waldes|Land|Opfere einen Wald, wenn das Herz des Yavimaya-Waldes ins Spiel kommt, oder begrabe das Herz des Yavimaya-Waldes.\n{T}: Erhöhe Deinen Manavorrat um {G}.\n{T}: Eine Kreatur Deiner Wahl erhält +1/+1 bis zum Ende des Zuges. +Heart's Desire|Herzenswunsch|Hexerei — Abenteuer|Erzeuge einen 1/1 weißen Mensch-Kreaturenspielstein. (Schicke diese Karte dann ins Exil. Du kannst sie später als Kreatur aus dem Exil wirken.) Heart-Piercer Bow|Herzstecherbogen|Artefakt — Ausrüstung|Immer wenn die ausgerüstete Kreatur angreift, fügt der Herzstecherbogen einer Kreatur deiner Wahl, die der verteidigende Spieler kontrolliert, 1 Schadenspunkt zu.\nAusrüsten {1} Heart-Piercer Manticore|Herzstecher-Mantikor|Kreatur — Mantikor|Wenn der Herzstecher-Mantikor ins Spiel kommt, kannst du eine andere Kreatur opfern. Wenn du dies tust, fügt der Herzstecher-Mantikor einem Ziel deiner Wahl Schadenspunkte in Höhe der Stärke der geopferten Kreatur zu.\nEinbalsamieren {5}{R} ({5}{R}, schicke diese Karte aus deinem Friedhof ins Exil: Erzeuge einen Spielstein, der eine Kopie von ihr ist, außer dass er ein weißer Zombie-Mantikor ohne Manakosten ist. Spiele Einbalsamieren wie eine Hexerei.) Heartbeat of Spring|Herzschlag des Frühlings|Verzauberung|Immer wenn ein Spieler ein Land für Mana tappt, erhöht dieser Spieler seinen Manavorrat um ein zusätzliches Mana dieses Typs. @@ -7789,6 +7811,7 @@ Imposing Sovereign|Achtunggebietende Herrscherin|Kreatur — Mensch|Kreaturen, d Imposing Visage|Eindrucksvolles Gesicht|Verzaubere Kreatur|Die verzauberte Kreatur kann nicht von nur einer Kreatur geblockt werden. Impostor of the Sixth Pride|Täuscher des sechsten Rudels|Kreatur — Gestaltwandler|Wandelwicht (Diese Karte hat alle Kreaturentypen.) Imprisoned in the Moon|Gefangen im Mond|Verzauberung — Aura|Verzaubert eine Kreatur, ein Land oder einen Planeswalker\nDie verzauberte bleibende Karte ist ein farbloses Land mit „{T}: Erhöhe deinen Manavorrat um {C}" und verliert alle anderen Kartentypen und Fähigkeiten. +Improbable Alliance|Ungewöhnliche Allianz|Verzauberung|Immer wenn du deine zweite Karte innerhalb desselben Zuges ziehst, erzeuge einen 1/1 blauen Feenwesen-Kreaturenspielstein mit Flugfähigkeit.\n{4}{U}{R}: Ziehe eine Karte und wirf dann eine Karte ab. Impromptu Raid|Stegreifüberfall|Verzauberung|{2}{R/G}: Decke die oberste Karte deiner Bibliothek auf. Falls es keine Kreaturenkarte ist, lege sie auf deinen Friedhof. Bringe sonst die Karte ins Spiel. Die Kreatur hat Eile. Opfere sie am Ende des Zuges. Improvised Armor|Improvisierte Rüstung|Kreaturenverzauberung|Die verzauberte Kreatur erhält +2/+5.Umwandlung {3} ({3}, wirf diese Karte aus deiner Hand ab: Ziehe eine Karte.) Imps' Taunt|Spott des Bolds|Spontanzauber|Rückkauf 3\nEine Kreatur Deiner Wahl greift in diesem Zug an, wenn möglich. @@ -7923,6 +7946,7 @@ Inquisitor Exarch|Inquisitor-Exarch|Kreatur — Kleriker|Wenn der Inquisitor-Exa Inquisitor's Flail|Flegel des Inquisitors|Artefakt — Ausrüstung|Falls die ausgerüstete Kreatur Kampfschaden zufügen würde, fügt sie stattdessen doppelt so viel Schaden zu.\nFalls eine andere Kreatur der ausgerüsteten Kreatur Kampfschaden zufügen würde, fügt sie der ausgerüsteten Kreatur stattdessen doppelt so viel Schaden zu.\nAusrüsten {2} Inquisitor's Ox|Ochse des Inquisitors|Kreatur — Ochse|Delirium — Der Ochse des Inquisitors erhält +1/+0 und hat Wachsamkeit, solange dein Friedhof vier oder mehr unterschiedliche Kartentypen enthält. Inquisitor's Snare|Falle des Inquisitors|Spontanzauber|Verhindere allen Schaden, den eine angreifende oder blockende Kreatur deiner Wahl in diesem Zug zufügen würde. Falls diese Kreatur schwarz oder rot ist, zerstöre sie. +Insatiable Appetite|Unstillbarer Appetit|Spontanzauber|Du kannst eine Speise opfern. Falls du dies tust, erhält eine Kreatur deiner Wahl +5/+5 bis zum Ende des Zuges. Andernfalls erhält die Kreatur +3/+3 bis zum Ende des Zuges. Insatiable Gorgers|Unersättliche Verschlinger|Kreatur — Vampir, Berserker|Die Unersättlichen Verschlinger greifen in jedem Kampf an, falls möglich.\nWahnsinn {3}{R} (Falls du diese Karte abwirfst, wirf sie ins Exil ab. Wenn du dies tust, wirke sie für ihre Wahnsinn-Kosten oder lege sie auf deinen Friedhof.) Insatiable Harpy|Unersättliche Harpyie|Kreatur — Harpyie|Fliegend, Lebensverknüpfung Insatiable Souleater|Unersättlicher Seelenfresser|Artefaktkreatur — Bestie|{G/P}: Der Unersättliche Seelenfresser verursacht bis zum Ende des Zuges Trampelschaden. ({G/P} kann entweder mit {G} oder 2 Lebenspunkten bezahlt werden.) @@ -7946,6 +7970,7 @@ Inspiring Roar|Anspornendes Gebrüll|Hexerei|Lege auf jede Kreatur, die du kontr Inspiring Statuary|Inspirierende Statuen|Artefakt|Nichtartefakt-Zaubersprüche, die du wirkst, haben Improvisieren. (Deine Artefakte können dir helfen, diese Zaubersprüche zu wirken. Mit jedem Artefakt, das du tappst, nachdem du mit dem Aktivieren deiner Manafähigkeiten fertig bist, bezahlst du {1}.) Inspiring Unicorn|Inspirierendes Einhorn|Kreatur — Einhorn|Immer wenn das Inspirierende Einhorn angreift, erhalten Kreaturen, die du kontrollierst, +1/+1 bis zum Ende des Zuges. Inspiring Vantage|Beeindruckendes Panorama|Land|Das Beeindruckende Panorama kommt getappt ins Spiel, es sei denn, du kontrollierst zwei oder weniger andere Länder.\n{T}: Erhöhe deinen Manavorrat um {R} oder {W}. +Inspiring Veteran|Inspirierender Veteran|Kreatur — Mensch, Ritter|Andere Ritter, die du kontrollierst, erhalten +1/+1. Inspirit|Anfeuern|Spontanzauber|Enttappe eine Kreatur deiner Wahl. Sie erhält +2/+4 bis zum Ende des Zuges. Instigator Gang|Aufhetzertrupp|Kreatur — Mensch, Werwolf|Angreifende Kreaturen, die du kontrollierst, erhalten +1/+0.\nTransformiere zu Beginn jedes Versorgungssegments den Aufhetzertrupp, falls im letzten Zug keine Zaubersprüche gewirkt wurden. Instigator|Anstifter|Kreatur — Spruchwandler|{1}{B}{B}, {T}, wirf eine Karte aus Deiner Hand ab: Alle Kreaturen, die ein Spieler Deiner Wahl beherrscht, greifen in diesem Zug an, wenn möglich. @@ -8442,6 +8467,7 @@ Keening Apparition|Klagende Erscheinung|Kreatur — Geist|Opfere die Klagende Er Keening Banshee|Klagende Todesfee|Kreatur — Geist|Fliegend\nWenn die Klagende Todesfee ins Spiel kommt, erhält eine Kreatur deiner Wahl -2/-2 bis zum Ende des Zuges. Keening Stone|Klagender Stein|Artefakt|{5}, {T}: Ein Spieler deiner Wahl legt die obersten X Karten seiner Bibliothek auf seinen Friedhof, wobei X gleich der Anzahl an Karten ist, die sich im Friedhof des Spielers befinden. Keep Watch|Wache halten|Spontanzauber|Ziehe für jede angreifende Kreatur eine Karte. +Keeper of Fables|Hüter der Fabeln|Kreatur — Katze|Immer wenn eine oder mehrere Nicht-Mensch-Kreaturen, die du kontrollierst, einem Spieler Kampfschaden zufügen, ziehe eine Karte. Keeper of Kookus|Hüter von Kookus|Beschwörung eines Goblins|{R}: Schutz vor Rot bis zum Ende des Zuges Keeper of Progenitus|Hüter des Progenitus|Kreatur — Elf, Druide|Immer wenn ein Spieler ein Gebirge, einen Wald oder eine Ebene für Mana tappt, erhöht dieser Spieler seinen Manavorrat um ein zusätzliches Mana eines beliebigen Typs, den dieses Land produziert hat. Keeper of Tresserhorn|Hüter von Tresserhorn|Beschwörung eines Hüters|Wenn der Hüter von Tresserhorn angreift und nicht geblockt wird, fügt er dem verteidigenden Spieler in diesem Zug keinem Schaden zu, und dieser Spieler verliert 2 Lebenspunkte.\nEffekte, die Schaden verhindern oder umleiten, können hier nicht angewendet werden, um den Verlust der Lebenspunkte zu verhindern. @@ -8479,6 +8505,7 @@ Kemba's Legion|Kembas Legion|Kreatur — Katze, Soldat|Wachsamkeit\nKembas Legio Kemba's Skyguard|Kembas Himmelswächter|Kreatur — Katze, Ritter|Fliegend\nWenn Kembas Himmelswächter ins Spiel kommt, erhältst du 2 Lebenspunkte dazu. Kemba, Kha Regent|Kemba, Kha-Herrscherin|Legendäre Kreatur — Katze, Kleriker|Bringe zu Beginn deines Versorgungssegments für jede an Kemba, Kha-Herrscherin angelegte Ausrüstung einen 2/2 weißen Katze-Kreaturenspielstein ins Spiel. Kemuri-Onna|Kemuri-Onna|Kreatur - Geist|Wenn die Kemuri-Onna ins Spiel kommt, wirft ein Spieler deiner Wahl eine Karte aus seiner Hand ab.\nImmer wenn du einen Geist oder einen arkanen Zauber spielst, kannst du Kemuri-Onna auf die Hand ihres Besitzers zurückbringen. +Kenrith's Transformation|Kenriths Verwandlung|Verzauberung — Aura|Verzaubert eine Kreatur\nWenn Kenriths Verwandlung ins Spiel kommt, ziehe eine Karte.\nDie verzauberte Kreatur verliert alle Fähigkeiten und ist eine grüne Hirsch-Kreatur mit Basis-Stärke und -Widerstandskraft 3/3. (Sie verliert alle anderen Karten- und Kreaturentypen.) Kenrith, the Returned King|Kenrith, der rückgekehrte König|Legendäre Kreatur — Mensch, Adliger|{R}: Alle Kreaturen verursachen Trampelschaden und erhalten Eile bis zum Ende des Zuges.\n{1}{G}: Lege eine +1/+1-Marke auf eine Kreatur deiner Wahl.\n{2}{W}: Ein Spieler deiner Wahl erhält 5 Lebenspunkte dazu.\n{3}{U}: Ein Spieler deiner Wahl zieht eine Karte.\n{4}{B}: Bringe eine Kreaturenkarte deiner Wahl aus einem Friedhof unter der Kontrolle ihres Besitzers ins Spiel. Kentaro, the Smiling Cat|Kentaro, die Grinsekatze|Legendäre Kreatur - Mensch, Samurai|Bushido 1 (Wenn diese Karte blockt oder geblockt wird, erhält sie +1/+1 bis zum Ende des Zuges.)\nDu kannst {X} bezahlen, anstatt die Manakosten von Samurai-Zaubersprüchen, die du spielst, zu bezahlen, wobei X den umgewandelten Manakosten des entsprechenden Zaubers entspricht. Keranos, God of Storms|Keranos, Gott der Stürme|Legendäre Verzauberungskreatur — Gott|Unzerstörbar\nSolange deine Hingabe zu Blau und Rot weniger als sieben beträgt, ist Keranos keine Kreatur.\nZeige die erste Karte, die du in jedem Zug ziehst, offen vor. Immer wenn du auf diese Weise eine Länderkarte vorzeigst, ziehe eine Karte. Immer wenn du auf diese Weise eine Karte vorzeigst, die kein Land ist, fügt Keranos einer Kreatur oder einem Spieler deiner Wahl 3 Schadenspunkte zu. @@ -8861,6 +8888,7 @@ Laquatus's Disdain|Laquatus' Hochmut|Spontanzauber|Neutralisiere einen Zauberspr Larceny|Abknöpfen|Verzauberung|Immer wenn eine Kreatur, die Du kontrollierst, einem Spieler Schaden zufügt, wirft dieser Spieler eine Karte aus seiner Hand ab. Larger Than Life|Überlebensgroß|Hexerei|Eine Kreatur deiner Wahl erhält +4/+4 und verursacht Trampelschaden bis zum Ende des Zuges. Lash Out|Auspeitschen|Spontanzauber|Auspeitschen fügt einer Kreatur deiner Wahl 3 Schadenspunkte zu. Befehde dich mit einem Gegner. Falls du die Fehde gewinnst, fügt Auspeitschen dem Beherrscher dieser Kreatur 3 Schadenspunkte zu. (Jeder Spieler in einer Fehde deckt die oberste Karte seiner Bibliothek auf und legt diese Karte dann auf oder unter seine Bibliothek. Ein Spieler gewinnt die Fehde, wenn seine Karte die höheren umgewandelten Manakosten hat.) +Lash of Thorns|Dornenpeitsche|Spontanzauber|Eine Kreatur deiner Wahl erhält +2/+1 und Todesberührung bis zum Ende des Zuges. Lash of the Whip|Peitschenhieb|Spontanzauber|Eine Kreatur deiner Wahl erhält -4/-4 bis zum Ende des Zuges. Lashknife Barrier|Peitschendes Hindernis|Verzauberung|Ziehe eine Karte, wenn das Peitschende Hindernis ins Spiel kommt.\nWenn eine Quelle einer Kreatur, die Du kontrollierst, Schaden zufügen würde, fügt die Quelle der Kreatur stattdessen soviel Schaden weniger 1 zu. Lashknife|Schneidende Peitsche|Kreaturenverzauberung|Wenn Du eine Ebene kontrollierst, kannst Du eine ungetappte Kreatur unter Deiner Kontrolle tappen, anstatt die Manakosten der Schneidenden Peitsche zu bezahlen.\nDie verzauberte Kreatur erhält Erstschlag. @@ -9216,9 +9244,11 @@ Lobber Crew|Schleuderschergen|Kreatur — Goblin, Krieger|Verteidiger\n{T}: Die Lobotomy|Lobotomie|Hexerei|Schaue Dir die Karten auf der Hand eines Spielers Deiner Wahl an und bestimme eine beliebige Karte davon außer einem Standardland. Durchsuche die Hand, den Friedhof und die Bibliothek des Spielers nach allen Kopien der gewählten Karte und entferne diese ganz aus dem Spiel. Der Spieler mischt danach seine Bibliothek neu. Loch Dragon|Seedrache|Kreatur — Drache|Fliegend\nImmer wenn der Seedrache ins Spiel kommt oder angreift, kannst du eine Karte abwerfen. Falls du dies tust, ziehe eine Karte. Loch Korrigan|Seen-Korrigan|Kreatur — Geist|{U/B}: Die Seen-Korrigan erhält +1/+1 bis zum Ende des Zuges. +Lochmere Serpent|Lochmere-Seeschlange|Kreatur — Schlange|Aufblitzen\n{U}, opfere eine Insel: Die Lochmere-Seeschlange kann in diesem Zug nicht geblockt werden.\n{B}, opfere einen Sumpf: Du erhältst 1 Lebenspunkt dazu und ziehst eine Karte.\n{U}{B}: Schicke fünf Karten deiner Wahl aus dem Friedhof eines Gegners ins Exil. Bringe die Lochmere-Seeschlange aus deinem Friedhof auf deine Hand zurück. Aktiviere diese Fähigkeit nur zu einem Zeitpunkt, zu dem du auch eine Hexerei wirken könntest. Locket of Yesterdays|Medaillon des Gestrigen|Artefakt|Zaubersprüche, die du spielst, kosten beim Ausspielen für jede Karte mit demselben Namen in deinem Friedhof {1} weniger. Lockjaw Snapper|Tetanus-Schnapper|Artefaktkreatur — Vogelscheuche|Verdorren (Dies fügt Kreaturen Schaden in Form von -1/-1-Marken zu.)\nWenn der Tetanus-Schnapper aus dem Spiel auf den Friedhof gelegt wird, lege auf jede Kreatur mit mindestens einer -1/-1-Marke eine weitere -1/-1-Marke. Locthwain Gargoyle|Locthwain-Gargoyle|Artefaktkreatur — Gargoyle|{4}: Der Locthwain-Gargoyle erhält +2/+0 und Flugfähigkeit bis zum Ende des Zuges. +Locthwain Paladin|Locthwain-Paladin|Kreatur — Mensch, Ritter|Bedrohlich (Diese Kreatur kann nicht geblockt werden, außer von zwei oder mehr Kreaturen.)\nAdamant — Falls drei oder mehr schwarze Mana ausgegeben wurden, um diesen Zauberspruch zu wirken, kommt der Locthwain-Paladin mit einer +1/+1-Marke ins Spiel. Locust Miser|Heuschreckengeizhals|Kreatur - Ratte, Schamane|Die maximale Handkartenzahl aller Gegner ist um 2 reduziert. Locust Swarm|Heuschreckenschwarm|Beschwörung eines Schwarms|Fliegend\n{G}: Regeneration\n{G}: Enttappe den Heuschrecken-schwarm. Benutze diese Fähigkeit nur einmal pro Zug. Lodestone Bauble|Richtungsweiser|Artefakt|{1}, {T}: Opfere den Richtungsweiser, um bis zu vier Standardländer Deiner Wahl aus dem Friedhof eines beliebigen Spielers auf seine Bibliothek in beliebiger Reihenfolge zu legen.\nDieser Spieler zieht eine Karte zu Beginn der nächsten Versorgungsphase. @@ -9266,6 +9296,7 @@ Lose Hope|Die Hoffnung verlieren|Spontanzauber|Eine Kreatur deiner Wahl erhält Lost Auramancers|Verlorene Auraschöpfer|Kreatur — Mensch, Zauberer|Verschwinden 3 (Diese bleibende Karte kommt mit drei Zeitmarken ins Spiel. Entferne zu Beginn deines Versorgungssegments eine Zeitmarke von ihr. Wenn die letzte Zeitmarke entfernt wird, opfere sie.)\n Wenn die Verlorenen Auraschöpfer aus dem Spiel auf einen Friedhof gelegt werden und falls auf ihnen keine Zeitmarken liegen, kannst du deine Bibliothek nach einer Verzauberungskarte durchsuchen und sie ins Spiel bringen. Falls du dies tust, mische danach deine Bibliothek. Lost Hours|Verlorene Stunden|Hexerei|Ein Spieler deiner Wahl zeigt die Karten auf seiner Hand offen vor. Bestimme davon eine Karte, die kein Land ist. Dieser Spieler legt diese Karte als dritte Karte von oben in seine Bibliothek. Lost Legacy|Verlorenes Vermächtnis|Hexerei|Benenne eine Karte, die weder ein Artefakt noch ein Land ist. Durchsuche den Friedhof, die Hand und die Bibliothek eines Spielers deiner Wahl nach einer beliebigen Anzahl an Karten mit diesem Namen und schicke sie ins Exil. Dieser Spieler mischt seine Bibliothek und zieht dann eine Karte für jede auf diese Weise aus seiner Hand ins Exil geschickte Karte. +Lost Legion|Vergessene Legion|Kreatur — Geist, Ritter|Wenn die Vergessene Legion ins Spiel kommt, wende Hellsicht 2 an. (Schaue dir die obersten zwei Karten deiner Bibliothek an. Du kannst eine beliebige Anzahl davon unter deine Bibliothek legen und den Rest in beliebiger Reihenfolge oben darauf.) Lost Leonin|Verlorener Leonide|Kreatur — Katze, Soldat|Infizieren (Diese Kreatur fügt Schaden in Form von -1/-1-Marken für Kreaturen und von Giftmarken für Spieler zu.) Lost Order of Jarkeld|Jarkelds vergessener Orden|Beschwörung von Rittern|Jarkelds vergessener Orden hat Stärke und Widerstandskraft von 1 plus der Anzahl der Kreaturen, die ein Gegner Deiner Wahl beherrscht. Lost Soul|Verlorene Seele|Beschwörung einer verlorenen Seele|Sumpftarnung @@ -9285,6 +9316,7 @@ Lotus Path Djinn|Lotuspfad-Dschinn|Kreatur — Dschinn, Mönch|Fliegend\nBravour Lotus Petal|Lotusblüte|Artefakt|{T}, opfere die Lotusblüte: Erhöhe Deinen Manavorrat um ein Mana einer beliebigen Farbe. Spiele diese Fähigkeit wie eine Manaquelle. Lotus Vale|Lotustal|Land|Opfere zwei ungetappte Länder, wenn das Lotustal ins Spiel kommt, oder begrabe das Lotustal.\n{T}: Erhöhe Deinen Manavorrat um drei Mana einer beliebigen Farbe. Lotus-Eye Mystics|Lotusblick-Mystiker|Kreatur — Mensch, Mönch|Bravour (Immer wenn du einen Nichtkreatur-Zauberspruch wirkst, erhält diese Kreatur +1/+1 bis zum Ende des Zuges.)\nWenn die Lotusblick-Mystiker ins Spiel kommen, bringe eine Verzauberungskarte deiner Wahl aus deinem Friedhof auf deine Hand zurück. +Lovestruck Beast|Verliebtes Biest|Kreatur — Bestie, Adliger|Das Verliebte Biest kann nicht angreifen, es sei denn, du kontrollierst eine 1/1-Kreatur. Lovisa Coldeyes|Lovisa Coldeyes|Legendäre Kreatur — Mensch, Herrscher|Barbaren, Krieger und Berserker erhalten +2/+2 und haben Eile. Lowland Basilisk|Tiefebenenbasilisk|Beschwörung eines Basilisken|Immer wenn der Tiefebenenbasilisk einer Kreatur Schaden zufügt, zerstöre diese Kreatur am Ende des Zuges. Lowland Giant|Tiefebenenriese|Beschwörung eines Riesen| @@ -9489,6 +9521,7 @@ Malakir Cullblade|Malakir-Keuler|Kreatur — Vampir, Krieger|Immer wenn eine Kre Malakir Familiar|Malakir-Vertrauter|Kreatur — Fledermaus|Fliegend, TodesberührungImmer wenn du Lebenspunkte dazuerhältst, erhält der Malakir-Vertraute +1/+1 bis zum Ende des Zuges. Malakir Soothsayer|Malakir-Wahrsagerin|Kreatur — Vampir, Schamane, Verbündeter|Mitstreiter — {T}, tappe einen ungetappten Verbündeten, den du kontrollierst: Du ziehst eine Karte und verlierst 1 Lebenspunkt. Malevolent Awakening|Böses Erwachen|Verzauberung|{1}{B}{B}, opfere eine Kreatur: Bringe eine Kreaturenkarte deiner Wahl aus deinem Friedhof auf deine Hand zurück. +Malevolent Noble|Heimtückischer Adliger|Kreatur — Mensch, Adliger|{2}, opfere ein Artefakt oder eine andere Kreatur: Lege eine +1/+1-Marke auf den Heimtückischen Adligen. Malevolent Whispers|Übelwollendes Flüstern|Hexerei|Übernimm bis zum Ende des Zuges die Kontrolle über eine Kreatur deiner Wahl. Enttappe die Kreatur. Sie erhält +2/+0 und Eile bis zum Ende des Zuges.\nWahnsinn {3}{R} (Falls du diese Karte abwirfst, wirf sie ins Exil ab. Wenn du dies tust, wirke sie für ihre Wahnsinn-Kosten oder lege sie auf deinen Friedhof.) Malfegor|Malfegor|Legendäre Kreatur — Dämon, Drache|Fliegend\nWenn Malfegor ins Spiel kommt, wirf alle Karten aus deiner Hand ab. Jeder Gegner opfert für jede auf diese Weise abgeworfene Karte eine Kreatur. Malfunction|Fehlfunktion|Verzauberung — Aura|Verzaubert ein Artefakt oder eine Kreatur\nWenn die Fehlfunktion ins Spiel kommt, tappe die verzauberte bleibende Karte.\nDie verzauberte bleibende Karte enttappt nicht während des Enttappsegments ihres Beherrschers. @@ -9564,6 +9597,8 @@ Mantle of Leadership|Mantel der Anführerschaft|Verzauberung — Aura|Aufblitzen Mantle of Tides|Mantel der Gezeiten|Artefakt — Ausrüstung|Die ausgerüstete Kreatur erhält +1/+2.\nImmer wenn du deine zweite Karte innerhalb desselben Zuges ziehst, lege den Mantel der Gezeiten an eine Kreatur deiner Wahl an, die du kontrollierst.\nAusrüsten {3} ({3}: Lege diese Karte an eine Kreatur deiner Wahl an, die du kontrollierst. Spiele Ausrüsten wie eine Hexerei.) Mantle of Webs|Spinnennetz-Umhang|Verzauberung — Aura|Verzaubert eine KreaturDie verzauberte Kreatur erhält +1/+3 und hat Reichweite. (Sie kann fliegende Kreaturen blocken.) Map the Wastes|Vermessung der Ödlande|Hexerei|Durchsuche deine Bibliothek nach einer Standardland-Karte, bringe sie getappt ins Spiel und mische dann deine Bibliothek. Kräftigung 1. (Lege eine +1/+1-Marke auf eine Kreatur mit der geringsten Widerstandskraft unter den Kreaturen, die du kontrollierst.) +Maraleaf Pixie|Maralaub-Fee|Kreatur — Feenwesen|Fliegend\n{T}: Erzeuge {G} oder {U}. +Maraleaf Rider|Maralaub-Reiterin|Kreatur — Elf, Ritter|Opfere eine Speise: Eine Kreatur deiner Wahl blockt die Maralaub-Reiterin in diesem Zug, falls möglich. Maralen of the Mornsong|Maralen vom Morgengesang|Legendäre Kreatur — Elf, Zauberer|Spieler können keine Karten ziehen.\nZu Beginn des Ziehsegments jedes Spielers verliert dieser Spieler 3 Lebenspunkte, durchsucht seine Bibliothek nach einer Karte, nimmt diese auf die Hand und mischt danach seine Bibliothek. Marang River Prowler|Marangfluss-Herumtreiber|Kreatur — Mensch, Räuber|Der Marangfluss-Herumtreiber kann nicht blocken und nicht geblockt werden.\nDu kannst den Marangfluss-Herumtreiber aus deinem Friedhof wirken, solange du eine schwarze oder grüne bleibende Karte kontrollierst. Marang River Skeleton|Marangfluss-Skelett|Kreatur — Skelett|{B}: Regeneriere das Marangfluss-Skelett.\nMegamorph {3}{B} (Du kannst diese Karte verdeckt für {3} als eine 2/2 Kreatur wirken. Decke sie zu einem beliebigen Zeitpunkt für ihre Megamorph-Kosten auf und lege eine +1/+1-Marke auf sie.) @@ -9791,6 +9826,7 @@ Memory Jar|Krug der Erinnerungen|Artefakt|{T}, opfere den Krug der Erinnerungen: Memory Lapse|Gedächtnislücke|Spontanzauber|Neutralisiere einen Zauberspruch Deiner Wahl. Lege ihn oben auf die Bibliothek seines Besitzers statt auf dessen Friedhof. Memory Plunder|Erinnerungsplünderung|Spontanzauber|Du kannst eine Spontanzauber- oder Hexereikarte deiner Wahl aus dem Friedhof eines Gegners spielen, ohne ihre Manakosten zu bezahlen. Memory Sluice|Erinnerungsschleuse|Hexerei|Ein Spieler deiner Wahl legt die obersten vier Karten seiner Bibliothek auf seinen Friedhof.\nVerschwören (Sowie du diesen Zauberspruch spielst, kannst du zwei ungetappte Kreaturen tappen, die du kontrollierst und die mindestens eine Farbe mit dem Zauberspruch gemeinsam haben. Wenn du das tust, kopiere den Zauberspruch; du kannst für die Kopie ein neues Ziel bestimmen.) +Memory Theft|Gedankenraub|Hexerei|Ein Gegner deiner Wahl zeigt die Karten auf seiner Hand offen vor. Du bestimmst davon eine Nichtland-Karte. Der Spieler wirft die bestimmte Karte ab. Du kannst eine Karte mit einem Abenteuer, die der Spieler besitzt, aus dem Exil auf den Friedhof des Spielers legen. Memory's Journey|Gedächtnisreise|Spontanzauber|Ein Spieler deiner Wahl mischt bis zu drei Karten deiner Wahl aus seinem Friedhof in seine Bibliothek.\nRückblende {G} (Du kannst diese Karte aus deinem Friedhof für ihre Rückblendekosten wirken. Schicke sie danach ins Exil.) Memory|Erinnern|Hexerei|Nachhall (Wirke diesen Zauberspruch nur aus deinem Friedhof. Schicke ihn danach ins Exil.)\nJeder Spieler mischt die Karten auf seiner Hand und in seinem Friedhof in seine Bibliothek und zieht dann sieben Karten. Menacing Ogre|Drohender Oger|Kreatur — Oger|Verursacht Trampelschaden, EileWenn der Drohende Oger ins Spiel kommt, bestimmt jeder Spieler geheim eine Zahl.\n Dann werden diese Zahlen aufgedeckt. Alle Spieler mit der höchsten Zahl verlieren ebenso viele Lebenspunkte. Falls du einer dieser Spieler bist, lege zwei +1/+1-Marken auf den Drohenden Oger. @@ -10383,6 +10419,7 @@ Murderous Betrayal|Todbringender Verrat|Verzauberung|{B}{B}, Bezahle die Hälfte Murderous Compulsion|Mörderischer Drang|Hexerei|Zerstöre eine getappte Kreatur deiner Wahl.\nWahnsinn {1}{B} (Falls du diese Karte abwirfst, wirf sie ins Exil ab. Wenn du dies tust, wirke sie für ihre Wahnsinn-Kosten oder lege sie auf deinen Friedhof.) Murderous Cut|Mörderischer Schnitt|Spontanzauber|Wühlen (Mit jeder Karte, die du aus deinem Friedhof ins Exil schickst, während du diesen Zauberspruch wirkst, bezahlst du {1} seiner Kosten.)\nZerstöre eine Kreatur deiner Wahl. Murderous Redcap|Mörderische Blutkappe|Kreatur — Goblin, Assassine|Wenn die Mörderische Blutkappe ins Spiel kommt, fügt sie einer Kreatur oder einem Spieler deiner Wahl Schadenspunkte in Höhe ihrer Stärke zu.\nBeharrlichkeit (Wenn diese Kreatur aus dem Spiel auf einen Friedhof gelegt wird und keine -1/-1-Marke auf ihr lag, bringe sie mit einer -1/-1-Marke unter der Kontrolle ihres Besitzers ins Spiel zurück.) +Murderous Rider|Mörderische Reiterin|Kreatur — Zombie, Ritter|Lebensverknüpfung\nWenn die Mörderische Reiterin stirbt, lege sie unter die Bibliothek ihres Besitzers. Murderous Spoils|Mörderische Ausbeute|Spontanzauber|Zerstöre eine nichtschwarze Kreatur deiner Wahl. Sie kann nicht regeneriert werden. Du erhältst die Kontrolle über alle Ausrüstung, die an sie angelegt war. (Dieser Effekt endet nicht am Ende des Zuges.) Murder|Mord|Spontanzauber|Zerstöre eine Kreatur deiner Wahl. Murk Dwellers|Bewohner der Dunkelheit|Beschwörung von dunklen Wesen|Greifen die Bewohner der Dunkelheit an und werden nicht geblockt, erhalten sie +2/+0 bis zum Ende des Kampfes @@ -10922,9 +10959,11 @@ Nyxborn Wolf|Nyxgeborene Wölfin|Verzauberungskreatur — Wolf|Göttergabe {4}{G O-Kagachi, Vengeful Kami|O-Kagachi, rachsüchtiger Kami|Legendäre Kreatur — Drache, Geist|Fliegend, verursacht Trampelschaden\nImmer wenn O-Kagachi, rachsüchtiger Kami, einem Spieler Kampfschaden zufügt und falls der Spieler dich während seines letzten Zuges angegriffen hat, schicke eine bleibende Karte, die kein Land ist und die der Spieler kontrolliert, ins Exil. O-Naginata|O-Naginata|Artefakt - Ausrüstung|O-Naginata kann nur an eine Kreatur mit Stärke 3 oder mehr angelegt werden.\nDie ausgerüstete Kreatur erhält +3/+0 und verursacht Trampelschaden.\nAusrüsten {2} ({2}: Lege diese Karte an eine Kreatur deiner Wahl an, die du kontrollierst. Spiele Ausrüsten wie eine Hexerei.) Oak Street Innkeeper|Wirtin aus der Eichenstraße|Kreatur — Elf|So lange es nicht dein Zug ist, sind getappte Kreaturen, die du kontrollierst, fluchsicher. +Oaken Boon|Eichensegen|Hexerei — Abenteuer|Lege zwei +1/+1-Marken auf eine Kreatur deiner Wahl. (Schicke diese Karte dann ins Exil. Du kannst sie später als Kreatur aus dem Exil wirken.) Oaken Brawler|Eichenraufbold|Kreatur — Baumhirte, Krieger|Wenn der Eichenraufbold ins Spiel kommt, befehde dich mit einem Gegner. Falls du die Fehde gewinnst, lege eine +1/+1-Marke auf den Eichenraufbold. (Jeder Spieler in einer Fehde deckt die oberste Karte seiner Bibliothek auf und legt diese Karte dann auf oder unter seine Bibliothek. Ein Spieler gewinnt die Fehde, wenn seine Karte die höheren umgewandelten Manakosten hat.) Oakenform|Eichengestalt|Verzauberung — Aura|Kreaturenverzauberung\nDie verzauberte Kreatur erhält +3/+3. Oakgnarl Warrior|Krieger der knorrigen Eichen|Kreatur — Baumhirte, Krieger|Wachsamkeit, verursacht Trampelschaden +Oakhame Adversary|Eichenheim-Widersacher|Kreatur — Elf, Krieger|Dieser Zauberspruch kostet beim Wirken {2} weniger, falls ein Gegner eine grüne bleibende Karte kontrolliert.\nTodesberührung\nImmer wenn der Eichenheim-Widersacher einem Spieler Kampfschaden zufügt, ziehe eine Karte. Oakhame Ranger|Eichenheim-Waldläuferin|Kreatur — Elf, Ritter|{T}: Kreaturen, die du kontrollierst, erhalten +1/+1 bis zum Ende des Zuges. Oakheart Dryads|Eichenherz-Dryaden|Verzauberungskreatur — Nymphe, Dryade|Konstellation — Immer wenn die Eichenherz-Dryaden oder eine andere Verzauberung unter deiner Kontrolle ins Spiel kommt, erhält eine Kreatur deiner Wahl +1/+1 bis zum Ende des Zuges. Oashra Cultivator|Oashra-Ackerbäuerin|Kreatur — Mensch, Druide|{2}{G}, {T}, opfere die Oashra-Ackerbäuerin: Durchsuche deine Bibliothek nach einer Standardland-Karte, bringe sie getappt ins Spiel und mische dann deine Bibliothek. @@ -10947,6 +10986,7 @@ Oath of Teferi|Teferis Eid|Legendäre Verzauberung|Wenn Teferis Eid ins Spiel ko Oath of the Ancient Wood|Eid des uralten Waldes|Verzauberung|Immer wenn der Eid des uralten Waldes oder eine andere Verzauberung unter deiner Kontrolle ins Spiel kommt, kannst du eine +1/+1-Marke auf eine Kreatur deiner Wahl legen. Oathkeeper, Takeno's Daisho|Eidbewahrer, Takenos Daisho|Legendäres Artefakt - Ausrüstung|Die ausgerüstete Kreatur erhält +3/+1.\nImmer wenn die ausgerüstete Kreatur aus dem Spiel auf einen Friedhof gelegt wird, bringe diese Karte unter deiner Kontrolle zurück ins Spiel falls es ein Samurai ist.\nWenn Eidbewahrer, Takenos Daisho, aus dem Spiel auf einen Friedhof gelegt wird, entferne die ausgerüstete Kreatur ganz aus dem Spiel.\nAusrüsten {2} Oathsworn Giant|Eidgebundener Riese|Kreatur — Riese, Soldat|Wachsamkeit\nAndere Kreaturen, die du kontrollierst, erhalten +0/+2 und haben Wachsamkeit. +Oathsworn Knight|Eidgebundener Ritter|Kreatur — Mensch, Ritter|Der Eidgebundene Ritter kommt mit vier +1/+1-Marken ins Spiel.\nDer Eidgebundene Ritter greift in jedem Kampf an, falls möglich.\nFalls dem Eidgebundenen Ritter Schaden zugefügt würde, während eine +1/+1-Marke auf ihm liegt, verhindere den Schaden und entferne eine +1/+1-Marke von ihm. Oathsworn Vampire|Eidgebundener Vampir|Kreatur — Vampir, Ritter|Der Eidgebundene Vampir kommt getappt ins Spiel.\nDu kannst den Eidgebundenen Vampir aus deinem Friedhof wirken, falls du in diesem Zug Lebenspunkte dazuerhalten hast. Ob Nixilis Reignited|Ob Nixilis der Wiederentflammte|Legendärer Planeswalker — Nixilis|+1: Du ziehst eine Karte und verlierst 1 Lebenspunkt.\n−3: Zerstöre eine Kreatur deiner Wahl.\n−8: Ein Gegner deiner Wahl erhält ein Emblem mit „Immer wenn ein Spieler eine Karte zieht, verlierst du 2 Lebenspunkte." Ob Nixilis of the Black Oath|Ob Nixilis des schwarzen Schwurs|Planeswalker — Nixilis|+2: Jeder Gegner verliert 1 Lebenspunkt. Du erhältst so viele Lebenspunkte dazu, wie auf diese Weise Lebenspunkte verloren wurden.\n−2: Bringe einen 5/5 schwarzen Dämon-Kreaturenspielstein mit Flugfähigkeit ins Spiel. Du verlierst 2 Lebenspunkte.\n−8: Du erhältst ein Emblem mit „{1}{B}, opfere eine Kreatur: Du erhältst X Lebenspunkte dazu und ziehst X Karten, wobei X gleich der Stärke der geopferten Kreatur ist."\nOb Nixilis des schwarzen Schwurs kann dein Kommandeur sein. @@ -11043,6 +11083,7 @@ Okina, Temple to the Grandfathers|Okina, Tempel der Großväter|Legendäres Land Okk|Okk|Beschwörung eines Goblins|Der Okk kann nur angreifen, wenn eine Kreatur mit größerer Stärke ebenfalls angreift.\nDer Okk kann nur blocken, wenn eine Kreatur mit größerer Stärke ebenfalls blockt. Oko's Accomplices|Okos Komplizen|Kreatur — Feenwesen|Fliegend Oko's Hospitality|Okos Gastfreundschaft|Spontanzauber|Kreaturen, die du kontrollierst, haben Basis-Stärke und -Widerstandskraft 3/3 bis zum Ende des Zuges. Du kannst deine Bibliothek und/oder deinen Friedhof nach einer Karte namens Oko der Trickser durchsuchen, sie offen vorzeigen und auf deine Hand nehmen. Falls du auf diese Weise deine Bibliothek durchsuchst, mische sie danach. +Oko, Thief of Crowns|Oko, Dieb der Kronen|Legendärer Planeswalker — Oko|+2: Erzeuge einen Speise-Spielstein.\n+1: Ein Artefakt oder eine Kreatur deiner Wahl verliert alle Fähigkeiten und wird eine grüne Hirsch-Kreatur mit Basis-Stärke und -Widerstandskraft 3/3.\n−5: Tausche die Kontrolle über ein Artefakt oder eine Kreatur deiner Wahl, das bzw. die du kontrollierst, und eine Kreatur deiner Wahl mit Stärke 3 oder weniger, die ein Gegner kontrolliert. Oko, the Trickster|Oko der Trickser|Legendärer Planeswalker — Oko|+1: Lege zwei +1/+1-Marken auf bis zu eine Kreatur deiner Wahl, die du kontrollierst.\n0: Oko der Trickser wird bis zum Ende des Zuges zu einer Kopie einer Kreatur deiner Wahl, die du kontrollierst. Verhindere allen Schaden, der ihm in diesem Zug zugefügt würde.\n-7: Bis zum Ende des Zuges hat jede Kreatur, die du kontrollierst, Basis-Stärke und -Widerstandskraft 10/10 und verursacht Trampelschaden. Old Ghastbark|Alte Schauderborke|Kreatur — Baumhirte, Krieger| Old-Growth Dryads|Altholz-Dryaden|Kreatur — Dryade|Wenn die Altholz-Dryaden ins Spiel kommen, kann jeder Gegner seine Bibliothek nach einer Standardland-Karte durchsuchen, diese getappt ins Spiel bringen und dann seine Bibliothek mischen. @@ -11068,6 +11109,8 @@ On Serra's Wings|Auf Serras Schwingen|Legendäre Verzauberung — Aura|Verzauber On Thin Ice|Auf dünnem Eis|Verschneite Verzauberung — Aura|Verzaubert ein verschneites Land, das du kontrollierst\nWenn Auf dünnem Eis ins Spiel kommt, schicke eine Kreatur deiner Wahl, die ein Gegner kontrolliert, ins Exil, bis Auf dünnem Eis das Spiel verlässt. Onakke Catacomb|Die Katakomben von Onakke|Welt — Shandalar|Alle Kreaturen sind schwarz und haben Todesberührung.\nImmer wenn du chaos würfelst, erhalten bis zum Ende des Zuges Kreaturen, die du kontrollierst, +1/+0 und Erstschlag. Onakke Ogre|Onakke-Oger|Kreatur — Oger, Krieger| +Once Upon a Time|Es war einmal|Spontanzauber|Falls dieser Zauberspruch der erste Zauberspruch ist, den du in dieser Partie wirkst, kannst du ihn wirken, ohne seine Manakosten zu bezahlen.\nSchaue dir die obersten fünf Karten deiner Bibliothek an. Du kannst davon eine Kreaturen- oder Länderkarte offen vorzeigen und auf deine Hand nehmen. Lege den Rest in zufälliger Reihenfolge unter deine Bibliothek. +Once and Future|Einstig und zukünftig|Spontanzauber|Bringe eine Karte deiner Wahl aus deinem Friedhof auf deine Hand zurück. Lege bis zu eine andere Karte deiner Wahl aus deinem Friedhof oben auf deine Bibliothek. Schicke Einstig und zukünftig ins Exil.\nAdamant — Falls drei oder mehr grüne Mana ausgegeben wurden, um diesen Zauberspruch zu wirken, bringe die Karten stattdessen auf deine Hand zurück und schicke Einstig und zukünftig ins Exil. Ondu Champion|Ondu-Champion|Kreatur — Minotaurus, Krieger, Verbündeter|Zusammenkunft — Immer wenn der Ondu-Champion oder ein anderer Verbündeter unter deiner Kontrolle ins Spiel kommt, verursachen Kreaturen, die du kontrollierst, bis zum Ende des Zuges Trampelschaden. Ondu Cleric|Ondu-Kleriker|Kreatur — Kor, Kleriker, Verbündeter|Immer wenn der Ondu-Kleriker oder ein anderer Verbündeter unter deiner Kontrolle ins Spiel kommt, kannst du soviele Lebenspunkte dazuerhalten, wie du Verbündete kontrollierst. Ondu Giant|Ondu-Riese|Kreatur — Riese, Druide|Wenn der Ondu-Riese ins Spiel kommt, kannst du deine Bibliothek nach einer Standardland-Karte durchsuchen, diese getappt ins Spiel bringen und dann deine Bibliothek mischen. @@ -11178,6 +11221,7 @@ Ordeal of Heliod|Prüfung des Heliod|Verzauberung — Aura|Verzaubert eine Kreat Ordeal of Nylea|Prüfung der Nylea|Verzauberung — Aura|Verzaubert eine Kreatur\nImmer wenn die verzauberte Kreatur angreift, lege eine +1/+1-Marke auf sie. Falls dann drei oder mehr +1/+1-Marken auf ihr liegen, opfere die Prüfung der Nylea.\nWenn du die Prüfung der Nylea opferst, durchsuche deine Bibliothek nach bis zu zwei Standardland-Karten, bringe diese getappt ins Spiel und mische dann deine Bibliothek. Ordeal of Purphoros|Prüfung des Purphoros|Verzauberung — Aura|Verzaubert eine Kreatur\nImmer wenn die verzauberte Kreatur angreift, lege eine +1/+1-Marke auf sie. Falls dann drei oder mehr +1/+1-Marken auf ihr liegen, opfere die Prüfung des Purphoros.\nWenn du die Prüfung des Purphoros opferst, fügt sie einer Kreatur oder einem Spieler deiner Wahl 3 Schadenspunkte zu. Ordeal of Thassa|Prüfung der Thassa|Verzauberung — Aura|Verzaubert eine Kreatur\nImmer wenn die verzauberte Kreatur angreift, lege eine +1/+1-Marke auf sie. Falls dann drei oder mehr +1/+1-Marken auf ihr liegen, opfere die Prüfung der Thassa.\nWenn du die Prüfung der Thassa opferst, ziehe zwei Karten. +Order of Midnight|Mitternachtsorden|Kreatur — Mensch, Ritter|Fliegend\nDer Mitternachtsorden kann nicht blocken. Order of Succession|Nachfolgeregelung|Hexerei|Bestimme Links oder Rechts. Beginnend mit dir und fortfahrend in der bestimmten Richtung bestimmt jeder Spieler eine Kreatur, die von dem jeweils nächsten Spieler in dieser Richtung kontrolliert wird. Jeder Spieler übernimmt die Kontrolle über die Kreatur, die er bestimmt hat. Order of Whiteclay|Orden des Weißlehms|Kreatur — Kithkin, Kleriker|{1}{W}{W}, {Q}: Bringe eine Kreaturenkarte deiner Wahl mit umgewandelten Manakosten von 3 oder weniger aus deinem Friedhof ins Spiel zurück. ({Q} ist das Enttappsymbol.) Order of Yawgmoth|Ordensritter des Yawgmoth|Beschwörung eines Ritters|Der Ordensritter des Yawgmoth kann nur von schwarzen Kreaturen oder Artefaktkreaturen geblockt werden.\nImmer wenn der Ordensritter des Yawgmoth einem Spieler erfolgreich Schaden zufügt, bestimmt dieser Spieler eine Karte aus seiner Hand und wirft diese ab. @@ -11248,7 +11292,9 @@ Outbreak|Seuchenausbruch|Hexerei|Du kannst einen Sumpf aus Deiner Hand abwerfen, Outflank|Flankenangriff|Spontanzauber|Der Flankenangriff fügt einer angreifenden oder blockenden Kreatur deiner Wahl so viele Schadenspunkte zu, wie du Kreaturen kontrollierst. Outland Boar|Hinterland-Wildschwein|Kreatur — Wildschwein|Das Hinterland-Wildschwein kann von Kreaturen mit Stärke 2 oder weniger nicht geblockt werden. Outland Colossus|Hinterland-Koloss|Kreatur — Riese|Ruhm 6 (Wenn diese Kreatur einem Spieler Kampfschaden zufügt und falls sie nicht ruhmvoll ist, lege sechs +1/+1-Marken auf sie und sie wird ruhmvoll.)Der Hinterland-Koloss kann nicht von mehr als einer Kreatur geblockt werden. +Outlaws' Merriment|Vergnügung der Geächteten|Verzauberung|Zu Beginn deines Versorgungssegments erzeugst du einen roten und weißen Kreaturenspielstein und bestimmst für ihn per Zufall eines der folgenden Sets an Eigenschaften.\n• 3/1 Mensch-Krieger mit Eile, der Trampelschaden verursacht.\n• 2/1 Mensch-Kleriker mit Eile und Lebensverknüpfung.\n• 1/2 Mensch-Räuber mit Eile und „Wenn diese Kreatur ins Spiel kommt, fügt sie einem Ziel deiner Wahl 1 Schadenspunkt zu." Outmaneuver|Ausmanövrieren|Spontanzauber|X geblockte Kreaturen Deiner Wahl fügen in diesem Zug ihren Kampfschaden dem verteidigenden Spieler statt den blockenden Kreaturen zu. +Outmuscle|Niederringen|Hexerei|Lege eine +1/+1-Marke auf eine Kreatur deiner Wahl, die du kontrollierst. Dann kämpft sie gegen eine Kreatur deiner Wahl, die du nicht kontrollierst. (Jede der Kreaturen fügt der anderen Schadenspunkte in Höhe ihrer Stärke zu.)\nAdamant — Falls drei oder mehr grüne Mana ausgegeben wurden, um diesen Zauberspruch zu wirken, erhält die Kreatur, die du kontrollierst, Unzerstörbarkeit bis zum Ende des Zuges. Outnumber|Zahlenmäßige Überlegenheit|Spontanzauber|Zahlenmäßige Überlegenheit fügt einer Kreatur deiner Wahl so viele Schadenspunkte zu, wie du Kreaturen kontrollierst. Outpost Siege|Belagerung des Außenpostens|Verzauberung|Sowie Belagerung des Außenpostens ins Spiel kommt, wähle Khane oder Drachen.\n• Khane — Schicke zu Beginn deines Versorgungssegments die oberste Karte deiner Bibliothek ins Exil. Bis zum Ende des Zuges kannst du die Karte spielen.\n• Drachen — Immer wenn eine Kreatur, die du kontrollierst, das Spiel verlässt, fügt Belagerung des Außenpostens einer Kreatur oder einem Spieler deiner Wahl 1 Schadenspunkt zu. Outrage Shaman|Gewalttätiger Schamane|Kreatur — Goblin, Schamane|Farbwert Wenn der Gewalttätige Schamane ins Spiel kommt, fügt er einer Kreatur deiner Wahl so viele Schadenspunkte zu, wie die Anzahl an roten Manasymbolen in den Manakosten von bleibenden Karten beträgt, die du kontrollierst. @@ -11989,6 +12035,7 @@ Prodigal Pyromancer|Verschwenderischer Feuerkundler|Kreatur — Mensch, Zauberer Prodigal Sorcerer|Abtrünniger Zauberer|Beschwörung eines Zauberers|{T}: Der Abtrünnige Zauberer fügt einer Kreatur oder einem Spieler Deiner Wahl 1 Schadenspunkt zu. Prodigious Growth|Außerordentliches Wachstum|Verzauberung — Aura|Verzaubert eine Kreatur\nDie verzauberte Kreatur erhält +7/+7 und verursacht Trampelschaden. Profane Command|Gottloser Befehl|Hexerei|Bestimme zwei Ein Spieler deiner Wahl verliert X Lebenspunkte; oder bringe eine Kreaturenkarte deiner Wahl mit umgewandelten Manakosten von X oder weniger aus deinem Friedhof ins Spiel; oder eine Kreatur deiner Wahl erhält -X/-X bis zum Ende des Zuges; oder bis zu X Kreaturen deiner Wahl verursachen Furcht bis zum Ende des Zuges. +Profane Insight|Profane Einsicht|Spontanzauber — Abenteuer|Du ziehst eine Karte und verlierst 1 Lebenspunkt. (Schicke diese Karte dann ins Exil. Du kannst sie später als Kreatur aus dem Exil wirken.) Profane Memento|Profanes Andenken|Artefakt|Immer wenn eine Kreaturenkarte von irgendwoher auf den Friedhof eines Gegners gelegt wird, erhältst du 1 Lebenspunkt dazu. Profane Prayers|Gottlose Gebete|Hexerei|Die Gottlosen Gebete fügen einer Kreatur oder einem Spieler deiner Wahl X Schadenspunkte zu und du erhältst X Lebenspunkte dazu, wobei X gleich der Anzahl an Klerikern im Spiel ist. Profane Procession|Unheilige Prozession|Legendäre Verzauberung|{3}{W}{B}: Schicke eine Kreatur deiner Wahl ins Exil. Falls dann drei oder mehr Karten im Exil sind, die mit der Unheiligen Prozession ins Exil geschickt wurden, transformiere sie. @@ -12207,6 +12254,7 @@ Quest for the Goblin Lord|Suche nach dem Goblinherrscher|Verzauberung|Immer wenn Quest for the Gravelord|Suche nach dem Fürst der Gräber|Verzauberung|Immer wenn eine Kreatur aus dem Spiel auf den Friedhof gelegt wird, kannst du eine Quest-Marke auf die Suche nach dem Fürst der Gräber legen.\nEntferne drei Quest-Marken von der Suche nach dem Fürst der Gräber und opfere sie: Bringe einen 5/5 schwarzen (Zombie, Riese)-Kreaturenspielstein ins Spiel. Quest for the Holy Relic|Suche nach der heiligen Reliquie|Verzauberung|Immer wenn du einen Kreaturenzauber wirkst, kannst du eine Quest-Marke auf die Suche nach der heiligen Reliquie legen.\nEntferne fünf Quest-Marken von der Suche nach der heiligen Reliquie und opfere sie: Durchsuche deine Bibliothek nach einer Ausrüstungskarte, bringe sie ins Spiel und lege sie an eine Kreatur an, die du kontrollierst. Mische danach deine Bibliothek. Quest for the Nihil Stone|Suche nach dem Stein Nihil|Verzauberung|Immer wenn ein Gegner eine Karte aus der Hand abwirft, kannst du eine Quest-Marke auf die Suche nach dem Stein Nihil legen.\nFalls zu Beginn des Versorgungssegments eines Gegners dieser Spieler keine Karten auf der Hand hat und auf der Suche nach dem Stein Nihil zwei oder mehr Quest-Marken liegen, kannst du diesen Spieler 5 Lebenspunkte verlieren lassen. +Questing Beast|Das Questentier|Legendäre Kreatur — Bestie|Wachsamkeit, Todesberührung, Eile\nDas Questentier kann von Kreaturen mit Stärke 2 oder weniger nicht geblockt werden.\nKampfschaden, den Kreaturen, die du kontrollierst, zufügen würden, kann nicht verhindert werden.\nImmer wenn Das Questentier einem Gegner Kampfschaden zufügt, fügt es einem Planeswalker deiner Wahl, den jener Spieler kontrolliert, ebenso viele Schadenspunkte zu. Questing Phelddagrif|Suchender Phelddagrif|Kreatur — Phelddagrif|{G}: Der Suchende Phelddagrif erhält +1/+1 bis zum Ende des Zuges. Ein Gegner Deiner Wahl bringt einen 1/1 grünen Flußpferd-Spielstein ins Spiel.\n{W}: Der Suchende Phelddagrif erhält Schutz vor Schwarz und Rot bis zum Ende des Zuges. Ein Gegner Deiner Wahl erhält 2 Lebenspunkte dazu.\n{U}: Der Suchende Phelddagrif erhält Flugfähigkeit bis zum Ende des Zuges. Ein Gegner Deiner Wahl darf eine Karte ziehen. Quick Sliver|Schneller Remasuri|Kreatur — Remasuri|Du kannst den Schnellen Remasuri zu jedem Zeitpunkt spielen, zu dem du einen Spontanzauber spielen könntest.\nJeder Spieler kann Remasurikarten zu jedem Zeitpunkt spielen, zu dem er einen Spontanzauber spielen könnte. Quickchange|Schnellwechsel|Spontanzauber|Die Farbe einer Kreatur deiner Wahl wird bis zum Ende des Zuges zu einer oder mehreren Farben, die du bestimmst.\nZiehe eine Karte. @@ -12798,6 +12846,7 @@ Retrofitter Foundry|Umgießerei|Artefakt|{3}: Enttappe die Umgießerei.\n{2}, {T Retromancer|Retroshino|Beschwörung eines Viashinos|Wenn der Retroshino Ziel eines Zauberspruchs oder einer Fähigkeit ist, fügt er dem Beherrscher dieses Zauberspruchs oder der Fähigkeit 3 Schadenspunkte zu. Return from Extinction|Vorm Aussterben bewahren|Hexerei|Bestimme eines —\n• Bringe eine Kreaturenkarte deiner Wahl aus deinem Friedhof auf deine Hand zurück.\n• Bringe zwei Kreaturenkarten deiner Wahl, die einen Kreaturentyp gemeinsam haben, aus deinem Friedhof auf deine Hand zurück. Return of the Nightstalkers|Rückkehr der Nachtschrate|Hexerei|Bringe alle Nachtschratkarten aus Deinem Friedhof direkt ins Spiel. Zerstöre dann alle Deine Sümpfe (behandle diese Nachtschrate, als ob Du sie gerade von Deiner Hand gesprochen hättest). +Return of the Wildspeaker|Rückkehr des Wildsprechers|Spontanzauber|Bestimme eines —\n• Ziehe so viele Karten, wie die höchste Stärke unter den Nicht-Mensch-Kreaturen, die du kontrollierst, beträgt.\n• Nicht-Mensch-Kreaturen, die du kontrollierst, erhalten +3/+3 bis zum Ende des Zuges. Return to Dust|Zu Staub zurückkehren|Spontanzauber|Entferne eine Artefakt oder eine Verzauberung deiner Wahl ganz aus dem Spiel. Hast du diesen Zauberspruch während deiner Hauptphase gespielt, kannst du bis zu einem weiteren Artefakt oder einer weiteren Verzauberung deiner Wahl ganz aus dem Spiel entfernen. Return to Nature|Rückkehr zur Natur|Spontanzauber|Bestimme eines —\n• Zerstöre ein Artefakt deiner Wahl.\n• Zerstöre eine Verzauberung deiner Wahl.\n• Schicke eine Karte deiner Wahl aus einem Friedhof ins Exil. Return to the Earth|Zurück zur Erde|Spontanzauber|Zerstöre ein Artefakt, eine Verzauberung oder eine Kreatur mit Flugfähigkeit deiner Wahl. @@ -13117,6 +13166,8 @@ Rootwater Shaman|Schamane im Wurzelwasser|Beschwörung von Meervolk|Du kannst Kr Rootwater Thief|Wurzelwasserdieb|Kreatur — Meervolk|{U}: Der Wurzelwasserdieb erhält Flugfähigkeit bis zum Ende des Zuges.\nImmer wenn der Wurzelwasserdieb einem Spieler Kampfschaden zufügt, kannst Du 2 bezahlen. Wenn Du dies tust, durchsuche die Bibliothek dieses Spielers nach einer Karte und entferne diese Karte ganz aus dem Spiel, danach mischt der Spieler seine Bibliothek. Rorix Bladewing|Rorix Bladewing|Kreatur — Drache, Legende|Fliegend, Eile Rosemane Centaur|Rosenmähnen-Zentaur|Kreatur — Zentaur, Soldat|Einberufen (Deine Kreaturen können dir helfen, diesen Zauberspruch zu wirken. Mit jeder Kreatur, die du tappst, während du diesen Zauberspruch wirkst, bezahlst du für {1} oder ein Mana der Farbe jener Kreatur.)\nWachsamkeit +Rosethorn Acolyte|Rosendorn-Tempeldienerin|Kreatur — Elf, Druide|{T}: Erzeuge ein Mana einer beliebigen Farbe. +Rosethorn Halberd|Rosendorn-Hellebarde|Artefakt — Ausrüstung|Wenn die Rosendorn-Hellebarde ins Spiel kommt, lege sie an eine Nicht-Mensch-Kreatur deiner Wahl an, die du kontrollierst.\nDie ausgerüstete Kreatur erhält +2/+1.\nAusrüsten {5} ({5}: Lege diese Karte an eine Kreatur deiner Wahl an, die du kontrollierst. Spiele Ausrüsten wie eine Hexerei.) Rosheen Meanderer|Rosheen Mäanderer|Legendäre Kreatur — Riese, Schamane|{T}: Erhöhe deinen Manavorrat um {4}. Verwende dieses Mana nur für Kosten, die {X} enthalten. Rot Farm Skeleton|Skelett der Verrottungsfarm|Kreatur — Pflanze, Skelett|Das Skelett der Verrottungsfarm kann nicht blocken.\n{2}{B}{G}, lege die obersten vier Karten deiner Bibliothek auf deinen Friedhof: Bringe das Skelett der Verrottungsfarm aus deinem Friedhof ins Spiel zurück. Aktiviere diese Fähigkeit nur zu einem Zeitpunkt, zu dem du auch eine Hexerei wirken könntest. Rot Shambler|Fäulnisschlurfer|Kreatur — Pilzwesen|Immer wenn eine andere Kreatur, die du kontrollierst, stirbt, lege eine +1/+1-Marke auf den Fäulnisschlurfer. @@ -13745,6 +13796,7 @@ Seaside Citadel|Seeküstenzitadelle|Land|Die Seeküstenzitadelle kommt getappt i Seaside Haven|Küsten-Zuflucht|Land|{T}: Erhöhe deinen Manavorrat um ein farbloses Mana.\n{W}{U}, {T}, opfere einen Vogel: Ziehe eine Karte. Seasinger|Sirene|Beschwörung von Meervolk|Begrabe die Sirene, wenn Du keine Inseln kontrollierst.\nDu kannst wählen, ob Du die Sirene während Deiner Enttap-Phase enttappst oder nicht.\n{T}: Übernimm die Kontrolle über eine Kreatur Deiner Wahl, wenn der Beherrscher dieser Kreatur mindestens eine Insel kontrolliert. Du verlierst die Kontrolle über diese Kreatur, wenn die Sirene enttappt wird oder Du die Kontrolle über die Sirene verlierst. Season of Growth|Zeit des Wachstums|Verzauberung|Immer wenn eine Kreatur unter deiner Kontrolle ins Spiel kommt, wende Hellsicht 1 an. (Schaue dir die oberste Karte deiner Bibliothek an. Du kannst sie unter deine Bibliothek legen.)\nImmer wenn du einen Zauberspruch wirkst, der eine Kreatur, die du kontrollierst, als Ziel hat, ziehe eine Karte. +Seasonal Ritual|Jahreszeiten-Ritual|Hexerei — Abenteuer|Erzeuge ein Mana einer beliebigen Farbe. (Schicke diese Karte dann ins Exil. Du kannst sie später als Kreatur aus dem Exil wirken.) Seasoned Marshal|Erfahrener Marschall|Beschwörung eines Soldaten|Immer wenn der Erfahrene Marschall angreift, kannst Du eine Kreatur Deiner Wahl tappen. Seasoned Pyromancer|Erfahrener Pyromagier|Kreatur — Mensch, Schamane|Wenn der Erfahrene Pyromagier ins Spiel kommt, wirf zwei Karten ab und ziehe dann zwei Karten. Erzeuge für jede auf diese Weise abgeworfene Nichtland-Karte einen 1/1 roten Elementarwesen-Kreaturenspielstein.\n{3}{R}{R}, schicke den Erfahrenen Pyromagier aus deinem Friedhof ins Exil: Erzeuge zwei 1/1 rote Elementarwesen-Kreaturenspielsteine. Seasoned Tactician|Trickreicher Taktiker|Beschwörung eines Taktikers|{3}: Entferne die obersten vier Karten Deiner Bibliothek aus dem Spiel, um allen Schaden zu verhindern, der Dir aus einer Quelle zugefügt wird. @@ -14095,6 +14147,7 @@ Shield of the Avatar|Schild des Avatars|Artefakt — Ausrüstung|Falls eine Quel Shield of the Oversoul|Schild der Überseele|Verzauberung — Aura|Kreaturenverzauberung\nSolange die verzauberte Kreatur grün ist, erhält sie +1/+1 und ist unzerstörbar. (Tödlicher Schaden und Effekte, die sie „zerstören", zerstören sie nicht. Beträgt ihre Widerstandskraft 0 oder weniger, wird sie weiterhin auf den Friedhof ihres Besitzers gelegt.)\nSolange die verzauberte Kreatur weiß ist, erhält sie +1/+1 und hat Flugfähigkeit. Shield of the Realm|Schild des Reiches|Artefakt — Ausrüstung|Falls eine Quelle der ausgerüsteten Kreatur Schaden zufügen würde, verhindere 2 dieser Schadenspunkte.\nAusrüsten {1} Shield of the Righteous|Schild der Gerechten|Artefakt — Ausrüstung|Die ausgerüstete Kreatur erhält +0/+2 und Wachsamkeit.\nImmer wenn die ausgerüstete Kreatur eine Kreatur blockt, enttappt diese Kreatur nicht während des nächsten Enttappsegments ihres Beherrschers.\nAusrüsten {2} +Shield's Might|Macht des Schilds|Spontanzauber — Abenteuer|Eine Kreatur deiner Wahl erhält +2/+2 bis zum Ende des Zuges. (Schicke diese Karte dann ins Exil. Du kannst sie später als Kreatur aus dem Exil wirken.) Shielded Aether Thief|Abgeschirmter Ätherdieb|Kreatur — Vedalken, Räuber|Aufblitzen (Du kannst diesen Zauberspruch zu jedem Zeitpunkt wirken, zu dem du einen Spontanzauber wirken könntest.)\nImmer wenn der Abgeschirmte Ätherdieb blockt, erhältst du {E} (eine Energiemarke).\n{T}, bezahle {E}{E}{E}: Ziehe eine Karte. Shielded Passage|Beschützter Durchgang|Spontanzauber|Verhindere allen Schaden, der in diesem Zug einer Kreatur deiner Wahl zugefügt würde. Shielded by Faith|Schutz des Glaubens|Verzauberung — Aura|Verzaubert eine KreaturDie verzauberte Kreatur hat Unzerstörbarkeit.Immer wenn eine Kreatur ins Spiel kommt, kannst du den Schutz des Glaubens an diese Kreatur anlegen. @@ -15162,7 +15215,7 @@ Spore Burst|Sporenausbruch|Hexerei|Domäne Bringe für jeden Standardlandtyp unt Spore Frog|Sporenfrosch|Kreatur — Frosch|Opfere den Sporenfrosch: Verhindere allen Kampfschaden, der in diesem Zug zugefügt würde. Spore Swarm|Sporenschwarm|Spontanzauber|Erzeuge drei 1/1 grüne Saproling-Kreaturenspielsteine. Sporeback Troll|Sporenrücken-Troll|Kreatur — Troll, Mutant|Pfropfen 2 (Diese Kreatur kommt mit zwei +1/+1-Marken ins Spiel. Immer wenn eine andere Kreatur ins Spiel kommt, kannst du eine +1/+1-Marke von dieser Kreatur auf die neue Kreatur bewegen.)\n{1}{G}: Regeneriere eine Kreatur deiner Wahl, auf der mindestens eine +1/+1-Marke liegt. -Sporecap Spider|Sporenbedeckte Spinne|Kreatur — Spinne|Reichweite (Diese Kreatur kann fliegende Kreaturen blocken.) +Sporecap Spider|Sporenbedeckte Spinne|Kreatur — Spinne|Reichweite Sporecrown Thallid|Sporenkronen-Thallid|Kreatur — Pilzwesen|Jede andere Kreatur, die du kontrollierst und die ein Pilzwesen oder Saproling ist, erhält +1/+1. Sporemound|Sporenbuckel|Kreatur — Pilzwesen|Immer wenn ein Land unter deiner Kontrolle ins Spiel kommt, bringe einen 1/1 grünen Saproling-Kreaturenspielstein ins Spiel. Sporesower Thallid|Sporensäender Thallid|Kreatur — Pilzwesen|Lege zu Beginn deines Versorgungssegments eine Sporenmarke auf jedes Pilzwesen, das du kontrollierst.\nEntferne drei Sporenmarken vom Sporensäenden Thalliden: Bringe einen 1/1 grünen Saprolingspielstein ins Spiel. @@ -15768,6 +15821,7 @@ Swell of Growth|Wachstumsschub|Spontanzauber|Eine Kreatur deiner Wahl erhält +2 Sweltering Suns|Gleißende Sonnen|Hexerei|Die Gleißenden Sonnen fügen jeder Kreatur 3 Schadenspunkte zu.\nUmwandlung {3} ({3}, wirf diese Karte ab: Ziehe eine Karte.) Swelter|Hitzebad|Hexerei|Hitzebad fügt zwei Kreaturen deiner Wahl je 2 Schadenspunkte zu. Swerve|Abweichen|Spontanzauber|Verändere das Ziel eines Zauberspruchs deiner Wahl, der nur ein einzelnes Ziel hat. +Swift End|Promptes Ende|Spontanzauber — Abenteuer|Zerstöre eine Kreatur oder einen Planeswalker deiner Wahl. Du verlierst 2 Lebenspunkte. (Schicke diese Karte dann ins Exil. Du kannst sie später als Kreatur aus dem Exil wirken.) Swift Justice|Schnell geübte Gerechtigkeit|Spontanzauber|Bis zum Ende des Zuges erhält eine Kreatur deiner Wahl +1/+0, Erstschlag und Lebensverknüpfung. Swift Kick|Flinker Tritt|Spontanzauber|Eine Kreatur deiner Wahl, die du kontrollierst, erhält +1/+0 bis zum Ende des Zuges. Sie kämpft gegen eine Kreatur deiner Wahl, die du nicht kontrollierst. Swift Maneuver|Flinkes Manöver|Spontanzauber|Verhindere die nächsten 2 Schadenspunkte, die in diesem Zug einer Kreatur oder einem Spieler deiner Wahl zugefügt würden.\nZiehe zu Beginn des Versorgungssegments des nächsten Zuges eine Karte. @@ -15857,6 +15911,7 @@ Syphon Soul|Seelenfang|Hexerei|Der Seelenfang fügt allen anderen Spielern 2 Sch Syr Alin, the Lion's Claw|Syr Alin Löwenpranke|Legendäre Kreatur — Mensch, Ritter|Erstschlag\nImmer wenn Syr Alin Löwenpranke angreift, erhalten andere Kreaturen, die du kontrollierst, +1/+1 bis zum Ende des Zuges. Syr Carah, the Bold|Syr Carah die Tapfere|Legendäre Kreatur — Mensch, Ritter|Immer wenn Syr Carah die Tapfere oder ein Spontanzauber oder eine Hexerei, den bzw. die du kontrollierst, einem Spieler Schaden zufügt, schicke die oberste Karte deiner Bibliothek ins Exil. Du kannst jene Karte in diesem Zug spielen.\n{T}: Syr Carah fügt einem Ziel deiner Wahl 1 Schadenspunkt zu. Syr Elenora, the Discerning|Syr Elenora die Scharfsichtige|Legendäre Kreatur — Mensch, Ritter|Die Stärke von Syr Elenora der Scharfsichtigen ist gleich der Anzahl an Karten auf deiner Hand.\nWenn Syr Elenora ins Spiel kommt, ziehe eine Karte.\nZaubersprüche, die deine Gegner wirken und die Syr Elenora als Ziel haben, kosten beim Wirken {2} mehr. +Syr Faren, the Hengehammer|Syr Faren, Hammer des Steinkreises|Legendäre Kreatur — Mensch, Ritter|Immer wenn Syr Faren, Hammer des Steinkreises, angreift, erhält eine andere angreifende Kreatur deiner Wahl bis zum Ende des Zuges +X/+X, wobei X gleich der Stärke von Syr Faren ist. Syr Konrad, the Grim|Syr Konrad der Grimmige|Legendäre Kreatur — Mensch, Ritter|Immer wenn eine andere Kreatur stirbt oder eine Kreaturenkarte von irgendwoher außer aus dem Spiel auf einen Friedhof gelegt wird oder eine Kreaturenkarte deinen Friedhof verlässt, fügt Syr Konrad der Grimmige jedem Gegner 1 Schadenspunkt zu.\n{1}{B}: Jeder Spieler legt die oberste Karte seiner Bibliothek auf seinen Friedhof. Szadek, Lord of Secrets|Szadek, Herr der Geheimnisse|Legendäre Kreatur — Vampir|Fliegend\nFalls Szadek, Herr der Geheimnisse einem Spieler Kampfschaden zufügen würde, lege stattdessen so viele +1/+1-Marken auf Szadek, und dieser Spieler legt so viele Karten oben von seiner Bibliothek auf seinen Friedhof. Séance|Séance|Verzauberung|Zu Beginn jedes Versorgungsegments kannst du eine Kreaturenkarte deiner Wahl aus deinem Friedhof ins Exil schicken. Falls du dies tust, bringe einen Spielstein ins Spiel, der eine Kopie dieser Karte ist, und zusätzlich zu seinen anderen Typen noch ein Geist. Schicke ihn zu Beginn des nächsten Endsegments ins Exil. @@ -15924,6 +15979,7 @@ Talisman of Indulgence|Talisman der Genusssucht|Artefakt|{T}: Erhöhe deinen Man Talisman of Progress|Talisman des Fortschritts|Artefakt|{T}: Erhöhe deinen Manavorrat um {1}.\n{T}: Erhöhe deinen Manavorrat um {W} oder {U}. Der Talisman des Fortschritts fügt dir 1 Schadenspunkt zu. Talisman of Resilience|Talisman der Zähigkeit|Artefakt|{T}: Erzeuge {C}.\n{T}: Erzeuge {B} oder {G}. Der Talisman der Zähigkeit fügt dir 1 Schadenspunkt zu. Talisman of Unity|Talisman der Einigkeit|Artefakt|{T}: Erhöhe deinen Manavorrat um {1}.\n{T}: Erhöhe deinen Manavorrat um {G} oder {W}. Der Talisman des Einigkeit fügt dir 1 Schadenspunkt zu. +Tall as a Beanstalk|Groß wie eine Bohnenranke|Verzauberung — Aura|Verzaubert eine Kreatur\nDie verzauberte Kreatur erhält +3/+3, hat Reichweite und ist zusätzlich zu ihren anderen Typen ein Riese. Tallowisp|Talgwisch|Kreatur - Geist|Immer wenn du einen Geist oder einen arkanen Zauber spielst, kannst du deine Bibliothek nach einer Kreaturenverzauberungskarte durchsuchen, sie offen vorzeigen und auf deine Hand nehmen. Falls du dies tust, mische danach deine Bibliothek. Talon Gates|Das Krallentor|Welt — Dominaria|Zu jeden Zeitpunkt, zu dem du eine Hexerei spielen könntest, kannst du eine Karte aus deiner Hand, die kein Land ist, mit X Zeitmarken ins Exil schicken, wobei X ihren umgewandelten Manakosten entspricht.Falls die ins Exil geschickte Karte nicht Aussetzen hat, erhält sie Aussetzen. (Zu Beginn des Versorgungssegments ihres Besitzers entfernt dieser eine Zeitmarke. Wenn die letzte entfernt ist, wirkt dieser Spieler die Karte, ohne ihre Manakosten zu bezahlen. Falls es eine Kreatur ist, hat sie Eile.)\nImmer wenn du chaos würfelst, entferne zwei Zeitmarken von jeder ausgesetzten Karte, die du besitzt. Talon Sliver|Klauenremasuri|Beschwörung eines Remasuris|Alle Remasuris erhalten Erstschlag @@ -16235,6 +16291,7 @@ The Fourth Sphere|Die vierte Sphäre|Welt — Phyrexia|Opfere zu Beginn deines V The Gitrog Monster|Das Gitrog-Monster|Legendäre Kreatur — Frosch, Schrecken|Todesberührung\nOpfere zu Beginn deines Versorgungssegments Das Gitrog-Monster, falls du nicht ein Land opferst.\nDu darfst in jedem deiner Züge ein zusätzliches Land spielen.\nImmer wenn eine oder mehrere Länderkarten von irgendwoher auf deinen Friedhof gelegt werden, ziehe eine Karte. The Great Aurora|Die Große Aurora|Hexerei|Jeder Spieler mischt alle Karten aus seiner Hand und alle bleibenden Karten, die er besitzt, in seine Bibliothek und zieht dann entsprechend viele Karten. Jeder Spieler kann eine beliebige Anzahl an Länderkarten aus seiner Hand ins Spiel bringen. Schicke Die Große Aurora ins Exil. The Great Forest|Der Große Wald|Welt — Lorwyn|Jede Kreatur verwendet beim Zuweisen ihres Kampfschadens den Wert ihrer Widerstandskraft und nicht den ihrer Stärke.\nImmer wenn du chaos würfelst, erhalten bis zum Ende des Zuges Kreaturen, die du kontrollierst, +0/+2 und verursachen Trampelschaden. +The Great Henge|Der Große Steinkreis|Legendäres Artefakt|Dieser Zauberspruch kostet beim Wirken {X} weniger, wobei X gleich der höchsten Stärke unter den Kreaturen ist, die du kontrollierst.\n{T}: Erzeuge {G}{G}. Du erhältst 2 Lebenspunkte dazu.\nImmer wenn eine Nichtspielsteinkreatur unter deiner Kontrolle ins Spiel kommt, lege eine +1/+1-Marke auf sie und ziehe eine Karte. The Haunt of Hightower|Spuk vom höchsten Turm|Legendäre Kreatur — Vampir|Fliegend, Lebensverknüpfung\nImmer wenn der Spuk vom höchsten Turm angreift, wirft der verteidigende Spieler eine Karte ab.\nImmer wenn eine Karte von irgendwoher auf den Friedhof eines Gegners gelegt wird, lege eine +1/+1-Marke auf den Spuk vom höchsten Turm. The Hippodrome|Das Hippodrom|Welt — Segovia|Alle Kreaturen erhalten -5/-0.\nImmer wenn du chaos würfelst, kannst du eine Kreatur deiner Wahl zerstören, wenn ihre Stärke 0 oder weniger beträgt. The Hive|Wespennest|Artefakt|5, {T}: Bringe einen 1/1 Wespen-Spielstein ins Spiel. Behandle diesen Spielstein als eine 1/1 Artefaktkreatur mit Flugfähigkeit. @@ -16246,6 +16303,7 @@ The Mending of Dominaria|Die Wiederherstellung Dominarias|Verzauberung — Sage| The Mimeoplasm|Das Mimeoplasma|Legendäre Kreatur — Schlammwesen|Sowie das Mimeoplasma ins Spiel kommt, kannst du zwei Kreaturenkarten aus Friedhöfen ins Exil schicken. Falls du dies tust, kommt es als Kopie einer dieser Karten mit zusätzlich so viele +1/+1-Marken ins Spiel, wie die Stärke der anderen Karte beträgt. The Mirari Conjecture|Die Mirari-Hypothese|Verzauberung — Sage|(Je eine Sagenmarke beim Ins-Spiel-Kommen und nach deinem Ziehsegment. Opfern nach III.)\nI — Bringe eine Spontanzauberkarte deiner Wahl aus deinem Friedhof auf deine Hand zurück.\nII — Bringe eine Hexereikarte deiner Wahl aus deinem Friedhof auf deine Hand zurück.\nIII — Immer wenn du bis zum Ende des Zuges einen Spontanzauber oder eine Hexerei wirkst, kopiere ihn bzw. sie. Du kannst neue Ziele für die Kopie bestimmen. The Rack|Streckbank|Artefakt|Hat ein Gegner am Ende seiner Versorgungsphase weniger als drei Karten in der Hand, fügt die Streckbank ihm für jede Karte weniger 1 Schadenspunkt zu. +The Royal Scions|Die Kinder des Königs|Legendärer Planeswalker — Will, Rowan|+1: Ziehe eine Karte und wirf dann eine Karte ab.\n+1: Eine Kreatur deiner Wahl erhält +2/+0 und Erstschlag und verursacht Trampelschaden bis zum Ende des Zuges.\n—8: Ziehe vier Karten. Wenn du dies tust, fügen die Kinder des Königs einem Ziel deiner Wahl so viele Schadenspunkte zu, wie du Karten auf deiner Hand hast. The Scarab God|Die Skarabäen-Gottheit|Legendäre Kreatur — Gott|Zu Beginn deines Versorgungssegments verliert jeder Gegner X Lebenspunkte und du wendest Hellsicht X an, wobei X gleich der Anzahl an Zombies ist, die du kontrollierst.\n{2}{U}{B}: Schicke eine Kreaturenkarte deiner Wahl aus einem Friedhof ins Exil. Erzeuge einen Spielstein, der eine Kopie von ihr ist, außer dass er ein 4/4 schwarzer Zombie ist.\nWenn Die Skarabäen-Gottheit stirbt, bringe sie zu Beginn des nächsten Endsegments auf die Hand ihres Besitzers zurück. The Scorpion God|Die Skorpion-Gottheit|Legendäre Kreatur — Gott|Immer wenn eine Kreatur, auf der mindestens eine -1/-1-Marke liegt, stirbt, ziehe eine Karte.\n{1}{B}{R}: Lege eine -1/-1-Marke auf eine andere Kreatur deiner Wahl.\nWenn Die Skorpion-Gottheit stirbt, bringe sie zu Beginn des nächsten Endsegments auf die Hand ihres Besitzers zurück. The Unspeakable|Der Unaussprechbare|Legendäre Kreatur - Geist|Fliegend, verursacht Trampelschaden\nImmer wenn der Unaussprechbare einem Spieler Kampfschaden zufügt, kannst du eine arkane Karte deiner Wahl aus deinem Friedhof auf deine Hand zurückbringen. @@ -16688,6 +16746,7 @@ Tragic Arrogance|Tragische Arroganz|Hexerei|Für jeden Spieler bestimmst du von Tragic Lesson|Tragische Lektion|Spontanzauber|Ziehe zwei Karten. Wirf dann eine Karte ab, es sei denn, du bringst ein Land, das du kontrollierst, auf die Hand seines Besitzers zurück. Tragic Poet|Tragischer Dichter|Beschwörung von Stadtbewohnern|{T}, opfere den Tragischen Dichter: Bringe eine Verzauberungskarte aus Deinem Friedhof auf Deine Hand zurück. Tragic Slip|Tragischer Ausrutscher|Spontanzauber|Eine Kreatur deiner Wahl erhält -1/-1 bis zum Ende des Zuges.\nMorbide — Diese Kreatur erhält stattdessen -13/-13 bis zum Ende des Zuges, falls in diesem Zug eine Kreatur gestorben ist. +Trail of Crumbs|Spur aus Brotkrumen|Verzauberung|Wenn die Spur aus Brotkrumen ins Spiel kommt, erzeuge einen Speise-Spielstein.\nImmer wenn du eine Speise opferst, kannst du {1} bezahlen. Falls du dies tust, schaue dir die obersten zwei Karten deiner Bibliothek an. Du kannst davon eine bleibende Karte offen vorzeigen und auf deine Hand nehmen. Lege den Rest in beliebiger Reihenfolge unter deine Bibliothek. Trail of Evidence|Spur von Hinweisen|Verzauberung|Immer wenn du einen Spontanzauber oder eine Hexerei wirkst, stelle Nachforschungen an. (Bringe einen farblosen Hinweis-Artefaktspielstein mit „{2}, opfere dieses Artefakt: Ziehe eine Karte" ins Spiel.) Trail of Mystery|Pfad der Geheimnisse|Verzauberung|Immer wenn eine verdeckte Kreatur unter deiner Kontrolle ins Spiel kommt, kannst du deine Bibliothek nach einer Standardland-Karte durchsuchen, sie offen vorzeigen, auf deine Hand nehmen und dann deine Bibliothek mischen.\nImmer wenn eine bleibende Karte, die du kontrollierst, aufgedeckt wird und falls es eine Kreatur ist, erhält sie +2/+2 bis zum Ende des Zuges. Trail of the Mage-Rings|Weg der Magierringe|Welt — Vryn|Spontanzauber und Hexereien haben Abprall. (Der Beherrscher des Zauberspruchs schickt diesen ins Exil, sowie er verrechnet wird, falls er ihn aus seiner Hand gewirkt hat. Zu Beginn des nächsten Versorgungssegments dieses Spielers kann er diese Karte aus dem Exil wirken, ohne ihre Manakosten zu bezahlen.)\nImmer wenn du chaos würfelst, kannst du deine Bibliothek nach einer Spontanzauber- oder Hexerei-Karte durchsuchen, sie offen vorzeigen, auf deine Hand nehmen und dann deine Bibliothek mischen. @@ -16882,6 +16941,7 @@ Tsabo's Assassin|Tsabos Meuchler|Kreatur — Assassine|{T}: Zerstöre eine Kreat Tsabo's Decree|Tsabos Erlaß|Spontanzauber|Bestimme einen Kreaturentyp. Ein Spieler Deiner Wahl zeigt offen die Karten auf seiner Hand und wirft alle Kreaturenkarten dieses Typs ab. Zerstöre dann alle Kreaturen dieses Typs, die dieser Spieler kontrolliert. Sie können nicht regeneriert werden. Tsabo's Web|Tsabos Netz|Artefakt|Ziehe eine Karte, wenn Tsabos Netz ins Spiel kommt.\nLänder mit einer aktivierten Fähigkeit, die kein Mana produziert, enttappen nicht nicht während des Enttapp-Segments ihres Beherrschers. Tsunami|Tsunami|Hexerei|Vernichte alle Inseln im Spiel. +Tuinvale Treefolk|Tuinwald-Baumhirte|Kreatur — Baumhirte, Druide| Tukatongue Thallid|Zuzzelzungen-Thallid|Kreatur — Pilzwesen|Wenn das Zuzzelzungen-Thallid aus dem Spiel auf den Friedhof gelegt wird, bringe einen 1/1 grünen Saproling-Kreaturenspielstein ins Spiel. Tuktuk Grunts|Tuktuks Geiferer|Kreatur — Goblin, Krieger, Verbündeter|Eile\nImmer wenn Tuktuks Geiferer oder ein anderer Verbündeter unter deiner Kontrolle ins Spiel kommt, kannst du eine +1/+1-Marke auf Tuktuks Geiferer legen. Tuktuk Scrapper|Tuktuk-Raufbold|Kreatur — Goblin, Handwerker, Verbündeter|Immer wenn der Tuktuk-Raufbold oder ein anderer Verbündeter unter deiner Kontrolle ins Spiel kommt, kannst du ein Artefakt deiner Wahl zerstören. Falls dieses Artefakt auf diese Weise auf einen Friedhof gelegt wird, fügt der Tuktuk-Raufbold dem Beherrscher dieses Artefakts so viele Schadenspunkte zu, wie du Verbündete kontrollierst. @@ -17996,6 +18056,7 @@ Weird Harvest|Seltsame Ernte|Hexerei|Jeder Spieler kann seine Bibliothek nach bi Weirded Vampire|Absonderliche Vampirin|Kreatur — Vampir, Schrecken|Wahnsinn {2}{B} (Falls du diese Karte abwirfst, wirf sie ins Exil ab. Wenn du dies tust, wirke sie für ihre Wahnsinn-Kosten oder lege sie auf deinen Friedhof.) Weirding Shaman|Bizarrer Schamane|Kreatur — Goblin, Schamane|{3}{B}, opfere einen Goblin: Bringe zwei 1/1 schwarze (Goblin, Räuber)-Kreaturenspielsteine ins Spiel. Weirding Wood|Verqueres Holz|Verzauberung — Aura|Verzaubert ein Land\nWenn das Verquere Holz ins Spiel kommt, stelle Nachforschungen an. (Bringe einen farblosen Hinweis-Artefaktspielstein mit „{2}, opfere dieses Artefakt: Ziehe eine Karte" ins Spiel.)\nDas verzauberte Land hat „{T}: Erhöhe deinen Manavorrat um zwei Mana genau einer beliebigen Farbe." +Welcome Home|Willkommen|Hexerei — Abenteuer|Erzeuge drei 2/2 grüne Bär-Kreaturenspielsteine. (Schicke diese Karte dann ins Exil. Du kannst sie später als Kreatur aus dem Exil wirken.) Welcome to the Fold|Willkommen im Bund|Hexerei|Wahnsinn {X}{U}{U} (Falls du diese Karte abwirfst, wirf sie ins Exil ab. Wenn du dies tust, wirke sie für ihre Wahnsinn-Kosten oder lege sie auf deinen Friedhof.)\nÜbernimm die Kontrolle über eine Kreatur deiner Wahl, falls ihre Widerstandskraft 2 oder weniger beträgt. Falls die Wahnsinn-Kosten von Willkommen im Bund bezahlt wurden, übernimm stattdessen die Kontrolle über diese Kreatur, falls ihre Widerstandskraft X oder weniger beträgt. Welder Automaton|Schweißender Automat|Artefaktkreatur — Konstrukt|{3}{R}: Der Schweißende Automat fügt jedem Gegner 1 Schadenspunkt zu. Weldfast Engineer|Bronzeviertel-Ingenieur|Kreatur — Mensch, Handwerker|Zu Beginn des Kampfes in deinem Zug erhält eine Artefaktkreatur deiner Wahl, die du kontrollierst, +2/+0 bis zum Ende des Zuges. @@ -18089,6 +18150,7 @@ Wicked Akuba|Böse Akuba|Kreatur - Geist|{B}: Ein Spieler deiner Wahl, dem in di Wicked Guardian|Böse Stiefmutter|Kreatur — Mensch, Adliger|Wenn die Böse Stiefmutter ins Spiel kommt, kannst du sie einer anderen Kreatur, die du kontrollierst, 2 Schadenspunkte zufügen lassen. Falls du dies tust, ziehe eine Karte. Wicked Pact|Böser Pakt|Hexerei|Zerstöre zwei Kreaturen Deiner Wahl, die nicht schwarz sind. Du verlierst 5 Lebenspunkte.\n(Du kannst den Bösen Pakt nicht sprechen, wenn Du nicht zwei Kreaturen zum Zerstören wählen kannst.) Wicked Reward|Unmoralische Belohnung|Spontanzauber|Opfere eine Kreatur: Eine Kreatur Deiner Wahl erhält +4/+2 bis zum Ende des Zuges. +Wicked Wolf|Böser Wolf|Kreatur — Wolf|Wenn der Böse Wolf ins Spiel kommt, kämpft er gegen bis zu eine Kreatur deiner Wahl, die du nicht kontrollierst.\nOpfere eine Speise: Lege eine +1/+1-Marke auf den Bösen Wolf. Er erhält Unzerstörbarkeit bis zum Ende des Zuges. Tappe ihn. Wicker Warcrawler|Geflochtener Kampfkrabbler|Artefaktkreatur — Vogelscheuche|Immer wenn der Geflochtene Kampfkrabbler angreift oder blockt, lege am Ende des Kampfes eine -1/-1-Marke auf ihn. Wicker Witch|Weidenhexe|Artefaktkreatur — Vogelscheuche| Wickerbough Elder|Galgenast-Ältester|Kreatur — Baumhirte, Schamane|Der Galgenast-Älteste kommt mit einer -1/-1-Marke ins Spiel.\n{G}, entferne eine -1/-1-Marke vom Galgenast-Ältesten: Zerstöre ein Artefakt oder eine Verzauberung deiner Wahl. @@ -18128,6 +18190,7 @@ Wild Wanderer|Wanderin der Wildnis|Kreatur — Elf, Druide|Wenn die Wanderin der Wild Wurm|Wilder Wurm|Beschwörung eines Wurms|Wirf eine Münze, wenn der Wilde Wurm ins Spiel kommt. Wenn Du den Münzwurf verlierst, bringe den Wilden Wurm auf die Hand seines Besitzers zurück. Wild-Field Scarecrow|Wildwiesen-Vogelscheuche|Artefaktkreatur — Vogelscheuche|Verteidiger\n{2}, opfere die Wildwiesen-Vogelscheuche: Durchsuche deine Bibliothek nach bis zu zwei Standardland-Karten, zeige sie offen vor und nimm sie auf deine Hand. Mische danach deine Bibliothek. Wildblood Pack|Wildblutrudel|Kreatur — Werwolf|Verursacht Trampelschaden\nAngreifende Kreaturen, die du kontrollierst, erhalten +3/+0.\nTransformiere zu Beginn jedes Versorgungssegments das Wildblutrudel, falls ein Spieler im letzten Zug zwei oder mehr Zaubersprüche gewirkt hat. +Wildborn Preserver|Wildgeborener Bewahrer|Kreatur — Elf, Bogenschütze|Aufblitzen\nReichweite\nImmer wenn eine andere Nicht-Mensch-Kreatur unter deiner Kontrolle ins Spiel kommt, kannst du {X} bezahlen. Wenn du dies tust, lege X +1/+1-Marken auf den Wildgeborenen Bewahrer. Wildcall|Wildruf|Hexerei|Manifestiere die oberste Karte deiner Bibliothek und lege dann X +1/+1-Marken auf sie. (Um eine Karte zu manifestieren, bringe sie als eine 2/2 Kreatur verdeckt ins Spiel. Decke sie zu einem beliebigen Zeitpunkt für ihre Manakosten auf, falls es eine Kreaturenkarte ist.) Wilderness Elemental|Wildniselementar|Kreatur — Elementarwesen|Verursacht Trampelschaden\nDie Stärke des Wildniselementar ist gleich der Anzahl an Nicht-Standardländern, die deine Gegner kontrollieren. Wilderness Hypnotist|Hypnotiseur des Wilden|Kreatur — Meervolk, Zauberer|{T}: Eine rote oder grüne Kreatur deiner Wahl erhält -2/-0 bis zum Ende des Zuges. @@ -18146,6 +18209,7 @@ Wildsize|Groß und wild|Spontanzauber|Eine Kreatur deiner Wahl erhält +2/+2 und Wildslayer Elves|Wildschlächter-Elfen|Kreatur — Elf, Krieger|Verdorren (Dies fügt Kreaturen Schaden in Form von -1/-1-Marken zu.) Wildwood Geist|Wildholzgeist|Kreatur — Geist|Solange es dein Zug ist, erhält der Wildholzgeist +2/+2. Wildwood Rebirth|Wildholzwiedergeburt|Spontanzauber|Bringe eine Kreaturenkarte deiner Wahl aus deinem Friedhof auf deine Hand zurück. +Wildwood Tracker|Wildholz-Fährtensucher|Kreatur — Elf, Krieger|Immer wenn der Wildholz-Fährtensucher angreift oder blockt und falls du eine andere Nicht-Mensch-Kreatur kontrollierst, erhält der Wildholz-Fährtensucher +1/+1 bis zum Ende des Zuges. Will of the Naga|Wille der Naga|Spontanzauber|Wühlen (Mit jeder Karte, die du aus deinem Friedhof ins Exil schickst, während du diesen Zauberspruch wirkst, bezahlst du {1} seiner Kosten.)\nTappe bis zu zwei Kreaturen deiner Wahl. Diese Kreaturen enttappen nicht während des nächsten Enttappsegments ihres Beherrschers. Will-Forged Golem|Willengeschmiedeter Golem|Artefaktkreatur — Golem|Einberufen (Deine Kreaturen können dir helfen, diesen Zauberspruch zu wirken. Jede Kreatur, die du tappst, während du diesen Zauberspruch wirkst, reduziert dessen Kosten um {1} oder um ein Mana der Farbe jener Kreatur.) Will-o'-the-Wisp|Irrlichter|Beschwörung von Irrlichtern|Können fliegen.\n{B}: Regeneration @@ -18291,6 +18355,7 @@ Wojek Embermage|Wojek-Funkenmagier|Kreatur — Mensch, Zauberer|Ausstrahlung {T} Wojek Halberdiers|Wojek-Hellebardiere|Kreatur — Mensch, Soldat|Bataillon — Immer wenn die Wojek-Hellebardiere und mindestens zwei andere Kreaturen angreifen, erhalten die Wojek-Hellebardiere Erstschlag bis zum Ende des Zuges. Wojek Siren|Wojek-Sirene|Spontanzauber|Ausstrahlung Eine Kreatur deiner Wahl und alle anderen Kreaturen, die mit ihr eine Farbe gemeinsam haben, erhalten +1/+1 bis zum Ende des Zuges. Wolf of Devil's Breach|Wolf aus der Teufelsspalte|Kreatur — Elementarwesen, Wolf|Immer wenn der Wolf aus der Teufelsspalte angreift, kannst du {1}{R} bezahlen und eine Karte abwerfen. Falls du dies tust, fügt der Wolf aus der Teufelsspalte einer Kreatur oder einem Planeswalker deiner Wahl Schadenspunkte in Höhe der umgewandelten Manakosten der abgeworfenen Karte zu. +Wolf's Quarry|Wolfsbeute|Hexerei|Erzeuge drei 1/1 grüne Wildschwein-Kreaturenspielsteine mit „Wenn diese Kreatur stirbt, erzeuge einen Speise-Spielstein." (Ein Speise-Spielstein ist ein Artefakt mit „{2}, {T}, opfere dieses Artefakt: Du erhältst 3 Lebenspunkte dazu.") Wolf-Skull Shaman|Wolfsschädelschamane|Kreatur — Elf, Schamane|Verwandtschaft Zu Beginn deines Versorgungssegments kannst du dir die oberste Karte deiner Bibliothek anschauen. Hat sie mindestens einen Kreaturentyp mit dem Wolfsschädelschamanen gemeinsam, kannst du sie offen vorzeigen. Falls du dies tust, bringe einen 2/2 grünen Wolf-Kreaturenspielstein ins Spiel. Wolfbitten Captive|Wolfsgebissener Gefangener|Kreatur — Mensch, Werwolf|{1}{G}: Der Wolfsgebissene Gefangene erhält +2/+2 bis zum Ende des Zuges. Aktiviere diese Fähigkeit nur einmal pro Zug.\nTransformiere zu Beginn jedes Versorgungssegments den Wolfsgebissenen Gefangenen, falls im letzten Zug keine Zaubersprüche gewirkt wurden. Wolfbriar Elemental|Dornenwolfelementar|Kreatur — Elementarwesen|Multibonus {G} (Du kannst zusätzlich beliebig oft {G} bezahlen, sowie du diesen Zauberspruch wirkst.)\nWenn das Dornenwolfelementar ins Spiel kommt, bringe für jedes Mal, dass du seine Bonuskosten bezahlt hast, einen 2/2 grünen Wolf-Kreaturenspielstein ins Spiel. @@ -18464,6 +18529,7 @@ Yoked Ox|Eingespannter Ochse|Kreatur — Ochse| Yoked Plowbeast|Unterjochte Pflugbestie|Kreatur — Bestie|Umwandlung {2} ({2}, wirf diese Karte aus deiner Hand ab: Ziehe eine Karte.) Yomiji, Who Bars the Way|Yomiji, der den Weg versperrt|Legendäre Kreatur - Geist|Immer wenn eine legendäre bleibende Karte (außer Yomiji, der den Weg versperrt) aus dem Spiel auf einen Friedhof gelegt wird, bringe diese Karte auf die Hand ihres Besitzers zurück. Yore-Tiller Nephilim|Vorzeitausgraber-Nephilim|Kreatur — Nephilim|Immer wenn der Vorzeitausgraber-Nephilim angreift, bringe eine Kreaturenkarte deiner Wahl aus deinem Friedhof getappt und angreifend ins Spiel zurück. +Yorvo, Lord of Garenbrig|Yorvo, Fürst von Garenbruck|Legendäre Kreatur — Riese, Adliger|Yorvo, Fürst von Garenbruck, kommt mit vier +1/+1-Marken ins Spiel.\nImmer wenn eine andere grüne Kreatur unter deiner Kontrolle ins Spiel kommt, lege eine +1/+1-Marke auf Yorvo. Falls dann die Stärke jener Kreatur höher ist als die von Yorvo, lege eine weitere +1/+1-Marke auf Yorvo. Yosei, the Morning Star|Yosei, der Stern des Morgens|Legendäre Kreatur - Drache, Geist|Fliegend\nWenn Yosei, der Stern des Morgens, aus dem Spiel auf einen Friedhof gelegt wird, übergeht ein Spieler deiner Wahl sein nächstes Enttappsegment. Tappe bis zu fünf bleibende Karten deiner Wahl, die dieser Spieler kontrolliert. Yotian Soldier|Yotischer Söldner|Artefaktkreatur — Soldat|Der Yotische Söldner wird beim Angreifen nicht getappt. Young Pyromancer|Junger Pyromagier|Kreatur — Mensch, Schamane|Immer wenn du einen Spontanzauber oder eine Hexerei wirkst, bringe einen 1/1 roten Elementarwesen-Kreaturenspielstein ins Spiel. diff --git a/forge-gui/res/languages/cardnames-es-ES.txt b/forge-gui/res/languages/cardnames-es-ES.txt index 3139ff6eb17..f79efa2cfbd 100644 --- a/forge-gui/res/languages/cardnames-es-ES.txt +++ b/forge-gui/res/languages/cardnames-es-ES.txt @@ -1,31 +1,31 @@ -Abandon Hope|Perder la esperanza|| +Abandon Hope|Perder la esperanza|Conjuro|Como coste adicional para lanzar este hechizo, descarta X cartas.\nMira la mano del oponente objetivo y elige X cartas de este. Ese jugador descarta esas cartas. Abandon Reason|Perder la razón|Instantáneo|Hasta dos criaturas objetivo obtienen +1/+0 cada una y ganan la habilidad de dañar primero hasta el final del turno.\nDemencia {1}{R}. (Si descartas esta carta, exíliala. Cuando lo hagas, lánzala por su coste de demencia o ponla en tu cementerio.) Abandoned Outpost|Puesto de avanzada abandonado|Tierra|El Puesto de avanzada abandonado entra en juego girado.\n{T}: Agrega {W} a tu reserva de maná.\n{T}, sacrificar el Puesto de avanzada abandonado: Agrega un maná de cualquier color a tu reserva de maná. Abandoned Sarcophagus|Sarcófago abandonado|Artefacto|Puedes lanzar cartas que no sean tierra con la habilidad de ciclo desde tu cementerio\nSi una carta con la habilidad de ciclo fuera a ir a tu cementerio desde cualquier parte sin haberse activado su habilidad de ciclo, en vez de eso, exíliala. Abattoir Ghoul|Necrófago del matadero|Criatura — Zombie|Daña primero.\nSiempre que una criatura que recibió daño del Necrófago del matadero este turno muera, ganas vidas igual a la resistencia de esa criatura. -Abbey Gargoyles|Gárgolas de la Abadía|| +Abbey Gargoyles|Gárgolas de la Abadía|Criatura - Gárgola|Vuela, protección contra el rojo Abbey Griffin|Grifo de la abadía|Criatura — Grifo|Vuela, vigilancia. -Abbey Matron|Abadesa|| +Abbey Matron|Abadesa|Criatura - Clérigo Humano|{W}, {T}: La Abadesa recibe +0/+3 hasta el final del turno. Abbot of Keral Keep|Abad de la Fortaleza Keral|Criatura — Monje humano|Destreza. (Siempre que lances un hechizo que no sea de criatura, esta criatura obtiene +1/+1 hasta el final del turno.)Cuando el Abad de la Fortaleza Keral entre al campo de batalla, exilia la primera carta de tu biblioteca. Hasta el final del turno, puedes jugar esa carta. -Abduction|Secuestro|| +Abduction|Secuestro|Encantamiento - Aura|Encantar criatura\nCuando el Secuestro entre en juego, endereza a la criatura encantada.\nTú controlas a la criatura encantada.\nCuando la criatura encantada muera, devuelve esa carta al juego bajo el control de su dueño. Aberrant Researcher|Investigador aberrante|Criatura — Insecto humano|Vuela.\nAl comienzo de tu mantenimiento, pon la primera carta de tu biblioteca en tu cementerio. Si es una carta de instantáneo o de conjuro, transforma al Investigador aberrante. -Abeyance|Supresión|| +Abeyance|Supresión|Instantáneo|Hasta el final del turno, el jugador objetivo no puede lanzar hechizos instantáneos o de brujería, y ese jugador no puede activar habilidades que no sean habilidades de maná.\nRoba una carta. Abhorrent Overlord|Jefe supremo aberrante|Criatura — Demonio|Vuela.\nCuando el Jefe supremo aberrante entre al campo de batalla, pon en el campo de batalla una cantidad de fichas de criatura Arpía negras 1/1 con la habilidad de volar igual a tu devoción al negro. (Cada {B} en los costes de maná de los permanentes que controlas cuenta para tu devoción al negro.)\nAl comienzo de tu mantenimiento, sacrifica una criatura. -Abjure|Abjurar|| +Abjure|Abjurar|Instantáneo|Como coste adicional para lanzar este hechizo, sacrifica un permanente azul.\nContrarresta el hechizo objetivo. Abnormal Endurance|Resistencia anormal|Instantáneo|Hasta el final del turno, la criatura objetivo obtiene +2/+0 y gana "Cuando esta criatura muera, regrésala al campo de batalla girada bajo el control de su propietario". Abolisher of Bloodlines|Abolidora de linajes|Criatura — Vampiro eldrazi|Vuela.\nCuando esta criatura se transforme en la Abolidora de linajes, el oponente objetivo sacrifica tres criaturas. Abolish|Abolir|Instantáneo|Puedes descartar una carta de llanura en lugar de pagar el coste de maná de Abolir.\nDestruye el artefacto o encantamiento objetivo. Abominable Treefolk|Pueblo arbóreo abominable|Criatura nevada — Pueblo-arbóreo|Arrolla.\nTanto la fuerza como la resistencia del Pueblo arbóreo abominable son iguales a la cantidad de permanentes nevados que controlas.\nCuando el Pueblo arbóreo abominable entre al campo de batalla, gira la criatura objetivo que controla un oponente. Esa criatura no se endereza durante el próximo paso de enderezar de su controlador. Abomination of Gudul|Abominación de Gudul|Criatura — Horror|Vuela.\nSiempre que la Abominación de Gudul haga daño de combate a un jugador, puedes robar una carta. Si lo haces, descarta una carta.\nMetamorfosis {2}{B}{G}{U}. (Puedes lanzar esta carta boca abajo como una criatura 2/2 pagando {3}. Ponla boca arriba en cualquier momento pagando su coste de metamorfosis.) -Abomination|Abominación|| -Aboroth|Aboroth|| +Abomination|Abominación|Criatura - Horror|Siempre que la Abominación bloquee o sea bloqueada por una criatura verde o blanca, destruye a esa criatura al final del combate. +Aboroth|Aboroth|Criatura — Elemental|Mantenimiento acumulativo - Pon un contador de -1/-1 en Aboroth. (Al principio de tu mantenimiento, pon un contador de edad en este permanente, luego sacrifícalo a menos que pagues su coste de mantenimiento por cada contador de edad en él). Aboshan's Desire|Deseo de Áboshan|Encantar criatura|La criatura encantada tiene la habilidad de volar.\nUmbral La criatura encantada no puede ser objetivo de hechizos o habilidades. (Tienes umbral mientras haya siete o más cartas en tu cementerio.) Aboshan, Cephalid Emperor|Áboshan, Emperador cefálido|Criatura — Cefálido legendario|Girar un Cefálido enderezado que controles: Gira el permanente objetivo.\n{U}{U}{U}: Gira todas las criaturas que no tengan la habilidad de volar. -About Face|Media vuelta|| +About Face|Media vuelta|Instantáneo|Intercambia la fuerza y resistencia de la criatura objetivo hasta el final del turno. Abrade|Erosionar|Instantáneo|Elige uno:\n• Erosionar hace 3 puntos de daño a la criatura objetivo.\n• Destruye el artefacto objetivo. Abrupt Decay|Deterioro brusco|Instantáneo|Deterioro brusco no puede ser contrarrestado por hechizos o habilidades.\nDestruye el permanente objetivo que no sea tierra con coste de maná convertido de 3 o menos. -Absolute Grace|Gracia absoluta|| -Absolute Law|Ley absoluta|| +Absolute Grace|Gracia absoluta|Encantamiento|Todas las criaturas tienen protección contra el negro. +Absolute Law|Ley absoluta|Encantamiento|Todas las criaturas tienen protección contra el rojo. Absolver Thrull|Absolutor thrull|Criatura — Clérigo thrull|Acechar (Cuando esta carta vaya a un cementerio desde el juego, remuévela del juego acechando a la criatura objetivo.)\nCuando el Absolutor thrull entre en juego o la criatura a la que acecha vaya a un cementerio, destruye el encantamiento objetivo. Absorb Vis|Absorber vis|Conjuro|El jugador objetivo pierde 4 vidas y tú ganas 4 vidas.\nCiclo de tierra básica {1}{B}. ({1}{B}, descartar esta carta: Busca en tu biblioteca una carta de tierra básica, muéstrala y ponla en tu mano. Luego baraja tu biblioteca.) Absorb|Absorber|Instantáneo|Contrarresta el hechizo objetivo. Ganas 3 vidas. @@ -35,10 +35,10 @@ Abuna's Chant|Canto del abunas|Instantáneo|Elige uno: Gana 5 vidas; o prevén l Abundance|Abundancia|Encantamiento|Si fueras a robar una carta, en vez de eso, puedes elegir tierra o no tierra y mostrar cartas de la parte superior de tu biblioteca hasta que muestres una carta del tipo elegido. Pon esa carta en tu mano y pon todas las otras cartas mostradas de esta manera en el fondo de tu biblioteca en cualquier orden. Abundant Growth|Crecimiento abundante|Encantamiento — Aura|Encantar tierra.\nCuando Crecimiento abundante entre al campo de batalla, roba una carta.\nLa tierra encantada tiene "{T}: Agrega un maná de cualquier color a tu reserva de maná". Abundant Maw|Milfauces|Criatura — Sanguijuela eldrazi|Emerger {6}{B}. (Puedes lanzar este hechizo sacrificando una criatura y pagando el coste de emerger menos el coste de maná convertido de esa criatura.)\nCuando lances el Milfauces, el oponente objetivo pierde 3 vidas y tú ganas 3 vidas. -Abyssal Gatekeeper|Portero abismal|| -Abyssal Horror|Horror abismal|| -Abyssal Hunter|Cazador abismal|| -Abyssal Nightstalker|Cazador nocturno abismal|| +Abyssal Gatekeeper|Portero abismal|Criatura — Horror|Cuando el Portero abismal muera, cada jugador sacrifica a una criatura. +Abyssal Horror|Horror abismal|Criatura — Horror|Vuela\nCuando el Horror abismal entre en juego, el jugador objetivo descarta dos cartas. +Abyssal Hunter|Cazador abismal|Criatura - Asesino Humano|{B}, {T}: Gira la criatura objetivo. El Cazador abismal inflige un daño igual a la fuerza del Cazador abismal sobre esa criatura. +Abyssal Nightstalker|Cazador nocturno abismal|Criatura — Cazador nocturno|Siempre que el Cazador nocturno abismal ataque y no sea bloqueado, el jugador defensor descarta una carta. Abyssal Nocturnus|Nócturnus abismal|Criatura — Horror|Siempre que un oponente descarte una carta, el Nócturnus abismal obtiene +2/+2 y gana la habilidad de inspirar temor hasta el final del turno. Abyssal Persecutor|Perseguidor abismal|Criatura — Demonio|Vuela, arrolla.\nTú no puedes ganar el juego y tus oponentes no pueden perder el juego. Abyssal Specter|Espectro abismal|Criatura — Espectro|Vuela. (Esta criatura no puede ser bloqueada excepto por criaturas que tengan la habilidad de volar.)\nSiempre que el Espectro abismal haga daño a un jugador, ese jugador descarta una carta de su mano. @@ -57,7 +57,7 @@ Academy Drake|Draco de la Academia|Criatura — Draco|Estímulo {4}. (Puedes pag Academy Elite|Élite de la academia|Criatura — Hechicero humano|La Élite de la academia entra al campo de batalla con X contadores +1/+1 sobre ella, donde X es la cantidad de cartas de instantáneo y de conjuro que hay en todos los cementerios.\n{2}{U}, remover un contador +1/+1 de la Élite de la academia: Roba una carta, luego descarta una carta. Academy Journeymage|Maga graduada de la Academia|Criatura — Hechicero humano|Te cuesta {1} menos lanzar este hechizo si controlas un Hechicero.\nCuando la Maga graduada de la Academia entre al campo de batalla, regresa la criatura objetivo que controla un oponente a la mano de su propietario. Academy Raider|Incursor de la academia|Criatura — Guerrero humano|Intimidar. (Esta criatura no puede ser bloqueada excepto por criaturas artefacto y/o criaturas que compartan un color con ella.)Siempre que el Incursor de la academia haga daño de combate a un jugador, puedes descartar una carta. Si lo haces, roba una carta. -Academy Rector|Rector de la Academia|| +Academy Rector|Rector de la Academia|Criatura - Clérigo Humano|Cuando el Rector de la Academia muera, puedes exiliarlo. Si lo haces, busca en tu biblioteca una carta de encantamiento, pon esa carta en juego y luego baraja tu biblioteca. Academy Researchers|Investigadores de la Academia|Criatura — Hechicero humano|Cuando los Investigadores de la Academia entren en juego, puedes poner en juego una carta de aura de tu mano anexada a los Investigadores de la Academia. Academy Ruins|Ruinas de la Academia|Tierra legendaria|{T}: Agrega {1} a tu reserva de maná.\n{1}{U}, {T}: Pon la carta de artefacto objetivo de tu cementerio en la parte superior de tu biblioteca. Academy at Tolaria West|Academia en Tolaria Oeste|Plano — Dominaria|Al comienzo de tu paso final, si no tienes cartas en tu mano, roba siete cartas.\nSiempre que lances caos, descarta tu mano. @@ -68,24 +68,24 @@ Acclaimed Contender|Contendiente aclamada|Criatura — Caballero humano|Cuando l Accomplished Automaton|Autómata consumado|Criatura artefacto — Constructo|Fabricar 1. (Cuando esta criatura entre al campo de batalla, pon un contador +1/+1 sobre ella o crea una ficha de criatura artefacto Servo incolora 1/1.) Accorder Paladin|Paladín de los acordantes|Criatura — Caballero humano|Grito de batalla. (Siempre que esta criatura ataque, cada otra criatura atacante obtiene +1/+0 hasta el final del turno.) Accorder's Shield|Escudo del acordante|Artefacto — Equipo|La criatura equipada obtiene +0/+3 y tiene la habilidad de vigilancia. (Esta criatura no se gira al atacar.)Equipar {3}. ({3}: Anexa este equipo a la criatura objetivo que controles. Juega la habilidad de equipar como un conjuro.) -Accumulated Knowledge|Conocimiento acumulado|| +Accumulated Knowledge|Conocimiento acumulado|Instantáneo|Roba una carta, luego roba tantas cartas como el número de cartas llamadas Conocimiento Acumulado en todos los cementerios. Accursed Centaur|Centauro maldito|Criatura — Centauro zombie|Cuando el Centauro maldito entre en juego, sacrifica una criatura. Accursed Horde|Horda maldita|Criatura — Zombie|{1}{B}: El Zombie objetivo atacante gana la habilidad de indestructible hasta el final del turno. (El daño y los efectos que dicen "destruir" no lo destruyen. Si su resistencia es 0 o menos, va al cementerio de su propietario igualmente.) Accursed Spirit|Espíritu maldito|Criatura — Espíritu|Intimidar. (Esta criatura no puede ser bloqueada excepto por criaturas artefacto y/o criaturas que compartan un color con ella.) Accursed Witch|Bruja maldita|Criatura — Chamán humano|A tus oponentes les cuesta {1} menos lanzar hechizos que hagan objetivo a la Bruja maldita.\nCuando la Bruja maldita muera, regrésala al campo de batalla transformada bajo tu control anexada al oponente objetivo. Acid Web Spider|Araña de red ácida|Criatura — Araña|Alcance.\nCuando la Araña de red ácida entre al campo de batalla, puedes destruir el equipo objetivo. Acid-Spewer Dragon|Dragón escupeácido|Criatura — Dragón|Vuela, toque mortal.\nMegametamorfosis {5}{B}{B}. (Puedes lanzar esta carta boca abajo como una criatura 2/2 pagando {3}. Ponla boca arriba en cualquier momento pagando su coste de megametamorfosis y pon un contador +1/+1 sobre ella.)\nCuando el Dragón escupeácido se ponga boca arriba, pon un contador +1/+1 sobre cada otra criatura Dragón que controlas. -Acidic Dagger|Daga corrosiva|| +Acidic Dagger|Daga corrosiva|Artefacto|{4}, {T}: Siempre que una criatura objetivo inflija daño de combate a una criatura no muralla en este turno, destruye a esa criatura no muralla. Cuando la criatura objetivo abandone el juego este turno, sacrifica la Daga corrosiva. Activa esta habilidad sólo antes de que se declaren los bloqueadores. Acidic Slime|Fango ácido|Criatura — Cieno|Toque mortal. (Cualquier cantidad de daño que esto haga a una criatura es suficiente para destruirla.)Cuando el Fango ácido entre al campo de batalla, destruye el artefacto, encantamiento o tierra objetivo. -Acidic Sliver|Fragmentado corrosivo|| -Acidic Soil|Suelo ácido|| +Acidic Sliver|Fragmentado corrosivo|Criatura - Fragmentado|Todos los fragmentados tienen "{2}, Sacrifica este permanente: Este permanente causa 2 de daño a cualquier objetivo." +Acidic Soil|Suelo ácido|Sorcery|Conjuro|Suelo ácido inflige daño a cada jugador igual al número de tierras que controlan. Acolyte of Xathrid|Acólita de Xathrid|Criatura — Clérigo humano|{1}{B}, {T}: El jugador objetivo pierde 1 vida. Acolyte of the Inferno|Acólito del infierno|Criatura — Monje humano|Prestigio 1. (Cuando esta criatura haga daño de combate a un jugador, si no tiene prestigio, pon un contador +1/+1 sobre ella y gana prestigio.)Siempre que el Acólito del infierno sea bloqueado por una criatura, hace 2 puntos de daño a esa criatura. Acolyte's Reward|Recompensa del acólito|Instantáneo|Prevén los siguientes X puntos de daño que se le fueran a hacer a la criatura objetivo este turno, donde X es tu devoción al blanco. Si se previene daño de esta manera, la Recompensa del acólito hace esa misma cantidad de daño a la criatura o jugador objetivo. (Cada {W} en los costes de maná de los permanentes que controlas cuenta para tu devoción al blanco.) Acorn Catapult|Catapulta de bellotas|Artefacto|{1}, {T}: La Catapulta de bellotas hace 1 punto de daño a la criatura o jugador objetivo. El controlador de esa criatura o ese jugador pone en el campo de batalla una ficha de criatura Ardilla verde 1/1. Acorn Harvest|Cosechar bellotas|Conjuro|Pon en juego dos fichas de criatura Ardilla verde 1/1.\nRetrospectiva {1}{G}, pagar 3 vidas. (Puedes jugar esta carta desde tu cementerio pagando su coste de retrospectiva. Luego remuévela del juego.) Acquire|Adquirir|Conjuro|Busca una carta de artefacto en la biblioteca del oponente objetivo y ponla en juego bajo tu control. Luego ese jugador baraja su biblioteca. -Acridian|Acrídido|| +Acridian|Acrídido|Criatura - Insecto|Eco {1}{G} (Al principio de su mantenimiento, si esto ha estado bajo tu control desde el principio de tu último mantenimiento, sacrifícalo a menos que pagues el coste del eco). Acrobatic Maneuver|Maniobra acrobática|Instantáneo|Exilia la criatura objetivo que controlas, luego regresa esa carta al campo de batalla bajo el control de su propietario.\nRoba una carta. Act of Aggression|Acto de agresión|Instantáneo|({R/P} puede pagarse con {R} o con 2 vidas.)Gana el control de la criatura objetivo que controla un oponente hasta el final del turno. Endereza esa criatura. Gana la habilidad de prisa hasta el final del turno. Act of Authority|Acto de autoridad|Encantamiento|Cuando el Acto de autoridad entre al campo de batalla, puedes exiliar el encantamiento o artefacto objetivo.Al comienzo de tu mantenimiento, puedes exiliar el artefacto o encantamiento objetivo. Si lo haces, su controlador gana el control del Acto de autoridad. @@ -99,19 +99,19 @@ Adanto Vanguard|Vanguardia de Adanto|Criatura — Soldado vampiro|Mientras la Va Adanto, the First Fort|Adanto, la primera fortaleza|Tierra legendaria|(Se transforma del Desembarco de la Legión.)\n{T}: Agrega {W} a tu reserva de maná.\n{2}{W}, {T}: Crea una ficha de criatura Vampiro blanca 1/1 con la habilidad de vínculo vital. Adaptive Automaton|Autómata adaptativo|Criatura artefacto — Constructo|En cuanto el Autómata adaptativo entre al campo de batalla, elige un tipo de criatura.\nEl Autómata adaptativo es del tipo elegido además de sus otros tipos.\nLas otras criaturas que controlas del tipo elegido obtienen +1/+1. Adaptive Snapjaw|Mandibulatensa adaptativo|Criatura — Bestia lagarto|Evolucionar. (Siempre que una criatura entre al campo de batalla bajo tu control, si la fuerza o la resistencia de esa criatura es mayor que la de esta criatura, pon un contador +1/+1 sobre esta criatura.) -Adarkar Sentinel|Centinela de Adarkar|| -Adarkar Unicorn|Unicornio de Adarkar|| +Adarkar Sentinel|Centinela de Adarkar|Criatura Artefacto - Soldado|{1}: El Centinela de Adarkar recibe +0/+1 hasta el final del turno. +Adarkar Unicorn|Unicornio de Adarkar|Criatura - Unicornio|{T}: Agrega {U} o {C}{U}. Gasta este maná sólo para pagar los costes acumulativos de mantenimiento. Adarkar Valkyrie|Valkiria de Adarkar|Criatura nevada — Ángel|Vuela, vigilancia.\n{T}: Cuando la criatura objetivo que no sea la Valkiria de Adarkar muera este turno, regresa esa carta al campo de batalla bajo tu control. Adarkar Wastes|Yermos de Adarkar|Tierra|{T}: Agrega {1} a tu reserva de maná.\n{T}: Agrega {W} o {U} a tu reserva de maná. Los Yermos de Adarkar te hacen 1 punto de daño. Adarkar Windform|Eolomorfo de Adarkar|Criatura nevada — Ilusión|Vuela.\n{1}{S}: La criatura objetivo pierde la habilidad de volar hasta el final del turno. ({S} puede pagarse con un maná de un permanente nevado.) Adder-Staff Boggart|Boggart vara de culebra|Criatura — Guerrero trasgo|Cuando el Boggart vara de culebra entre en juego, enfréntate con un oponente. Si ganas, pon un contador +1/+1 sobre el Boggart vara de culebra. (Cada jugador enfrentado muestra la primera carta de su biblioteca, luego pone esa carta en la parte superior o inferior. Gana el jugador cuya carta tenga el mayor coste de maná convertido.) -Addle|Turbar|| +Addle|Turbar|Conjuro|Elige un color. El jugador objetivo revela su mano y tú eliges una carta de ese color. Ese jugador descarta esa carta. Adeliz, the Cinder Wind|Adeliz, Viento de Ceniza|Criatura legendaria — Hechicero humano|Vuela, prisa.\nSiempre que lances un hechizo de instantáneo o de conjuro, los Hechiceros que controlas obtienen +1/+1 hasta el final del turno. Admiral Beckett Brass|Almirante Beckett Azófar|Criatura legendaria — Pirata humano|Los otros Piratas que controlas obtienen +1/+1.\nAl comienzo de tu paso final, gana el control del permanente objetivo que no sea tierra y que esté controlado por un jugador que recibió daño de combate de tres o más Piratas este turno. Admiral's Order|Orden de la almirante|Instantáneo|Incursión — Si atacaste con una criatura este turno, puedes pagar {U} en vez de pagar el coste de maná de este hechizo.\nContrarresta el hechizo objetivo. Admonition Angel|Ángel de admonición|Criatura — Ángel|Vuela.\nAterrizaje — Siempre que una tierra entre al campo de batalla bajo tu control, puedes exiliar el permanente objetivo que no sea tierra distinto del Ángel de admonición.\nCuando el Ángel de admonición deje el campo de batalla, regresa al campo de batalla bajo el control de sus propietarios todas las cartas exiliadas con él. Adorned Pouncer|Acechador ornamentado|Criatura — Felino|Daña dos veces.\nEternizar {3}{W}{W}. ({3}{W}{W}, exiliar esta carta de tu cementerio: Crea una ficha que es una copia de esta carta, excepto que es un Felino Zombie negro 4/4 sin coste de maná. Activa la habilidad de eternizar solo como un conjuro.) -Advance Scout|Explorador avanzado|| +Advance Scout|Explorador avanzado|Criatura - Soldado Explorador Humano|Daña primero\n{W}: La criatura objetivo recibe el primer golpe hasta el final del turno. Advanced Hoverguard|Aeroguarda mejorado|Criatura — Zángano|Vuela.\n{U}: El Aeroguarda mejorado no puede ser objetivo de hechizos o habilidades este turno. Advanced Stitchwing|Alacosida avanzado|Criatura — Horror zombie|Vuela.\n{2}{U}, descartar dos cartas: Regresa el Alacosida avanzado de tu cementerio al campo de batalla girado. Advent of the Wurm|Advenimiento de la sierpe|Instantáneo|Crea una ficha de criatura Sierpe verde 5/5 con la habilidad de arrollar. @@ -125,11 +125,11 @@ Aegis Automaton|Autómata de la égida|Criatura artefacto — Constructo|{4}{W}: Aegis of Honor|Égida del honor|Encantamiento|{1}: La siguiente vez que un hechizo de instantáneo o de conjuro fuera a hacerte daño este turno, en vez de eso, ese hechizo hace ese daño a su controlador. Aegis of the Gods|Égida de los dioses|Criatura encantamiento — Soldado humano|Tienes la habilidad de antimaleficio. (No puedes ser objetivo de hechizos o habilidades que controlan tus oponentes.) Aegis of the Heavens|Égida de los cielos|Instantáneo|La criatura objetivo obtiene +1/+7 hasta el final del turno. -Aegis of the Meek|Égida de los mansos|| +Aegis of the Meek|Égida de los mansos|Artefacto|{1}, {T}: La criatura objetivo 1/1 recibe +1/+2 hasta el final del turno. Aeon Chronicler|Aeon Chronicler|Creature — Avatar|Aeon Chronicler's power and toughness are each equal to the number of cards in your hand.\nSuspend X—{X}{3}{U}. X can't be 0.\nWhenever a time counter is removed from Aeon Chronicler while it's exiled, draw a card. Aeon Engine|Rotor de los eones|Artefacto|El Rotor de los eones entra al campo de batalla girado.\n{T}, exiliar el Rotor de los eones: Invierte el orden de turno del juego. (Por ejemplo, si el juego avanza por la mesa hacia la izquierda, ahora avanza hacia la derecha.) Aerial Assault|Asalto aéreo|Conjuro|Destruye la criatura girada objetivo. Ganas 1 vida por cada criatura que controlas con la habilidad de volar. -Aerial Caravan|Caravana aérea|| +Aerial Caravan|Caravana aérea|Criatura - Soldado Humano|Vuela\n{1}{U}{U}: Exilia la carta superior de tu biblioteca. Hasta el final del turno, puedes jugar esa carta. (Revela la carta cuando la exilies.) Aerial Engineer|Ingeniera aérea|Criatura — Artífice humano|Mientras controles un artefacto, la Ingeniera aérea obtiene +2/+0 y tiene la habilidad de volar. Aerial Formation|Formación aérea|Instantáneo|Esfuerzo — Lanzar la Formación aérea cuesta {2}{U} más por cada objetivo después del primero.\nCualquier cantidad de criaturas objetivo obtienen +1/+1 cada una y ganan la habilidad de volar hasta el final del turno. Aerial Guide|Guía aéreo|Criatura — Draco|Vuela.\nSiempre que el Guía aéreo ataque, otra criatura atacante objetivo gana la habilidad de volar hasta el final del turno. @@ -147,12 +147,12 @@ Aeronaut Admiral|Almirante aeronauta|Criatura — Piloto humano|Vuela.\nLos Veh Aeronaut Tinkerer|Reparador de aeronaves|Criatura — Artífice humano|El Reparador de aeronaves tiene la habilidad de volar mientras controles un artefacto. (No puede ser bloqueada excepto por criaturas que tengan la habilidad de volar o alcance.) Aesthir Glider|Planeador aesthir|Criatura artefacto — Constructo ave|Vuela.\nEl Planeador aesthir no puede bloquear. Aether Adept|Perito del éter|Criatura — Hechicero humano|Cuando el Perito del éter entre al campo de batalla, regresa la criatura objetivo a la mano de su propietario. -Aether Barrier|Barrera de éter|| +Aether Barrier|Barrera de éter|Encantamiento|Cuando un jugador lance un hechizo de criatura, ese jugador sacrifica un permanente a menos que pague {1}. Aether Burst|Estallido del Éter|Instantáneo|Regresa hasta X criaturas objetivo a las manos de sus propietarios, donde X es 1 más el número de cartas de Estallido del Éter que haya en todos los cementerios en cuanto juegues el Estallido del Éter. Aether Charge|Carga de Éter|Encantamiento|Siempre que una Bestia entre en juego bajo tu control, puedes elegir que haga 4 puntos de daño al oponente objetivo. Aether Chaser|Perseguidor de éter|Criatura — Artífice humano|Daña primero.\nCuando el Perseguidor de éter entre al campo de batalla, obtienes {E}{E} (dos contadores de energía).\nSiempre que el Perseguidor de éter ataque, puedes pagar {E}{E}. Si lo haces, crea una ficha de criatura artefacto Servo incolora 1/1. Aether Figment|Imaginario del éter|Criatura — Ilusión|Estímulo {3}. (Puedes pagar {3} adicionales en cuanto lances este hechizo.)\nEl Imaginario del éter es imbloqueable.\nSi el Imaginario del éter fue estimulado, entra al campo de batalla con dos contadores +1/+1 sobre él. -Aether Flash|Destello del Éter|| +Aether Flash|Destello del Éter|Cada vez que una criatura entre en juego, el Destello del Éter le inflige 2 puntos de daño. Aether Gale|Vendaval del éter|Conjuro|Regresa seis permanentes objetivo que no sean tierra a las manos de sus propietarios. Aether Gust|Ráfaga de éter|Instantáneo|Elige el hechizo o permanente objetivo que sea rojo o verde. Su propietario lo pone en la parte superior o en el fondo de su biblioteca. Aether Herder|Pastor del éter|Criatura — Druida artífice elfo|Cuando el Pastor del éter entre al campo de batalla, obtienes {E}{E} (dos contadores de energía).\nSiempre que el Pastor del éter ataque, puedes pagar {E}{E}. Si lo haces, crea una ficha de criatura artefacto Servo incolora 1/1. @@ -160,17 +160,17 @@ Aether Hub|Planta de éter central|Tierra|Cuando la Planta de éter central entr Aether Inspector|Inspector de éter|Criatura — Enano artífice|Vigilancia.\nCuando el Inspector de éter entre al campo de batalla, obtienes {E}{E} (dos contadores de energía).\nSiempre que el Inspector de éter ataque, puedes pagar {E}{E}. Si lo haces, crea una ficha de criatura artefacto Servo incolora 1/1. Aether Meltdown|Colapso del éter|Encantamiento — Aura|Destello. (Puedes lanzar este hechizo en cualquier momento en que pudieras lanzar un instantáneo.)\nEncantar criatura o vehículo.\nCuando el Colapso del éter entre al campo de batalla, obtienes {E}{E} (dos contadores de energía).\nEl permanente encantado obtiene -4/-0. Aether Membrane|Membrana de éter|Criatura — Muro|Defensor.\nLa Membrana de éter puede bloquear como si tuviera la habilidad de volar.\nSiempre que la Membrana de éter bloquee a una criatura, regresa esa criatura a la mano de su propietario al final del combate. -Aether Mutation|Mutación del éter|| +Aether Mutation|Mutación del éter|Conjuro|Devuelve la criatura objetivo a la mano de su dueño. Crea X fichas de criaturas verdes Saprolín 1/1, donde X es el coste de maná convertido de esa criatura. Aether Poisoner|Envenenadora de éter|Criatura — Artífice humano|Toque mortal. (Cualquier cantidad de daño que esto haga a una criatura es suficiente para destruirla.)\nCuando la Envenenadora de éter entre al campo de batalla, obtienes {E}{E} (dos contadores de energía).\nSiempre que la Envenenadora de éter ataque, puedes pagar {E}{E}. Si lo haces, crea una ficha de criatura artefacto Servo incolora 1/1. -Aether Rift|Grieta de éter|| +Aether Rift|Grieta de éter|Encantamiento|Al principio de tu mantenimiento, descarta una carta al azar. Si descartas una carta de criatura de esta manera, devuélvela de tu cementerio al juego a menos que algún jugador pague 5 vidas. Aether Shockwave|Onda expansiva de éter|Instantáneo|Elige uno: Gira todos los Espíritus; o gira todas las criaturas que no sean Espíritus. Aether Snap|Chasquido del éter|Conjuro|Remueve todos los contadores de todos los permanentes y exilia todas las fichas. Aether Spellbomb|Bombahechizo de éter|Artefacto|{U}, sacrificar la Bombahechizo de éter: Regresa la criatura objetivo a la mano de su propietario.\n{1}, sacrificar la Bombahechizo de éter: Roba una carta. -Aether Sting|Piquete de Éter|| -Aether Storm|Tormenta del éter|| +Aether Sting|Piquete de Éter|Encantamiento|Siempre que un oponente lance un hechizo de criatura, el Piquete de Éter inflige 1 de daño a ese jugador. +Aether Storm|Tormenta del éter|Encantamiento|No se pueden lanzar hechizos de criaturas.\nPaga 4 vidas: Destruir la Tormenta del éter. No se puede regenerar. Cualquier jugador puede activar esta habilidad. Aether Swooper|Surcadora de éter|Criatura — Artífice vedalken|Vuela.\nCuando la Surcadora de éter entre al campo de batalla, obtienes {E}{E} (dos contadores de energía).\nSiempre que la Surcadora de éter ataque, puedes pagar {E}{E}. Si lo haces, crea una ficha de criatura artefacto Servo incolora 1/1. Aether Theorist|Teórico del éter|Criatura — Bribón vedalken|Cuando el Teórico del éter entre al campo de batalla, obtienes {E}{E}{E} (tres contadores de energía).\n{T}, pagar {E}: Adivina 1. (Mira la primera carta de tu biblioteca. Puedes poner esa carta en el fondo de tu biblioteca.) -Aether Tide|Corriente de éter|| +Aether Tide|Corriente de éter|Conjuro|Como coste adicional para lanzar este hechizo, descarta X cartas de criatura. Devuelve las X criaturas objetivo a las manos de sus dueños. Aether Tradewinds|Vientos alisios del éter|Instantáneo|Regresa el permanente objetivo que controlas y el permanente objetivo que no controlas a las manos de sus propietarios. Aether Tunnel|Túnel de éter|Encantamiento — Aura|Encantar criatura.\nLa criatura encantada obtiene +1/+0 y no puede ser bloqueada. Aether Vial|Frasco de éter|Artefacto|Al comienzo de tu mantenimiento, puedes poner un contador de carga sobre el Frasco de éter.\n{T}: puedes poner en juego de tu mano una criatura con coste de maná convertido igual al número de contadores de carga sobre el Frasco de éter. @@ -201,27 +201,27 @@ Affa Protector|Protector de Affa|Criatura — Soldado humano aliado|Vigilancia. Affectionate Indrik|Indrik cariñoso|Criatura — Bestia|Cuando el Indrik cariñoso entre al campo de batalla, puedes hacer que luche contra la criatura objetivo que no controlas. (Cada una hace una cantidad de daño igual a su fuerza a la otra.) Afflicted Deserter|Desertor afligido|Criatura — Licántropo humano|Al comienzo de cada mantenimiento, si no se lanzaron hechizos en el último turno, transforma al Desertor afligido. Afflict|Afligir|Instantáneo|La criatura objetivo obtiene -1/-1 hasta el final del turno.\nRoba una carta. -Afiya Grove|Arboleda de Afiya|| +Afiya Grove|Arboleda de Afiya|Encantamiento|La Arboleda de Afiya entra en juego con tres contadores +1/+1.\nAl principio de tu mantenimiento, mueve un contador +1/+1 de la Arboleda de Afiya a la criatura objetivo.\nCuando la Arboleda de Afiya Grove no tenga contadores +1/+1, sacrifícala. Afterlife|Vestigio de vida|Instantáneo|Destruye la criatura objetivo. No puede ser regenerada. Su controlador pone en el campo de batalla una ficha de criatura Espíritu blanca 1/1 con la habilidad de volar. -Aftershock|Conmoción posterior|| +Aftershock|Conmoción posterior|Conjuro|Destruye el artefacto, la criatura o la tierra objetivo. La Conmoción posterior te inflinge 3 de daño. Agadeem Occultist|Ocultista de Agadeem|Criatura — Chamán humano aliado|{T}: Pon en el campo de batalla bajo tu control la carta de criatura objetivo del cementerio de un oponente si su coste de maná convertido es menor o igual al número de Aliados que controlas. Ageless Entity|Entidad sempiterna|Criatura — Elemental|Siempre que ganes vida, pon esa misma cantidad de contadores +1/+1 sobre la Entidad sempiterna. Ageless Sentinels|Centinelas eternos|Criatura — Muro|(Los muros no pueden atacar.)Vuela.\nCuando los Centinelas eternos bloquean, su tipo de criatura se convierte en Ave Gigante. (Deja de ser Muro. Este efecto no termina al final del turno.) Agent of Erebos|Agente de Erebos|Criatura encantamiento — Zombie|Constelación — Siempre que el Agente de Erebos u otro encantamiento entre al campo de batalla bajo tu control, exilia todas las cartas del cementerio del jugador objetivo. Agent of Horizons|Agente de los horizontes|Criatura — Bribón humano|{2}{U}: El Agente de los horizontes no puede ser bloqueado este turno. Agent of Masks|Agente de máscaras|Criatura — Consejero humano|Al comienzo de tu mantenimiento, cada oponente pierde 1 vida. Ganas vida igual a la cantidad de vida perdida de esta manera. -Agent of Shauku|Agente de Shauku|| -Agent of Stromgald|Agente de Stromgald|| +Agent of Shauku|Agente de Shauku|Criatura - Mercenario Humano|{1}{B}, Sacrifica una tierra: La criatura objetivo recibe +2/+0 hasta el final del turno. +Agent of Stromgald|Agente de Stromgald|Criatura — Caballero Humano|{R}: Agrega {B}. Agent of Treachery|Agente de la traición|Criatura — Bribón humano|Cuando el Agente de la traición entre al campo de batalla, gana el control del permanente objetivo.\nAl comienzo de tu paso final, si controlas tres o más permanentes de los que no eres propietario, roba tres cartas. Agent of the Fates|Agente de las Moiras|Criatura — Asesino humano|Toque mortal.\nHeroísmo — Siempre que lances un hechizo que haga objetivo al Agente de las Moiras, cada oponente sacrifica una criatura. Aggravated Assault|Agresión con agravantes|Encantamiento|{3}{R}{R}: Endereza todas las criaturas que controles. Después de esta fase, hay una fase de combate adicional seguida de una fase principal adicional. Juega esta habilidad sólo en cualquier momento en que pudieras jugar un conjuro. Aggravate|Agravar|Instantáneo|Agravar hace 1 punto de daño a cada criatura que controle el jugador objetivo. Cada criatura que recibió daño de esta manera ataca este turno si puede. -Aggression|Agresión|| +Aggression|Agresión|Encantamiento - Aura|Encantar criatura no muralla\nLa criatura encantada tiene la habilidad daña primero y arrollar.\nAl principio del paso final del controlador de la criatura encantada, destruye esa criatura si no atacó este turno. Aggressive Mammoth|Mamut agresivo|Criatura — Elefante|Arrolla. (Esta criatura puede hacer el daño de combate sobrante al jugador o planeswalker al que ataca.)\nLas otras criaturas que controlas tienen la habilidad de arrollar. Aggressive Mining|Excavación intensiva|Encantamiento|No puedes jugar tierras.\nSacrificar una tierra: Roba dos cartas. Activa esta habilidad solo una vez cada turno. -Aggressive Urge|Impulso Agresivo|| -Agility|Agilidad|| -Agonizing Demise|Fallecimiento Agónico|| +Aggressive Urge|Impulso Agresivo|Instantáneo|La criatura objetivo recibe +1/+1 hasta el final del turno.\nRoba una carta. +Agility|Agilidad|Encantamiento - Aura|Encantar criatura.\nLa criatura encantada obtiene +1/+1 y tiene la habilidad de flanquear. (Siempre que una criatura sin la habilidad de flanquear bloquee a esta criatura, la criatura bloqueadora obtiene -1/-1 hasta el final del turno.) +Agonizing Demise|Fallecimiento Agónico|Instantáneo|Estímulo {1}{R} (Puedes pagar {1}{R} adicionales al lanzar este hechizo.)\nDestruye la criatura objetivo que no sea negra. No puede ser regenerada. Si el Fallecimiento Agónico fue estimulado, le hace daño al controlador de esa criatura igual a la fuerza de esa criatura. Agonizing Memories|Recuerdos agónicos|Conjuro|Mira la mano del jugador objetivo y elige dos cartas de ahí. Pon esas cartas en la parte superior de la biblioteca de ese jugador en cualquier orden. Agonizing Syphon|Extracción agonizante|Conjuro|La Extracción agonizante hace 3 puntos de daño a cualquier objetivo y tú ganas 3 vidas. Agony Warp|Deformar agónicamente|Instantáneo|La criatura objetivo obtiene -3/-0 hasta el final del turno.\nLa criatura objetivo obtiene -0/-3 hasta el final del turno. @@ -239,7 +239,7 @@ Ainok Bond-Kin|Ainok unido por la fe|Criatura — Soldado perro|Supervivencia {1 Ainok Guide|Guía ainok|Criatura — Explorador perro|Cuando el Guía ainok entre al campo de batalla, elige uno:\n• Pon un contador +1/+1 sobre el Guía ainok.\n• Busca en tu biblioteca una carta de tierra básica, muéstrala, luego baraja tu biblioteca y pon esa carta en la parte superior. Ainok Survivalist|Sobreviviente ainok|Criatura — Chamán perro|Megametamorfosis {1}{G}. (Puedes lanzar esta carta boca abajo como una criatura 2/2 pagando {3}. Ponla boca arriba en cualquier momento pagando su coste de megametamorfosis y pon un contador +1/+1 sobre ella.)\nCuando el Sobreviviente ainok se ponga boca arriba, destruye el artefacto o encantamiento objetivo que controla un oponente. Ainok Tracker|Rastreador ainok|Criatura — Explorador perro|Daña primero.Metamorfosis {4}{R}. (Puedes lanzar esta carta boca abajo como una criatura 2/2 pagando {3}. Ponla boca arriba en cualquier momento pagando su coste de metamorfosis.) -Air Bladder|Vejiga de aire|| +Air Bladder|Vejiga de aire|Encantamiento — Aura|Encantar criatura\nLa criatura encantada tiene la habilidad de volar.\nLa criatura encantada sólo puede bloquear a las criaturas con la habilidad de volar. Air Elemental|Elemental de aire|Criatura — Elemental|Vuela. Air Servant|Sirviente de aire|Criatura — Elemental|Vuela. (Esta criatura no puede ser bloqueada excepto por criaturas que tengan la habilidad de volar o alcance.)\n{2}{U}: Gira la criatura objetivo con la habilidad de volar. Airborne Aid|Ayuda aérea|Conjuro|Roba una carta por cada Ave en juego. @@ -301,63 +301,63 @@ Akroma's Memorial|Monumento a Akroma|Artefacto legendario|Las criaturas que cont Akroma's Vengeance|Venganza de Akroma|Conjuro|Destruye todos los artefactos, criaturas y encantamientos.\nCiclo {3}. ({3}, descartar esta carta de tu mano: Roba una carta.) Akroma, Angel of Fury|Akroma, ángel de furia|Criatura legendaria — Ángel|Akroma, ángel de furia no puede ser contrarrestada.\nVuela, arrolla, protección contra blanco y contra azul.\n{R}: Akroma, ángel de furia obtiene +1/+0 hasta el final del turno.\nMetamorfosis {3}{R}{R}{R}. (Puedes lanzar esta carta boca abajo como una criatura 2/2 pagando {3}. Ponla boca arriba en cualquier momento pagando su coste de metamorfosis.) Akroma, Angel of Wrath|Akroma, Ángel de Ira|Criatura — Ángel legendario|Vuela, daña primero, arrolla, prisa, protección contra negro, protección contra rojo.\nAkroma, Ángel de Ira no se gira al atacar. -Akron Legionnaire|Legionario de Akron|| -Aku Djinn|Djinn de Aku|| +Akron Legionnaire|Legionario de Akron|Criatura - Soldado Gigante|Excepto las criaturas llamadas Legionario de Akron y las criaturas artefacto, las criaturas que controlas no pueden atacar. +Aku Djinn|Djinn de Aku|Criatura — Djinn|Arrolla\nAl principio de tu mantenimiento, pon un contador +1/+1 en cada criatura que cada oponente controle. Akuta, Born of Ash|Akuta, nacido de la ceniza|Criatura legendaria - Espíritu|Prisa.\nAl comienzo de tu mantenimiento, si tienes más cartas en tu mano que cada oponente, puedes sacrificar un pantano. Si lo haces, regresa a Akuta, nacido de la ceniza de tu cementerio al juego. -Alabaster Dragon|Dragón alabastro|| +Alabaster Dragon|Dragón alabastro|Criatura - Dragón Volador|Cuando el Dragón alabastro muera, mételo en la biblioteca de su dueño. Alabaster Kirin|Kirin de alabastro|Criatura — Kirin|Vuela, vigilancia. -Alabaster Leech|Sanguijuela de Alabastro|| +Alabaster Leech|Sanguijuela de Alabastro|Criatura - Sanguijuela|Los hechizos blancos que lanzas cuestan {W} más de lo que cuestan. Alabaster Mage|Mago de alabastro|Criatura — Hechicero humano|{1}{W}: La criatura objetivo que controlas gana la habilidad de vínculo vital hasta el final del turno. (El daño hecho por la criatura también hace que su controlador gane esa misma cantidad de vidas.) -Alabaster Potion|Poción de alabastro|| -Alabaster Wall|Muro de alabastro|| +Alabaster Potion|Poción de alabastro|Instántaneo|Elige uno —\n• El jugador objetivo gana X de vida.\n• Evita el siguiente daño X que se infligiría a cualquier objetivo en este turno. +Alabaster Wall|Muro de alabastro|Criatura - Muro|Defensor (Esta criatura no puede atacar.)\n{T}: Evita el siguiente daño de 1 que sería infligido a cualquier objetivo en este turno. Alaborn Cavalier|Caballero de Alaborn|Criatura — Caballero humano|Siempre que el Caballero de Alaborn ataque, puedes girar la criatura objetivo. -Alaborn Grenadier|Granadero de Alaborn|| -Alaborn Musketeer|Mosquetero de Alaborn|| -Alaborn Trooper|Soldado de caballeria de Alaborn|| -Alaborn Veteran|Veterano alaborn|| -Alaborn Zealot|Defensor alaborn|| -Aladdin's Lamp|Lámpara de Aladino|| +Alaborn Grenadier|Granadero de Alaborn|Criatura — Soldado humano|Vigilancia +Alaborn Musketeer|Mosquetero de Alaborn|Criatura — Soldado humano|Alcance (Esta criatura puede bloquear a las criaturas con la habilidad de volar.) +Alaborn Trooper|Soldado de caballeria de Alaborn|Criatura — Soldado humano| +Alaborn Veteran|Veterano alaborn|Criatura — Caballero humano|{T}: La criatura objetivo recibe +2/+2 hasta el final del turno. Activa esta habilidad sólo durante tu turno, antes de que los atacantes sean declarados. +Alaborn Zealot|Defensor alaborn|Criatura — Soldado humano|Cuando el Defensor alaborn bloquee a una criatura, destruye a esa criatura y al Defensor alaborn. +Aladdin's Lamp|Lámpara de Aladino|Artefacto|{X}, {T}: La próxima vez que robes una carta en este turno, mira las X cartas de la parte superior de tu biblioteca, pon todas menos una en la parte inferior de tu biblioteca en un orden aleatorio, y luego roba una carta. X no puede ser 0. Aladdin's Ring|Anillo de Aladino|Artefacto|{8}, {T}: El Anillo de Aladino hace 4 puntos de daño a la criatura o jugador objetivo. -Alarum|Voz de alarma|| -Albino Troll|Troll albino|| +Alarum|Voz de alarma|Instantáneo|Endereza la criatura objetivo que no atacante. Obtiene +1/+3 hasta el final del turno. +Albino Troll|Troll albino|Criatura — Troll|Eco {1}{G} (Al principio de tu mantenimiento, si esto ha estado bajo tu control desde el principio de tu último mantenimiento, sacrifícalo a menos que pagues su coste de eco.)\n{1}{G}: Regenera el Troll albino. Alchemist's Apprentice|Aprendiz de alquimista|Criatura — Hechicero humano|Sacrificar el Aprendiz de alquimista: Roba una carta. Alchemist's Greeting|Saludo del alquimista|Conjuro|El Saludo del alquimista hace 4 puntos de daño a la criatura objetivo.\nDemencia {1}{R}. (Si descartas esta carta, exíliala. Cuando lo hagas, lánzala por su coste de demencia o ponla en tu cementerio.) Alchemist's Refuge|Refugio del alquimista|Tierra|{T}: Agrega {1} a tu reserva de maná.\n{G}{U}, {T}: Puedes lanzar las cartas que no sean tierra este turno como si tuvieran la habilidad de destello. Alchemist's Vial|Frasco del alquimista|Artefacto|Cuando el Frasco del alquimista entre al campo de batalla, roba una carta.{1}, {T}, sacrificar el Frasco del alquimista: La criatura objetivo no puede atacar ni bloquear este turno. -Aleatory|Azar|| +Aleatory|Azar|Instantáneo|Lanza este hechizo sólo durante el combate después de que los bloqueadores sean declarados.\nLanza una moneda al aire. Si ganas la tirada, la criatura objetivo obtiene +1/+1 hasta el final del turno.\nRoba una carta al comienzo del mantenimiento del turno siguiente. Alesha's Vanguard|Vanguardia de Alesha|Criatura — Guerrero orco|Rapidez {2}{B}. (Puedes lanzar este hechizo por su coste de rapidez. Si lo haces, gana la habilidad de prisa y regresa del campo de batalla a la mano de su propietario al comienzo del próximo paso final.) Alesha, Who Smiles at Death|Alesha, la que sonríe a la muerte|Criatura legendaria — Guerrero humano|Daña primero.\nSiempre que Alesha, la que sonríe a la muerte ataque, puedes pagar {W/B}{W/B}. Si lo haces, regresa la carta de criatura objetivo con fuerza de 2 o menos de tu cementerio al campo de batalla girada y atacando. -Alexi's Cloak|Capa de Alexi|| -Alexi, Zephyr Mage|Alexi, Maga Céfira|| +Alexi's Cloak|Capa de Alexi|Encantamiento — Aura|Destello\nEncantar criatura\nLa criatura encantada tiene la habilidad de velo. (No puede ser objetivo de hechizos o habilidades.) +Alexi, Zephyr Mage|Alexi, Maga Céfira|Criatura Legendaria - Hechicero Humano|{X}{U}, {T}, Descarta dos cartas: Devuelve X criaturas objetivo a las manos de sus dueños. Algae Gharial|Gavial de algas|Criatura — Cocodrilo|Velo.\nSiempre que otra criatura vaya a un cementerio desde el juego, puedes poner un contador +1/+1 sobre el Gavial de algas. Alhammarret's Archive|Archivo de Alhammarret|Artefacto legendario|Si fueras a ganar vidas, en vez de eso, ganas el doble de esas vidas.Si fueras a robar una carta, excepto la primera que robas en tus pasos de robar, en vez de eso, roba dos cartas. Alhammarret, High Arbiter|Alhammarret, árbitro supremo|Criatura legendaria — Esfinge|Vuela.Cuando Alhammarret, árbitro supremo entre al campo de batalla, cada oponente muestra su mano. Eliges el nombre de una carta que no sea tierra mostrada de esta manera.Tus oponentes no pueden lanzar hechizos con el nombre elegido (mientras esta criatura esté en el campo de batalla). -Ali Baba|Ali Baba|| -Aliban's Tower|Torre de Alibán|| +Ali Baba|Ali Baba|Criatura — Pícaro humano|{R}: Gira el Muro objetivo. +Aliban's Tower|Torre de Alibán|Instantáneo|La criatura objetivo que bloquea obtiene +3/+1 hasta el final del turno. Aligned Hedron Network|Edros alineados|Artefacto|Cuando los Edros alineados entren al campo de batalla, exilia todas las criaturas con fuerza de 5 o más hasta que los Edros alineados dejen el campo de batalla. (Esas criaturas regresan bajo el control de sus propietarios.) All Is Dust|Todo es polvo|Conjuro tribal — Eldrazi|Cada jugador sacrifica todos los permanentes de color que controla. All Suns' Dawn|Amanecer de todos los soles|Conjuro|Por cada color, regresa hasta una carta objetivo de ese color de tu cementerio a tu mano. Luego remueve del juego el Amanecer de todos los soles. All That Glitters|Todo lo que reluce|Encantamiento — Aura|Encantar criatura.\nLa criatura encantada obtiene +1/+1 por cada artefacto y/o encantamiento que controlas. -Allay|Mitigar|| +Allay|Mitigar|Instantáneo|Recuperar {3} (Puedes pagar {3} adicionales al lanzar este hechizo. Si lo haces, pon esta carta en tu mano en cuanto se resuelva.)\nDestruye el encantamiento objetivo. Alley Evasion|Huida por el callejón|Instantáneo|Elige uno:\n• La criatura objetivo que controlas obtiene +1/+2 hasta el final del turno.\n• Regresa la criatura objetivo que controlas a la mano de su propietario. -Alley Grifters|Embaucadores callejeros|| +Alley Grifters|Embaucadores callejeros|Criatura — Mercenario humano|Siempre que los Embaucadores callejeros sean bloqueados, el jugador defensor descarta una carta. Alley Strangler|Estrangulador del callejón|Criatura — Bribón etergénito|Amenaza. Alliance of Arms|Alianza de armas|Conjuro|Unir fuerzas — Comenzando contigo, cada jugador puede pagar cualquier cantidad de maná. Cada jugador pone en el campo de batalla X fichas de criatura Soldado blancas 1/1, donde X es el la cantidad total de maná pagado de esta manera. Allied Reinforcements|Refuerzos aliados|Conjuro|Pon en el campo de batalla dos fichas de criatura Caballero Aliado blancas 2/2. -Allied Strategies|Estrategias Aliadas|| +Allied Strategies|Estrategias Aliadas|Conjuro|Dominio - El jugador objetivo roba una carta por cada tipo de tierra básica entre las tierras que controle. Allosaurus Rider|Jinete de alosaurio|Criatura — Guerrero elfo|Puedes remover del juego dos cartas verdes de tu mano en lugar de pagar el coste de maná del Jinete de alosaurio.\nTanto la fuerza como la resistencia del Jinete de alosaurio son iguales a 1 más el número de tierras que controlas. -Alloy Golem|Gólem de Aleación|| +Alloy Golem|Gólem de Aleación|Criatura artefacto — Golem|Cuando el Gólem de Aleación entre en juego, elige un color.\nEl Gólem de Aleación es el color elegido. (Sigue siendo un artefacto.) Alloy Myr|Myr de aleación|Criatura artefacto — Myr|{T}: Agrega un maná de cualquier color a tu reserva de maná. -Alluring Scent|Aroma seductor|| +Alluring Scent|Aroma seductor|Conjuro|Todas las criaturas capaces de bloquear a la criatura objetivo en este turno lo hacen. Alluring Siren|Sirena tentadora|Criatura — Sirena|{T}: La criatura objetivo que controla un oponente te ataca este turno si puede. Ally Encampment|Campamento aliado|Tierra|{T}: Agrega {1} a tu reserva de maná.{T}: Agrega un maná de cualquier color a tu reserva de maná. Usa este maná solo para lanzar un hechizo de Aliado.{1}, {T}, sacrificar el Campamento aliado: Regresa el Aliado objetivo que controlas a la mano de su propietario. Alms Beast|Bestia de las limosnas|Criatura — Bestia|Las criaturas que bloquean o son bloqueadas por la Bestia de las limosnas tienen la habilidad de vínculo vital. Alms Collector|Recaudador de dádivas|Criatura — Clérigo felino|Destello.\nSi un oponente fuera a robar dos o más cartas, en vez de eso, ese jugador y tú roban una carta cada uno. Alms of the Vein|Limosna sanguinolenta|Conjuro|El oponente objetivo pierde 3 vidas y tú ganas 3 vidas.\nDemencia {B}. (Si descartas esta carta, exíliala. Cuando lo hagas, lánzala por su coste de demencia o ponla en tu cementerio.) -Alms|Limosna|| +Alms|Limosna|Encantamiento|{1}, Exilia la carta superior de tu cementerio: Evita el siguiente daño de 1 que sería infligido a la criatura objetivo en este turno. Alpha Authority|Autoridad del alfa|Encantamiento — Aura|Encantar criatura.La criatura encantada tiene la habilidad de antimaleficio y no puede ser bloqueada por más de una criatura. Alpha Brawl|Lucha de alfas|Conjuro|La criatura objetivo que controla un oponente le hace daño igual a su fuerza a cada otra criatura que controla ese jugador, luego cada una de esas criaturas le hace daño igual a su fuerza a esa criatura. -Alpha Kavu|Kavu alfa|| +Alpha Kavu|Kavu alfa|Criatura — Kavu|{1}{G}: La criatura Kavu objetivo recibe -1/+1 hasta el final del turno. Alpha Myr|Myr alfa|Criatura artefacto — Myr| Alpha Status|Categoría alfa|Encantar criatura|La criatura encantada obtiene +2/+2 por cada una de las demás criaturas en juego que compartan un tipo de criatura con ella. Alpha Tyrranax|Tyrranax alfa|Criatura — Bestia| @@ -366,76 +366,77 @@ Alpine Guide|Guía alpino|Criatura nevada — Explorador humano|Cuando el Guía Alpine Moon|Luna alpina|Encantamiento|En cuanto la Luna alpina entre al campo de batalla, elige el nombre de una carta de tierra no básica.\nLas tierras que tus oponentes controlen con el nombre elegido pierden todos los tipos de tierra y habilidades y ganan "{T}: Agrega un maná de cualquier color". Altac Bloodseeker|Buscasangre de Altac|Criatura — Berserker humano|Siempre que una criatura que controla un oponente muera, el Buscasangre de Altac obtiene +2/+0 y gana las habilidades de dañar primero y prisa hasta el final del turno. (Hace daño de combate antes que las criaturas sin la habilidad de dañar primero y puede atacar y {T} tan pronto como entra bajo tu control.) Altar Golem|Gólem del altar|Criatura artefacto — Gólem|Arrolla.\nTanto la fuerza como la resistencia de Gólem del altar son iguales al número de criaturas que haya en juego.\nEl Gólem del altar no se endereza durante el paso de enderezar de su controlador.\nGirar cinco criaturas enderezadas que controlas: Endereza el Gólem del altar. -Altar of Bone|Altar de hueso|| -Altar of Dementia|Altar de la demencia|Artefacto|Sacrificar una criatura: El jugador objetivo pone en su cementerio una cantidad de cartas de la parte superior de su biblioteca igual a la fuerza de la criatura sacrificada. +Altar of Bone|Altar de hueso|Conjuro|Como coste adicional para lanzar este hechizo, sacrifica a una criatura.\nBusca en tu biblioteca una carta de criatura, revela esa carta y ponla en tu mano. Luego baraja tu biblioteca. +Altar of Dementia|Altar de la demencia|Artefacto|Sacrifica una criatura: El jugador objetivo pone un número de cartas igual a la fuerza de la criatura sacrificada desde la parte superior de su biblioteca a su cementerio. Altar of Shadows|Altar de sombras|Artefacto|Al comienzo de tu fase principal precombate, agrega {B} a tu reserva de maná por cada contador de carga sobre el Altar de sombras.\n{7}, {T}: Destruye la criatura objetivo. Luego pon un contador de carga sobre el Altar de sombras. Altar of the Brood|Altar de la progenie|Artefacto|Siempre que otro permanente entre al campo de batalla bajo tu control, cada oponente pone la primera carta de su biblioteca en su cementerio. Altar of the Lost|Altar de los perdidos|Artefacto|El Altar de los perdidos entra al campo de batalla girado.\n{T}: Agrega dos maná de cualquier combinación de color a tu reserva de maná. Usa este maná sólo para lanzar hechizos con retrospectiva desde un cementerio. Altar's Light|La luz del altar|Instantáneo|Remueve del juego el artefacto o encantamiento objetivo. Altar's Reap|Cosecha del altar|Instantáneo|Como coste adicional para lanzar la Cosecha del altar, sacrifica una criatura.Roba dos cartas. +Alter Fate|Alterar el destino|Conjuro — Aventura|Regresa la carta de criatura objetivo de tu cementerio a tu mano. (Luego, exilia esta carta. Puedes lanzar la criatura más adelante desde el exilio.) Alter Reality|Modificar la realidad|Instantáneo|Cambia el texto del permanente o hechizo objetivo reemplazando todas las referencias a un color por otro. (Este efecto no termina al final del turno.)\nRetrospectiva {1}{U}. (Puedes jugar esta carta desde tu cementerio pagando su coste de retrospectiva. Luego remuévela del juego.) Altered Ego|Ego alterado|Criatura — Metamorfo|El Ego alterado no puede ser contrarrestado.\nPuedes hacer que el Ego alterado entre al campo de batalla como una copia de cualquier criatura en el campo de batalla, salvo que entra con X contadores +1/+1 adicionales sobre él. -Aluren|Pasajes encantados|| +Aluren|Pasajes encantados|Encantamiento|Cualquier jugador puede lanzar hechizos de criaturas con coste de maná convertido 3 o menos sin pagar su coste de maná y como si tuvieran la habilidad de destello. Always Watching|Siempre alerta|Encantamiento|Las criaturas que no sean fichas que controlas obtienen +1/+1 y tienen la habilidad de vigilancia. Amaranthine Wall|Muro amarantino|Criatura artefacto — Muro|Defensor.\n{2}: El Muro amarantino gana la habilidad de indestructible hasta el final del turno. (El daño y los efectos que dicen "destruir" no lo destruyen.) Amass the Components|Reunir los componentes|Conjuro|Roba tres cartas, luego pon una carta de tu mano en el fondo de tu biblioteca. Ambassador Laquatus|Embajador Laquatus|Criatura legendaria — Hechicero tritón|{3}: El jugador objetivo pone las tres primeras cartas de su biblioteca en su cementerio. Ambassador Oak|Roble embajador|Criatura — Guerrero pueblo-arbóreo|Cuando el Roble embajador entre en juego, pon en juego una ficha de criatura Guerrero Elfo verde 1/1. -Amber Prison|Prisión de ámbar|| +Amber Prison|Prisión de ámbar|Artefacto|Puedes elegir no enderezar a la Prisión de ámbar durante su paso de enderezar.\n{4}, {T}:Gira el artefacto, criatura o tierra objetivo. Ese permanente no se enderezará durante el paso de enderezar del jugador que lo controla mientras la Prisión de ámbar permanezca girado. Ambition's Cost|El precio de la ambición|Conjuro|Roba tres cartas y pierde tres vidas. Ambitious Aetherborn|Etergénito ambicioso|Criatura — Artífice etergénito|Fabricar 1. (Cuando esta criatura entre al campo de batalla, pon un contador +1/+1 sobre ella o crea una ficha de criatura artefacto Servo incolora 1/1.) Ambuscade Shaman|Chamán de la emboscada|Criatura — Chamán orco|Siempre que el Chamán de la emboscada u otra criatura entre al campo de batalla bajo tu control, esa criatura obtiene +2/+2 hasta el final del turno.\nRapidez {3}{B}. (Puedes lanzar este hechizo por su coste de rapidez. Si lo haces, gana la habilidad de prisa y regresa del campo de batalla a la mano de su propietario al comienzo del próximo paso final.) Ambuscade|Asechanza|Instantáneo|La criatura objetivo que controlas obtiene +1/+0 hasta el final del turno. Hace una cantidad de daño igual a su fuerza a la criatura objetivo que controla un oponente. -Ambush Commander|Comandante de Emboscada|| +Ambush Commander|Comandante de Emboscada|Criatura — Elfo|Los bosques que controlas son criaturas Elfo verde 1/1 que siguen siendo tierras.\n{1}{G}, sacrificar un Elfo: La criatura objetivo obtiene +3/+3 hasta el final del turno. Ambush Krotiq|Krotiq emboscador|Criatura — Insecto|Arrolla.\nCuando el Krotiq emboscador entre al campo de batalla, regresa otra criatura que controlas a la mano de su propietario. -Ambush Party|Banda emboscada|| +Ambush Party|Banda emboscada|Criatura - Pícaro humano|Daña primero, prisa Ambush Viper|Víbora emboscadora|Criatura — Víbora|Destello. (Puedes lanzar este hechizo en cualquier momento en que pudieras lanzar un instantáneo.)\nToque mortal. (Cualquier cantidad de daño que esto haga a una criatura es suficiente para destruirla.) -Ambush|Emboscada|| +Ambush|Emboscada|Instantáneo|Las criaturas que bloquean reciben la habilidad daña primero hasta el final del turno. Aminatou's Augury|Augurio de Aminatou|Conjuro|Exilia las ocho primeras cartas de tu biblioteca. Puedes poner en el campo de batalla una carta de tierra que se encuentre entre ellas. Hasta el final del turno, por cada tipo de carta que no sea tierra, puedes lanzar una carta de ese tipo de entre las cartas exiliadas sin pagar su coste de maná. Aminatou, the Fateshifter|Aminatou, la Alteradestinos|Planeswalker legendario — Aminatou|+1: Roba una carta, luego pon una carta de tu mano en la parte superior de tu biblioteca.\n−1: Exilia otro permanente objetivo del cual eres propietario, luego regrésalo al campo de batalla bajo tu control.\n−6: Elige izquierda o derecha. Cada jugador gana el control de todos los permanentes que no sean tierra y que no sean Aminatou, la Alteradestinos controlados por el siguiente jugador en la dirección elegida.\nAminatou, la Alteradestinos puede ser tu comandante. Ammit Eternal|Eterno ammit|Criatura — Demonio cocodrilo zombie|Afligir 3. (Siempre que esta criatura sea bloqueada, el jugador defensor pierde 3 vidas.)\nSiempre que un oponente lance un hechizo, pon un contador -1/-1 sobre el Eterno ammit.\nSiempre que el Eterno ammit haga daño de combate a un jugador, remueve todos los contadores -1/-1 que haya sobre él. Amoeboid Changeling|Cambiaformas ameboide|Criatura — Metamorfo|Cambiaformas. (Esta carta es de todos los tipos de criatura en todo momento.)\n{T}: La criatura objetivo gana todos los tipos de criatura hasta el final del turno.\n{T}: La criatura objetivo pierde todos los tipos de criatura hasta el final del turno. -Amok|Locura temporal|| +Amok|Locura temporal|Encantamiento|{1}, Descarta una carta al azar: Pon un contador +1/+1 en la criatura objetivo. Amorphous Axe|Hacha amorfa|Artefacto — Equipo|La criatura equipada obtiene +3/+0 y es de todos los tipos de criatura.\nEquipar {3}. -Amphibious Kavu|Kavu anfibio|| +Amphibious Kavu|Kavu anfibio|Criatura — Kavu|Siempre que el Kavu anfibio bloquee o sea bloqueado por una o más criaturas azules y/o negras, el Kavu anfibio obtiene +3/+3 hasta el final del turno. Amphin Cutthroat|Degollador anfino|Criatura — Bribón salamandra| Amphin Pathmage|Mago alternativo anfino|Criatura — Hechicero salamandra|{2}{U}: La criatura objetivo no puede ser bloqueada este turno. Amplifire|Amplifuego|Criatura — Elemental|Al comienzo de tu mantenimiento, muestra las primeras cartas de tu biblioteca hasta que muestres una carta de criatura. Hasta tu próximo turno, la fuerza base del Amplifuego se convierte en el doble de la fuerza de esa carta y su resistencia base se convierte en el doble de la resistencia de esa carta. Pon las cartas mostradas en el fondo de tu biblioteca en un orden aleatorio. Ampryn Tactician|Estratega amprynio|Criatura — Soldado humano|Cuando el Estratega amprynio entre al campo de batalla, las criaturas que controlas obtienen +1/+1 hasta el final del turno. -Amrou Kithkin|Kitkin Amrou|| +Amrou Kithkin|Kitkin Amrou|Criatura — Kithkin|Amrou Kithkin no puede ser bloqueado por criaturas con fuerza de 3 o superior. Amrou Scout|Exploradora de Amrou|Criatura — Explorador rebelde kithkin|{4}, {T}: Busca en tu biblioteca una carta de Rebelde con coste de maná convertido de 3 o menos y ponla en juego. Luego baraja tu biblioteca. Amrou Seekers|Buscadores de Amrou|Criatura — Rebelde kithkin|Los Buscadores de Amrou no pueden ser bloqueados excepto por criaturas artefacto y/o criatura blancas. Amugaba|Amugaba|Criatura — Ilusión|Vuela.\n{2}{U}, descartar una carta de tu mano: Regresa el Amugaba a la mano de su propietario. -Amulet of Kroog|Amuleto de Kroog|| +Amulet of Kroog|Amuleto de Kroog|Artefacto|{2}, {T}: Evita el siguiente daño de 1 que sería infligido a cualquier objetivo en este turno. Amulet of Quoz|Amuleto de Quoz|| Amulet of Safekeeping|Amuleto de custodia|Artefacto|Siempre que seas objetivo de un hechizo o habilidad que controla un oponente, contrarresta ese hechizo o habilidad a menos que su controlador pague {1}.\nLas fichas de criatura obtienen -1/-0. -Amulet of Unmaking|Amuleto de disgregación|| +Amulet of Unmaking|Amuleto de disgregación|Artefacto|{5}, {T}, Exilia el Amuleto de disgregación: Exilia el artefacto, criatura o tierra objetivo. Activa esta habilidad sólo cuando puedas lanzar un conjuro. Amulet of Vigor|Amuleto de vigor|Artefacto|Siempre que un permanente entre al campo de batalla girado y bajo tu control, enderézalo. -An-Havva Constable|Alguacil de An-Havva|| -An-Havva Inn|Posada de An-Havva|| -An-Havva Township|Municipio de An-Havva|| -An-Zerrin Ruins|Ruinas de An-Havva|| +An-Havva Constable|Alguacil de An-Havva|Criatura — Humano|La resistencia del Alguacil de An-Havva es igual a 1 más el número de criaturas verdes en juego. +An-Havva Inn|Posada de An-Havva|Conjuro|Ganas X más 1 vida, donde X es el número de criaturas verdes en juego. +An-Havva Township|Municipio de An-Havva|Tierra|{T}: Agrega {C}.\n{1}, {T}: Agrega {G}.\n{2}, {T}: Agrega {R} o {W}. +An-Zerrin Ruins|Ruinas de An-Zerrin|Encantamiento|Cuando las Ruinas de An-Zerrin entren en juego, elige un tipo de criatura.\nLas criaturas del tipo elegido no se enderezan durante los pasos de enderezar de sus controladores. Ana Battlemage|Mago de guerra Ana|Criatura — Hechicero humano|Estímulo {2}{U} y/o {1}{B}.\nCuando el Mago de guerra Ana entre en juego, si se pagó el coste de estímulo {2}{U}, el jugador objetivo descarta tres cartas.\nCuando el Mago de guerra Ana entre en juego, si se pagó el coste de estímulo {1}{B}, gira la criatura objetivo enderezada y esa criatura hace una cantidad de daño igual a su fuerza a su controlador. -Ana Disciple|Discípulo Ana|| -Ana Sanctuary|Santuario Ana|| +Ana Disciple|Discípulo Ana|Criatura — Mago humano|{U}, {T}: La criatura objetivo gana la habilidad de volar hasta el final del turno.\n{B}, {T}: La criatura objetivo obtiene -2/-0 hasta el final del turno. +Ana Sanctuary|Santuario Ana|Encantamiento|Al comienzo de tu mantenimiento, si controlas un permanente azul o negro, la criatura objetivo obtiene +1/+1 hasta el final del turno. Si controlas un permanente azul y un permanente negro, esa criatura obtiene +5/+5 hasta el final del turno. Anaba Ancestor|Ancestro Anaba|| Anaba Bodyguard|Guardaespaldas de Anaba|Criatura — Minotauro|Daña primero. (Esta criatura hace daño de combate antes que las criaturas sin la habilidad de dañar primero.) Anaba Shaman|Chamán de Anaba|Criatura — Chamán minotauro|{R}, {T}: El Chamán de Anaba hace 1 punto de daño a la criatura o jugador objetivo. -Anaba Spirit Crafter|Animista de Anaba|| +Anaba Spirit Crafter|Animista de Anaba|Criatura — Minotauro chamán|Las criaturas Minotauro obtienen +1/+0. Anaconda|Anaconda|Criatura — Víbora|Cruza pantanos. (Esta criatura es imbloqueable mientras el jugador defensor controle un pantano.) Anafenza, Kin-Tree Spirit|Anafenza, espíritu del árbol familiar|Criatura legendaria — Espíritu soldado|Siempre que otra criatura que no sea ficha entre al campo de batalla bajo tu control, fortalece 1. (Elige la criatura con menor resistencia entre las criaturas que controlas y pon un contador +1/+1 sobre ella.) Anafenza, the Foremost|Anafenza, la líder|Criatura legendaria — Soldado humano|Siempre que Anafenza, la líder ataque, pon un contador +1/+1 sobre otra criatura objetivo girada que controlas.\nSi una carta de criatura fuera a ir al cementerio de un oponente desde cualquier parte, en vez de eso, exíliala. Anarchist|Anarquista|Criatura — Ciudadano|Cuando el Anarquista entre en juego, puedes regresar la carta objetivo de conjuro de tu cementerio a tu mano. -Anarchy|Anarquía|| +Anarchy|Anarquía|Conjuro|Destruye todos los permanentes blancos. Anathemancer|Anatemante|Criatura — Hechicero zombie|Cuando el Anatemante entre en juego, le hace daño al jugador objetivo igual a la cantidad de tierras no básicas que controla ese jugador.\nDesenterrar {5}{B}{R}. ({5}{B}{R}: Regresa esta carta de tu cementerio al juego. Gana la habilidad de prisa. Remuévela del juego al final del turno o si fuera a dejar el juego. Desentierra sólo como un conjuro.) -Anavolver|Anavolver|| +Anavolver|Anavolver|Criatura — Volver|Estímulo {1}{U} y/o {B} (Puedes pagar {1}{U} y/o {B} adicionales al lanzar este hechizo.)\nSi Anavolver fue estimulado con el estímulo {1}{U}, entra en juego con dos contadores +1/+1 y con la habilidad de volar.\nSi Anavolver fue estimulado con el estímulo {B}, entra en juego con un contador +1/+1 sobre él y con "Pagar 3 vidas: Regenerar Anavolver". Anax and Cymede|Anax y Cymeda|Criatura legendaria — Soldado humano|Daña primero, vigilancia.\nHeroísmo — Siempre que lances un hechizo que haga objetivo a Anax y Cymeda, las criaturas que controlas obtienen +1/+1 y ganan la habilidad de arrollar hasta el final del turno. Ancestor's Chosen|Elegido de la Antepasada|Criatura — Clérigo humano|Daña primero. (Esta criatura hace daño de combate antes que las criaturas sin la habilidad de dañar primero.)\nCuando el Elegido de la Antepasada entre en juego, ganas 1 vida por cada carta en tu cementerio. Ancestor's Prophet|Profeta de la Antepasada|Criatura — Señor clérigo|Girar cinco Clérigos enderezados que controles: Gana 10 vidas. Ancestral Blade|Filo ancestral|Artefacto — Equipo|Cuando el Filo ancestral entre al campo de batalla, crea una ficha de criatura Soldado blanca 1/1 y luego anéxale el Filo ancestral.\nLa criatura equipada obtiene +1/+1.\nEquipar {1}. ({1}: Anexa este Equipo a la criatura objetivo que controlas. Activa la habilidad de equipar como un conjuro.) -Ancestral Knowledge|Conocimiento ancestral|| -Ancestral Mask|Máscara ancestral|| -Ancestral Memories|Bendición angélica|| +Ancestral Knowledge|Conocimiento ancestral|Encantamiento|Mantenimiento acumulativo {1} (Al comienzo de tu mantenimiento, pon un contador de edad en este permanente, luego sacrifícalo a menos que pagues su coste de mantenimiento por cada contador de edad en él.)\nCuando el Conocimiento ancestral entre en juego, mira las diez cartas superiores de tu biblioteca, luego exilia a cualquier número de ellas y vuelve a poner el resto encima de tu biblioteca en cualquier orden.\nCuando el Conocimiento ancestral abandone el juego, baraja tu biblioteca. +Ancestral Mask|Máscara ancestral|Encantamiento — Aura|Encantar criatura\nLa criatura encantada recibe +2/+2 por cada uno de los otros encantamientos en juego. +Ancestral Memories|Bendición angélica|Conjuro|Mira las siete cartas superiores de tu biblioteca. Pon dos de ellas en tu mano y el resto en tu cementerio. Ancestral Statue|Estatua ancestral|Criatura artefacto — Gólem|Cuando la Estatua ancestral entre al campo de batalla, regresa un permanente que controlas y que no sea tierra a la mano de su propietario. Ancestral Tribute|Tributo ancestral|Conjuro|Gana 2 vidas por cada carta que haya en tu cementerio.\nRetrospectiva {9}{W}{W}{W}. (Puedes jugar esta carta desde tu cementerio pagando su coste de retrospectiva. Luego remuévela del juego.) Ancestral Vengeance|Venganza ancestral|Encantamiento — Aura|Encantar criatura.\nCuando la Venganza ancestral entre al campo de batalla, pon un contador +1/+1 sobre la criatura objetivo que controlas.\nLa criatura encantada obtiene -1/-1. @@ -447,36 +448,36 @@ Ancient Brontodon|Brontodón anciano|Criatura — Dinosaurio| Ancient Carp|Carpa primigenia|Criatura — Pez| Ancient Crab|Cangrejo antiguo|Criatura — Cangrejo| Ancient Craving|Anhelo antiguo|Conjuro|Robas tres cartas y pierdes 3 vidas. -Ancient Den|Guarida antigua|Tierra artefacto|(Ancient Den isn't a spell.)\n{T}: Agrega {W} a tu reserva de maná. +Ancient Den|Guarida antigua|Tierra artefacto|(La Guarida antigua no es un hechizo.)\n{T}: Agrega {W} a tu reserva de maná. Ancient Excavation|Excavación antigua|Instantáneo|Roba una cantidad de cartas igual a la cantidad de cartas en tu mano, luego descarta una carta por cada carta robada de esta manera.\nCiclo de tierras básicas {2}. ({2}, descartar esta carta: Busca en tu biblioteca una carta de tierra básica, muéstrala y ponla en tu mano. Luego baraja tu biblioteca.) Ancient Grudge|Agravio antiguo|Instantáneo|Destruye el artefacto objetivo.\nRetrospectiva {G} (Puedes jugar esta carta desde tu cementerio pagando su coste de retrospectiva. Luego remuévela del juego.) Ancient Hellkite|Engendro anciano|Criatura — Dragón|Vuela.\n{R}: El Engendro anciano hace 1 punto de daño a la criatura objetivo que controla el jugador defensor. Activa esta habilidad sólo si el Engendro anciano está atacando. -Ancient Hydra|Hidra antigua|| -Ancient Kavu|Kavu Antiguo|| +Ancient Hydra|Hidra antigua|Criatura — Hidra|Desaparecer 5 (Esta criatura entra en juego con cinco contadores de desaparecer. Al comienzo de tu mantenimiento, elimina un contador de desaparecer de ella. Si no puedes, sacrifícala.)\n{1}, Elimina un contador de desaparecer de la Hidra Antigua: inflige 1 de daño a cualquier objetivo. +Ancient Kavu|Kavu Antiguo|Criatura — Kavu|{2}: El Kabu Antiguo se vuelve incoloro hasta el final del turno. Ancient Ooze|Cieno antiguo|Criatura — Cieno|Tanto la fuerza como la resistencia del Cieno antiguo son iguales al coste total de maná convertido de las demás criaturas que controles. -Ancient Runes|Runas antiguas|| +Ancient Runes|Runas antiguas|Encantamiento|Al comienzo del mantenimiento de cada jugador, las Runas antiguas infligen daño a ese jugador igual al número de artefactos que controlan. Ancient Silverback|Lomo plateado antiguo|Criatura — Simio|{G}: Regenera al Lomo plateado antiguo. (La próxima vez que esta criatura fuera a ser destruida este turno, no lo es. En vez de eso, gírala, remueve todo el daño de ella y remuévela del combate.) -Ancient Spider|Araña antigua|| -Ancient Spring|Manantial Antiguo|| +Ancient Spider|Araña antigua|Criatura — Araña|Daña primero; alcance (Esta criatura puede bloquear a criaturas con la habilidad de volar.) +Ancient Spring|Manantial Antiguo|Tierra|El Manantial Antiguo entra en juego girado.\n{T}: Agrega {U}.\n{T}, Sacrifica el Manantial Antiguo: Agrega {W}{B}. Ancient Stirrings|Agitamiento antiguo|Conjuro|Mira las primeras cinco cartas de tu biblioteca. Puedes mostrar una carta incolora que se encuentre entre ellas y ponerla en tu mano. Luego pon el resto en el fondo de tu biblioteca en cualquier orden. (Las cartas sin coste de maná de color en sus costes de maná son incoloras. Las tierras también son incoloras.) Ancient Stone Idol|Ídolo de piedra antiguo|Criatura artefacto — Gólem|Destello.\nTe cuesta {1} menos lanzar este hechizo por cada criatura atacante.\nArrolla.\nCuando el Ídolo de piedra antiguo muera, crea una ficha de criatura artefacto Constructo incolora 6/12 con la habilidad de arrollar. -Ancient Tomb|Tumba antigua|| +Ancient Tomb|Tumba antigua|Tierra|{T}: Agrega {C}{C}. La Tumba antigua te inflinge 2 de daño. Ancient Ziggurat|Ziggurat antiguo|Tierra|{T}: Agrega un maná de cualquier color a tu reserva de maná. Usa este maná sólo para jugar hechizos de criatura. Ancient of the Equinox|Ancestro del equinoccio|Criatura — Pueblo-arbóreo|Arrolla, antimaleficio. -Andradite Leech|Sanguijuela Andradita|| +Andradite Leech|Sanguijuela Andradita|Criatura — Sanguijuela|Los hechizos negros que lances cuestan {B} más.\n{B}: La Sanguijuela Andradita recibe +1/+1 hasta el final del turno. Angel of Condemnation|Ángel de la condenación|Criatura — Ángel|Vuela, vigilancia.\n{2}{W}, {T}: Exilia otra criatura objetivo. Regresa esa carta al campo de batalla bajo el control de su propietario al comienzo del próximo paso final.\n{2}{W}, {T}, espolear al Ángel de la condenación: Exilia otra criatura objetivo hasta que el Ángel de la condenación deje el campo de batalla. (Una criatura espoleada no se enderezará durante tu próximo paso de enderezar.) Angel of Deliverance|Ángel de la liberación|Criatura — Ángel|Vuela.\nDelirio — Siempre que el Ángel de la liberación haga daño, si entre las cartas de tu cementerio hay cuatro o más tipos de carta, exilia la criatura objetivo que controla un oponente. Angel of Despair|Ángel de desesperación|Criatura — Ángel|Vuela.\nCuando el Ángel de desesperación entre al campo de batalla, destruye el permanente objetivo. Angel of Finality|Ángel de irrevocabilidad|Criatura — Ángel|Vuela. Cuando el Ángel de irrevocabilidad entre al campo de batalla, exilia todas las cartas del cementerio del jugador objetivo. Angel of Flight Alabaster|Ángel de la Legión Alabastro|Criatura — Ángel|Vuela.\nAl comienzo de tu mantenimiento, regresa la carta de Espíritu objetivo de tu cementerio a tu mano. -Angel of Fury|Ángel de furia|| +Angel of Fury|Ángel de furia|Criature — Ángel|Vuela\nCuando el Ángel de furia muera, puedes mezclarlo en la biblioteca de su dueño. Angel of Glory's Rise|Ángel del ascenso de la gloria|Criatura — Ángel|Vuela.\nCuando el Ángel del ascenso de la gloria entre al campo de batalla, exilia a todos los Zombies, luego regresa al campo de batalla todas las cartas de criatura Humano de tu cementerio. Angel of Grace|Ángel de la gracia|Criatura — Ángel|Destello.\nVuela.\nCuando el Ángel de la gracia entre al campo de batalla, hasta el final del turno, el daño que fuera a reducir tu total de vidas a menos de 1, en vez de eso, lo reduce a 1.\n{4}{W}{W}, exiliar al Ángel de la gracia de tu cementerio: Tu total de vidas se convierte en 10. Angel of Invention|Ángel de la invención|Criatura — Ángel|Vuela, vigilancia, vínculo vital.\nFabricar 2. (Cuando esta criatura entre al campo de batalla, pon dos contadores +1/+1 sobre ella o crea dos fichas de criatura artefacto Servo incoloras 1/1.)\nLas otras criaturas que controlas obtienen +1/+1. Angel of Jubilation|Ángel del júbilo|Criatura — Ángel|Vuela.\nLas otras criaturas que controlas que no sean negras obtienen +1/+1.\nLos jugadores no pueden pagar vidas ni sacrificar criaturas para lanzar hechizos ni para activar habilidades. -Angel of Mercy|Angel de Piedad|| +Angel of Mercy|Angel de Piedad|Criatura — Ángel|Vuela\nCuando el Ángel de Piedad entra en juego, ganas 3 vidas. Angel of Renewal|Ángel de la renovación|Criatura — Ángel aliado|Vuela.Cuando el Ángel de la renovación entre al campo de batalla, ganas 1 vida por cada criatura que controlas. -Angel of Retribution|Ángel de Castigo|| +Angel of Retribution|Ángel de Castigo|Criatura — Ángel|Vuela, daña primero Angel of Salvation|Ángel de salvación|Criatura — Ángel|Destello; convocar (Cada criatura que gires al jugar este hechizo reduce su coste en {1} o en un maná del color de esa criatura)
Vuela.
Cuando el Ángel de salvación entre en juego, prevén los siguientes 5 puntos de daño que se le fuera a hacer este turno a cualquier número de criaturas y/o jugadores objetivo, dividido como elijas. Angel of Sanctions|Ángel de las condenas|Criatura — Ángel|Vuela.\nCuando el Ángel de las condenas entre al campo de batalla, puedes exiliar el permanente objetivo que no sea tierra que controle un oponente hasta que el Ángel de las condenas deje el campo de batalla.\nEmbalsamar {5}{W}. ({5}{W}, exiliar esta carta de tu cementerio: Crea una ficha que es una copia de esta carta, excepto que es un Ángel Zombie blanco sin coste de maná. Activa la habilidad de embalsamar solo como un conjuro.) Angel of Serenity|Ángel de serenidad|Criatura — Ángel|Vuela.Cuando el Ángel de serenidad entre al campo de batalla, puedes exiliar hasta otras tres criaturas del campo de batalla y/o cartas de criatura objetivo de los cementerios.Cuando el Ángel de serenidad deje el campo de batalla, regresa las cartas exiliadas a las manos de sus propietarios. @@ -489,30 +490,30 @@ Angel's Grace|Gracia del ángel|Instantáneo|Fracción de segundo (Mientras este Angel's Herald|Heraldo del ángel|Criatura — Clérigo humano|{2}{W}, {T}, sacrificar una criatura verde, una criatura blanca y una criatura azul: Busca en tu biblioteca una carta llamada Arcángel empíreo y ponla en juego. Luego baraja tu biblioteca. Angel's Mercy|Piedad del ángel|Instantáneo|Gana 7 vidas. Angel's Tomb|Tumba del ángel|Artefacto|Siempre que una criatura entre al campo de batalla bajo tu control, puedes hacer que la Tumba del ángel se convierta en una criatura artefacto Ángel blanca 3/3 con la habilidad de volar hasta el final del turno. -Angel's Trumpet|Trompeta de ángeles|| -Angelfire Crusader|Cruzado fuegoangelico|| +Angel's Trumpet|Trompeta de ángeles|Artefacto|Todas las criaturas tienen vigilancia.\nAl principio del paso final de cada jugador, gira todas las criaturas enderezadas que el jugador controle y que no hayan atacado este turno. La Trompeta de Ángeles inflige un daño al jugador igual al número de criaturas giradas de esta manera. +Angelfire Crusader|Cruzado fuegoangélico|Criatura — Caballero humano|{R}: El Cruzado fuegoangélico obtiene +1/+0 hasta el final del turno. Angelheart Vial|Frasco corazón de ángel|Artefacto|Siempre que recibas daño, puedes poner esa misma cantidad de contadores de carga sobre el Frasco corazón de ángel.\n{2}, {T}, remover cuatro contadores de carga del Frasco corazón de ángel: Gana 2 vidas y roba una carta. Angelic Accord|Acuerdo angelical|Encantamiento|Al comienzo de cada paso final, si has ganado 4 o más vidas este turno, pon en el campo de batalla una ficha de criatura Ángel blanca 4/4 con la habilidad de volar. Angelic Arbiter|Árbitro angelical|Criatura — Ángel|Vuela.\nCada oponente que lanzó un hechizo este turno no puede atacar con criaturas.\nCada oponente que atacó con una criatura este turno no puede lanzar hechizos. Angelic Armaments|Armamento angelical|Artefacto — Equipo|La criatura equipada obtiene +2/+2, tiene la habilidad de volar, y es un Ángel blanco además de sus otros colores y tipos.\nEquipar {4}. Angelic Benediction|Reconocimiento angelical|Encantamiento|Exaltado. (Siempre que una criatura que controlas ataque sola, esa criatura obtiene +1/+1 hasta el final del turno.)\nSiempre que una criatura que controles ataque sola, puedes girar la criatura objetivo. -Angelic Blessing|Bendicion angelica|| +Angelic Blessing|Bendición angélica|Conjuro|La criatura objetivo obtiene +3/+3 y gana la habilidad de volar hasta el final del turno. (No puede ser bloqueado excepto por criaturas que tengan la habilidad de volar o alcance.) Angelic Captain|Capitana angelical|Criatura — Ángel aliado|Vuela.Siempre que la Capitana angelical ataque, obtiene +1/+1 hasta el final del turno por cada otro Aliado atacante. Angelic Chorus|Coro angélico|Encantamiento|Siempre que una criatura entre en juego bajo tu control, ganas una cantidad de vida igual a su resistencia. -Angelic Curator|Conservador angélico|| +Angelic Curator|Conservador angélico|Criatura - Ángel Espíritu|Vuela, protección de artefactos Angelic Destiny|Destino angélico|Encantamiento — Aura|Encantar criatura.\nLa criatura encantada obtiene +4/+4, tiene las habilidades de volar y dañar primero y es un Ángel además de sus otros tipos.\nCuando la criatura encantada muera, regresa el Destino angélico a la mano de su propietario. Angelic Edict|Edicto angelical|Conjuro|Exilia la criatura o encantamiento objetivo. Angelic Exaltation|Exaltación angélica|Encantamiento|Siempre que una criatura que controlas ataque sola, obtiene +X/+X hasta el final del turno, donde X es la cantidad de criaturas que controlas. -Angelic Favor|Servicio angelical|| +Angelic Favor|Servicio angelical|Instantáneo|Si controlas una Llanura, puedes girar una criatura enderezada que controlas en lugar de pagar el coste de maná de este hechizo.\nLanza este hechizo sólo durante el combate.\nCrea una ficha criatura Ángel blanco 4/4 con la habilidad de vuelo. Exílialo al principio del siguiente paso final. Angelic Field Marshal|Mariscal de campo angelical|Criatura — Ángel|Vuela.\nTeniente — Mientras controles a tu comandante, la Mariscal de campo angelical obtiene +2/+2 y las criaturas que controlas tienen la habilidad de vigilancia. Angelic Gift|Don angelical|Encantamiento — Aura|Encantar criatura.Cuando el Don angelical entre al campo de batalla, roba una carta.La criatura encantada tiene la habilidad de volar. Angelic Guardian|Guardiana angelical|Criatura — Ángel|Vuela. (Esta criatura no puede ser bloqueada excepto por criaturas que tengan la habilidad de volar o alcance.)\nSiempre que una o más criaturas que controlas ataquen, ganan la habilidad de indestructible hasta el final del turno.(El daño y los efectos que dicen "destruye" no las destruyen.) Angelic Overseer|Supervisora angélica|Criatura — Ángel|Vuela.\nMientras controles un Humano, la Supervisora angélica tiene antimaleficio y es indestructible. Angelic Page|Paje angélico|Criatura — Espíritu|Vuela. (Esta criatura no puede ser bloqueada excepto por criaturas que tengan la habilidad de volar.)\n{T}: La criatura atacante o bloqueadora objetivo obtiene +1/+1 hasta el final del turno. -Angelic Protector|Protector angelical|| +Angelic Protector|Protector angelical|Criatura — Ángel|Vuela\nSiempre que el Protector angelical se convierta en el objetivo de un hechizo o habilidad, el Protector angelical obtiene +0/+3 hasta el final del turno. Angelic Purge|Purga angelical|Conjuro|Como coste adicional para lanzar la Purga angelical, sacrifica un permanente.\nExilia el artefacto, criatura o encantamiento objetivo. -Angelic Renewal|Renovación angélica|| -Angelic Shield|Escudo Angélico|| +Angelic Renewal|Renovación angélica|Encantamiento|Cada vez que una criatura es puesta en tu cementerio desde el juego, puedes sacrificar la Renovación angélica. Si lo haces, devuelve esa carta al juego. +Angelic Shield|Escudo Angélico|Encantamiento|Las criaturas que controlas obtienen +0/+1.\nSacrifica al Escudo Angélico: Devuelve la criatura objetivo a la mano de su dueño. Angelic Skirmisher|Escaramuzadora angélica|Criatura — Ángel|Vuela.Al comienzo de cada combate, elige entre las habilidades de dañar primero, vigilancia o vínculo vital. Las criaturas que controlas ganan esa habilidad hasta el final del turno. Angelic Wall|Muro angelical|Criatura — Muro|(Los Muros no pueden atacar.)\nVuela. Angelsong|Canción angelical|Instantáneo|Prevén todo el daño de combate que se fuera a hacer este turno.\nCiclo {2}. ({2}, descartar esta carta: Roba una carta.) @@ -526,21 +527,21 @@ Angrath's Rampage|Estragos de Angrath|Conjuro|Elige uno:\n• El jugador objetiv Angrath, Captain of Chaos|Angrath, Capitán del Caos|Planeswalker legendario — Angrath|Las criaturas que controlas tienen la habilidad de amenaza.\n−2: Enrola 2. (Pon dos contadores +1/+1 sobre un Ejército que controlas. Si no controlas ninguno, crea primero una ficha de criatura Ejército Zombie negra 0/0.) Angrath, Minotaur Pirate|Angrath, pirata minotauro|Planeswalker legendario — Angrath|+2: Angrath, pirata minotauro hace 1 punto de daño al oponente objetivo y a cada criatura que controla ese jugador.\n−3: Regresa la carta de Pirata objetivo de tu cementerio al campo de batalla.\n−11: Destruye todas las criaturas que controla el oponente objetivo. Angrath, pirata minotauro hace daño a ese jugador igual a su fuerza total. Angrath, the Flame-Chained|Angrath, el de las Cadenas Ardientes|Planeswalker legendario — Angrath|+1: Cada oponente descarta una carta y pierde 2 vidas.\n−3: Gana el control de la criatura objetivo hasta el final del turno. Enderézala. Gana la habilidad de prisa hasta el final del turno. Sacrifícala al comienzo del próximo paso final si tiene un coste de maná convertido de 3 o menos.\n−8: Cada oponente pierde una cantidad de vidas igual a la cantidad de cartas en su cementerio. -Angry Mob|Turba|| +Angry Mob|Turba|Criatura — Humano|Arrolla\nMientras sea tu turno, tanto la fuerza como la resistencia de la Turba son iguales a 2 más el número de Pantanos que controlan tus oponentes. Mientras no sea tu turno, tanto la fuerza como la resistencia de la Turba es igual a 2. Anguished Unmaking|Fin angustioso|Instantáneo|Exilia el permanente objetivo que no sea tierra. Pierdes 3 vidas. Animal Boneyard|Cementerio de animales|Encantar tierra|La tierra encantada tiene: "{T}, sacrificar una criatura: Gana una cantidad de vida igual a la resistencia de esa criatura". Animal Magnetism|Magnetismo animal|Conjuro|Muestra cinco cartas de la parte superior de tu biblioteca. Un oponente elige una carta de criatura de entre ellas. Pon en juego esa carta y el resto en tu cementerio. Animar, Soul of Elements|Ánimar, Alma de los Elementos|Criatura legendaria — Elemental|Protección contra blanco y contra negro.\nSiempre que lances un hechizo de criatura, pon un contador +1/+1 sobre Ánimar, Alma de los Elementos.\nTe cuesta {1} menos lanzar los hechizos de criatura por cada contador +1/+1 sobre Ánimar. -Animate Artifact|Animar artefacto|| -Animate Dead|Animar a los muertos|| -Animate Land|Animar la tierra|| -Animate Wall|Animar muro|| +Animate Artifact|Animar artefacto|Encantamiento — Aura|Encantar artefacto\nMientras que el artefacto encantado no sea una criatura, es una criatura con poder y resistencia cada uno igual a su coste de maná convertido. +Animate Dead|Animar a los muertos|Encantamiento — Aura|Encantar la carta de criatura encantadora en un cementerio\nCuando Animar a los muertos entra en juego, si está en juego, pierde "encantar carta de criatura en un cementerio" y gana "encantar criatura puesta en juego con Animar a los muertos." Devuelve la carta de criatura encantada al juego bajo tu control y adjúntale Animar a los muertos. Cuando Animar a los muertos abandona el juego, el controlador de esa criatura lo sacrifica.\nLa criatura encantada obtiene -1/-0. +Animate Land|Animar la tierra|Instantáneo|Hasta el final del turno, la tierra objetivo se convierte en una criatura 3/3 que sigue siendo una tierra. +Animate Wall|Animar muro|Encantamiento — Aura|Encantar Muro\nEl Muro encantado puede atacar como si no tuviera defensor. Animating Faerie|Hada de la animación|Criatura — Hada|Vuela. Animation Module|Módulo de animación|Artefacto|Siempre que se pongan uno o más contadores +1/+1 sobre un permanente que controlas, puedes pagar {1}. Si lo haces, crea una ficha de criatura artefacto Servo incolora 1/1.\n{3}, {T}: Elige un contador sobre el permanente o el jugador objetivo. Ese permanente o jugador obtiene otro contador del mismo tipo. Animist's Awakening|Despertar de la animista|Conjuro|Muestra las X primeras cartas de tu biblioteca. Pon todas las cartas de tierra que se encuentren entre ellas en el campo de batalla giradas y el resto en el fondo de tu biblioteca en un orden aleatorio.Dominio de hechizos — Si hay dos o más cartas de instantáneo y/o de conjuro en tu cementerio, endereza esas tierras. Anje Falkenrath|Anje Falkenrath|Criatura legendaria — Vampiro|Prisa.\n{T}, descartar una carta: Roba una carta.\nSiempre que descartes una carta, si tiene la habilidad de demencia, endereza a Anje Falkenrath. Anje's Ravager|Devastador de Anje|Criatura — Berserker vampiro|El Devastador de Anje ataca cada combate si puede.\nSiempre que el Devastador de Anje ataque, descarta tu mano, luego roba tres cartas.\nDemencia {1}{R}. (Si descartas esta carta, exíliala. Cuando lo hagas, lánzala por su coste de demencia o ponla en tu cementerio.) -Ankh of Mishra|Ankh de Mishra|| +Ankh of Mishra|Ankh de Mishra|Artefacto|Cada vez que una tierra entra en juego, Ankh de Mishra inflige 2 puntos de daño al controlador de esa tierra. Ankle Shanker|Tobillero|Criatura — Berserker trasgo|Prisa.\nSiempre que el Tobillero ataque, las criaturas que controlas ganan las habilidades de dañar primero y toque mortal hasta el final del turno. Annex|Anexar|Encantamiento — Aura|Encantar tierra. (Haz objetivo a una tierra al jugarlo. Esta carta entra en juego anexada a esa tierra.)\nTú controlas la tierra encantada. Annihilate|Aniquilar|Instantáneo|Destruye la criatura objetivo que no sea negra. No puede ser regenerada.Roba una carta. @@ -551,15 +552,15 @@ Anointed Deacon|Diácono ungido|Criatura — Clérigo vampiro|Al comienzo del co Anointed Procession|Procesión de ungidos|Encantamiento|Si un efecto fuera a crear una o más fichas bajo tu control, en vez de eso, crea el doble de esas fichas. Anointer Priest|Sacerdotisa ungidora|Criatura — Clérigo humano|Siempre que una ficha de criatura entre al campo de batalla bajo tu control, ganas 1 vida.\nEmbalsamar {3}{W}. ({3}{W}, exiliar esta carta de tu cementerio: Crea una ficha que es una copia de esta carta, excepto que es un Clérigo Humano Zombie blanco sin coste de maná. Activa la habilidad de embalsamar solo como un conjuro.) Anointer of Champions|Proclamadora de campeones|Criatura — Clérigo humano|{T}: La criatura atacante objetivo obtiene +1/+1 hasta el final del turno. -Anoint|Untar|| +Anoint|Untar|Instantáneo|Recuperar {3} (Puedes pagar {3} adicionales al lanzar este hechizo. Si lo haces, pon esta carta en tu mano en cuanto se resuelva.)\nEvita los siguientes 3 puntos de daños que se infligirían a la criatura objetivo en este turno. Anowon, the Ruin Sage|Anowon, el Sabio de las Ruinas|Criatura legendaria — Chamán vampiro|Al comienzo de tu mantenimiento, cada jugador sacrifica una criatura que no sea Vampiro. Answered Prayers|Plegarias escuchadas|Encantamiento|Siempre que una criatura entre al campo de batalla bajo tu control, ganas 1 vida. Si las Plegarias escuchadas no son una criatura, se convierten en una criatura Ángel 3/3 con la habilidad de volar además de sus otros tipos hasta el final del turno. Ant Queen|Hormiga reina|Criatura — Insecto|{1}{G}: Pon en el campo de batalla una ficha de criatura Insecto verde 1/1. -Antagonism|Antagonismo|| +Antagonism|Antagonismo|Encantamiento|Al comienzo del paso final de cada jugador, el Antagonismo inflige 2 puntos de daño a ese jugador a menos que uno de sus oponentes haya recibido daño en ese turno. Anthem of Rakdos|Himno de Rakdos|Encantamiento|Siempre que una criatura que controlas ataque, obtiene +2/+0 hasta el final del turno y el Himno de Rakdos te hace 1 punto de daño.\nTemerario Mientras no tengas cartas en la mano, si una fuente que controlas fuera a hacer daño a una criatura o jugador, en vez de eso, hace el doble del daño a esa criatura o jugador. Anthousa, Setessan Hero|Anthousa, heroína setessana|Criatura legendaria — Guerrero humano|Heroísmo — Siempre que lances un hechizo que haga objetivo a Anthousa, heroína setessana, hasta tres tierras objetivo que controlas se convierten cada una en criaturas Guerrero 2/2 hasta el final del turno. Siguen siendo tierras. -Anthroplasm|Antroplasma|| -Anti-Magic Aura|Aura antimagia|| +Anthroplasm|Antroplasma|Criatura — Metamorfo|El Antroplasma entra en juego con dos contadores +1/+1.\n{X}, {T}: Elimina todos los contadores +1/+1 del Antroplasma y ponle X contadores +1/+1 +Anti-Magic Aura|Aura antimagia|Encantamiento — Aura|Encantar criatura\nLa criatura encantada no puede ser el blanco de hechizos y no puede ser encantada por otras Auras. Anticipate|Anticipar|Instantáneo|Mira las tres primeras cartas de tu biblioteca. Pon una de ellas en tu mano y el resto en el fondo de tu biblioteca en cualquier orden. Antler Skulkin|Calaveroso con astas|Criatura artefacto — Espantapájaros|{2}: La criatura blanca objetivo gana la habilidad de persistir hasta el final del turno. (Cuando vaya a un cementerio desde el juego, si no tiene contadores -1/-1 sobre ella, regrésala al juego bajo el control de su propietario con un contador -1/-1.) Anurid Barkripper|Descortezador anuro|Criatura — Bestia|Umbral El Descortezador anuro obtiene +2/+2. (Tienes umbral mientras haya siete o más cartas en tu cementerio.) @@ -567,11 +568,11 @@ Anurid Brushhopper|Saltamaleza anuro|Criatura — Bestia|Descartar dos cartas de Anurid Murkdiver|Anuro de aguaturbia|Criatura — Bestia zombie|Cruza pantanos. Anurid Scavenger|Carroñero anuro|Criatura — Bestia|Protección contra negro.\nAl comienzo de tu mantenimiento, sacrifica el Carroñero anuro a menos que pongas una carta de tu cementerio en la parte inferior de tu biblioteca. Anurid Swarmsnapper|Tragaenjambres anuro|Criatura — Bestia|El Tragaenjambres anuro puede bloquear como si tuviera la habilidad de volar.\n{1}{G}: El Tragaenjambres anuro puede bloquear a una criatura adicional este turno. -Anvil of Bogardan|Yunque de Bogardan|| +Anvil of Bogardan|Yunque de Bogardan|Artefacto|Los jugadores no tienen un tamaño máximo de mano.\nAl principio del paso de cada jugador, ese jugador roba una carta adicional, y luego descarta una carta. Anvilwrought Raptor|Rapaz de metal forjado|Criatura artefacto — Ave|Vuela, daña primero. -Anya, Merciless Angel|Anya, ángel despiadado|Criatura legendaria — Ángel|Vuela.Anya, ángel despiadado obtiene +3/+3 por cada oponente cuyo total de vidas sea menos que la mitad de su total de vidas inicial.Mientras el total de vidas de un oponente sea menos que la mitad de su total de vidas inicial, Anya tiene la habilidad de indestructible. -Apathy|Apatía|| -Apes of Rath|Simios de Rath|| +Anya, Merciless Angel|Anya, ángel despiadado|Criatura legendaria — Ángel|Vuela. Anya, ángel despiadado obtiene +3/+3 por cada oponente cuyo total de vidas sea menos que la mitad de su total de vidas inicial.Mientras el total de vidas de un oponente sea menos que la mitad de su total de vidas inicial, Anya tiene la habilidad de indestructible. +Apathy|Apatía|Encantamiento — Aura|Encantar criatura\nLa criatura encantada no se endereza durante el paso de enderezar de su controlador.\nAl comienzo del mantenimiento del controlador de la criatura encantada, ese jugador puede descartar una carta al azar. Si lo hace, endereza esa criatura. +Apes of Rath|Simios de Rath|Criatura — Simio|Siempre que los Simios de Rath ataquen, no se enderezan durante el siguiente paso de enderezar de su controlador. Apex Altisaur|Altisaurio ejemplar|Criatura — Dinosaurio|Cuando el Altisaurio ejemplar entre al campo de batalla, lucha contra hasta una criatura objetivo que no controlas.\nEnfurecer — Siempre que el Altisaurio ejemplar reciba daño, lucha contra hasta una criatura objetivo que no controlas. Apex Hawks|Halcones del cenit|Criatura — Ave|Multiestímulo {1}{W}. (Puedes pagar {1}{W} adicionales tantas veces como quieras mientras lanzas este hechizo.)\nVuela.\nLos Halcones del cenit entran al campo de batalla con un contador +1/+1 sobre ellos por cada vez que fueron estimulados. Apex of Power|Cúspide del poder|Conjuro|Exilia las siete primeras cartas de tu biblioteca. Hasta el final del turno, puedes lanzar las cartas que no sean tierra exiliadas de esta manera.\nSi este hechizo fue lanzado desde tu mano, agrega diez manás de un color cualquiera. @@ -582,10 +583,10 @@ Aphetto Grifter|Timador de Afetto|Criatura — Hechicero|Girar dos Hechiceros en Aphetto Runecaster|Lanzarrunas de Afeto|Criatura — Hechicero|Siempre que una criatura se ponga boca arriba, puedes robar una carta. Aphetto Vulture|Buitre de Afetto|Criatura — Ave zombie|Vuela.\nCuando el Buitre de Afetto vaya a un cementerio desde el juego, puedes poner la carta objetivo de Zombie de tu cementerio en la parte superior de tu biblioteca. Aphotic Wisps|Centellas afóticas|Instantáneo|La criatura objetivo es negra y gana la habilidad de inspirar temor hasta el final del turno.\nRoba una carta. -Apocalypse Chime|Campana del Apolcalipsis|| +Apocalypse Chime|Campana del Apocalipsis|Artefacto|{2}, {T}, Sacrificar Campana del Apocalipsis: Destruye todos los permanentes que no sean fichas con un nombre originalmente impreso en la expansión Homeland. No pueden ser regenerados. Apocalypse Demon|Demonio del apocalipsis|Criatura — Demonio|Vuela.\nTanto la fuerza como la resistencia del Demonio del apocalipsis son iguales a la cantidad de cartas que haya en tu cementerio.\nAl comienzo de tu mantenimiento, gira el Demonio del apocalipsis a menos que sacrifiques otra criatura Apocalypse Hydra|Hidra del Apocalipsis|Criatura — Hidra|La Hidra del Apocalipsis entra en juego con X contadores +1/+1 sobre ella. Si X es 5 o más, entra en juego con X contadores +1/+1 adicionales sobre ella.\n{1}{R}, remover un contador +1/+1 de la Hidra del Apocalipsis: La Hidra del Apocalipsis hace 1 daño a la criatura o jugador objetivo. -Apocalypse|Apocalipsis|| +Apocalypse|Apocalipsis|Conjuro|Exilia todos los permanentes. Descarta tu mano. Apostle of Purifying Light|Apóstol de la luz purificadora|Criatura — Clérigo humano|Protección contra negro. (Esta criatura no puede ser bloqueada, hecha objetivo, recibir daño, estar encantada o ser equipada por nada negro.)\n{2}: Exilia la carta objetivo de un cementerio. Apostle's Blessing|Bendición del apóstol|Instantáneo|({W/P} puede pagarse con {W} o con 2 vidas.)\nEl artefacto o criatura objetivo que controlas gana protección contra artefactos o contra el color de tu elección hasta el final del turno. Apothecary Geist|Geist boticario|Criatura — Espíritu|Vuela.\nCuando el Geist boticario entre al campo de batalla, si controlas otro Espíritu, ganas 3 vidas. @@ -595,8 +596,8 @@ Appetite for Brains|Hambre de cerebros|Conjuro|El oponente objetivo muestra su m Appetite for the Unnatural|Apetito por lo artificial|Instantáneo|Destruye el artefacto o encantamiento objetivo. Ganas 2 vidas. Applied Biomancy|Biomancia aplicada|Instantáneo|Elige uno o ambos:\n• La criatura objetivo obtiene +1/+1 hasta el final del turno.\n• Regresa la criatura objetivo a la mano de su propietario. Apprentice Necromancer|Nigromante aprendiz|Criatura — Hechicero zombie|{B}, {T}, sacrificar el Nigromante aprendiz: Regresa la carta de criatura objetivo de tu cementerio al campo de batalla. Esa criatura gana la habilidad de prisa. Al comienzo del próximo paso final, sacrifícala. -Apprentice Sorcerer|Hechicero aprendiz|| -Apprentice Wizard|Aprendiz de brujo|| +Apprentice Sorcerer|Hechicero aprendiz|Criatura — Hechicero humano|{T}: El Hechicero aprendiz inflige 1 de daño a cualquier objetivo. Activa esta habilidad sólo durante tu turno, antes de que los atacantes sean declarados. +Apprentice Wizard|Aprendiz de brujo|Criatura — Hechicero humano|{U}, {T}: Agrega {C}{C}{C}. Approach of the Second Sun|Acercamiento del Segundo Sol|Conjuro|Si el Acercamiento del Segundo Sol fue lanzado de tu mano y ya lanzaste otro hechizo llamado Acercamiento del Segundo Sol en este juego, ganas el juego. De lo contrario, pon el Acercamiento del Segundo Sol en la biblioteca de su propietario en séptimo lugar desde la parte superior y tú ganas 7 vidas. Aquamoeba|Acuamiba|Criatura — Bestia|Descartar una carta de tu mano: Intercambia la fuerza con la resistencia de la Acuamiba hasta el final del turno. Aquamorph Entity|Entidad aquamórfica|Criatura — Metamorfo|En cuanto la Entidad aquamórfica entre en juego o se ponga boca arriba, se convierte en 5/1 o 1/5, a tu elección.\nMetamorfosis {2}{U} (Puedes jugar esta carta boca abajo como una criatura 2/2 pagando {3}. Ponla boca arriba en cualquier momento pagando su coste de metamorfosis.) @@ -628,7 +629,7 @@ Arboreal Grazer|Herbívoro arbóreo|Criatura — Bestia|Alcance.\nCuando el Herb Arboretum Elemental|Elemental de arboreto|Criatura — Elemental|Convocar. (Tus criaturas pueden ayudar a lanzar este hechizo. Cada criatura que gires al lanzar este hechizo cuenta como un pago de {1} o de un maná del color de esa criatura.)\nAntimaleficio. (Esta criatura no puede ser objetivo de hechizos o habilidades que controlan tus oponentes.) Arc Blade|Cuchilla arqueada|Conjuro|La Cuchilla arqueada hace 2 puntos de daño a la criatura o jugador objetivo. Remueve del juego la Cuchilla arqueada con tres contadores de tiempo sobre ella.
Suspender 3—{2}{R} (En lugar de jugar esta carta de tu mano, puedes pagar {2}{R} y removerla del juego con tres contadores de tiempo sobre ella. Al comienzo de tu mantenimiento, remueve un contador de tiempo. Cuando se remueva el último, juégala sin pagar su coste de maná.) Arc Lightning|Relámpago arco|Conjuro|El Relámpago arco hace 3 puntos de daño divididos como elijas entre una, dos o tres criaturas y/o jugadores objetivo. -Arc Mage|Mago arco|| +Arc Mage|Mago arco|Criatura — Hechicero humano|{2}{R}, {T}, Descarta una carta: el Mago arco inflige 2 puntos de daño divididos a tu elección entre uno o dos objetivos. Arc Runner|Corredor de arco|Criatura — Buey elemental|Prisa. (Esta criatura puede atacar y {T} tan pronto como entre bajo tu control.)\nAl comienzo del paso final, sacrifica el Corredor de arco. Arc Trail|Rastro del arco|Conjuro|El Rastro del arco hace 2 puntos de daño a la criatura o jugador objetivo y 1 punto de daño a otra criatura o jugador objetivo. Arc-Slogger|Pasolento voltaico|Criatura — Bestia|{R}, remover del juego las diez primeras cartas de la parte superior de tu biblioteca: El Pasolento voltaico hace 2 puntos de daño a la criatura o jugador objetivo. @@ -637,7 +638,7 @@ Arcane Adaptation|Adaptación arcana|Encantamiento|En cuanto la Adaptación arca Arcane Denial|Constricción arcana|Instantáneo|Contrarresta el hechizo objetivo. Su controlador puede robar hasta dos cartas al comienzo del mantenimiento del próximo turno.Tú robas una carta al comienzo del mantenimiento del próximo turno. Arcane Encyclopedia|Enciclopedia arcana|Artefacto|{3}, {T}: Roba una carta. Arcane Flight|Vuelo arcano|Encantamiento — Aura|Encantar criatura.\nLa criatura encantada obtiene +1/+1 y tiene la habilidad de volar. -Arcane Laboratory|Laboratorio arcano|| +Arcane Laboratory|Laboratorio arcano|Encantamiento|Cada jugador no puede lanzar más de un hechizo por turno. Arcane Lighthouse|Faro arcano|Tierra|{T}: Agrega {1} a tu reserva de maná.\n{1}, {T}: Hasta el final del turno, las criaturas que controlan tus oponentes pierden las habilidades de antimaleficio y velo y no pueden tener las habilidades de antimaleficio o velo. Arcane Melee|Reyerta arcana|Encantamiento|Cuesta {2} menos lanzar hechizos de instantáneo y de conjuro. Arcane Sanctum|Santuario arcano|Tierra|El Santuario arcano entra al campo de batalla girado.\n{T}: Agrega {W}, {U} o {B} a tu reserva de maná. @@ -660,19 +661,19 @@ Arcbound Stinger|Aguijoneador arcoligado|Criatura artefacto|Vuela.\nModular 1 (E Arcbound Wanderer|Vagabundo arcoligado|Criatura artefacto|Modular—Estallido solar (Esto entra en juego con un contador +1/+1 sobre él por cada color de maná usado para pagar su coste. Cuando sea puesto en un cementerio, puedes poner sus contadores +1/+1 sobre la criatura artefacto objetivo.) Arcbound Worker|Trabajador arcoligado|Criatura artefacto — Constructo|Modular 1. (Esto entra al campo de batalla con un contador +1/+1 sobre él. Cuando sea puesto en un cementerio, puedes poner sus contadores +1/+1 sobre la criatura artefacto objetivo.) Arch of Orazca|Arco de Orazca|Tierra|Ascender. (Si controlas diez o más permanentes, obtienes la bendición de la ciudad durante el resto del juego.)\n{T}: Agrega {C} a tu reserva de maná.\n{5}, {T}: Roba una carta. Activa esta habilidad solo si tienes la bendición de la ciudad. -Archaeological Dig|Excavación Arqueológica|| +Archaeological Dig|Excavación Arqueológica|Tierra|{T}: Agrega {C}.\n{T}, Sacrifica Excavación Arqueológica: Agrega una maná de cualquier color. Archaeomancer|Arqueomante|Criatura — Hechicero humano|Cuando el Arqueomante entre al campo de batalla, regresa la carta de instantáneo o de conjuro objetivo de tu cementerio a tu mano. Archangel Avacyn|Arcángel Avacyn|Criatura legendaria — Ángel|Destello.\nVuela, vigilancia.\nCuando el Arcángel Avacyn entre al campo de batalla, las criaturas que controlas ganan la habilidad de indestructible hasta el final del turno.\nCuando una criatura que controles que no sea Ángel muera, transforma al Arcángel Avacyn al principio del próximo mantenimiento. Archangel of Strife|Arcángel del conflicto|Criatura — Ángel|Vuela.\nEn cuanto el Arcángel del conflicto entre al campo de batalla, cada jugador elige guerra o paz.\nLas criaturas controladas por los jugadores que eligieron guerra obtienen +3/+0.\nLas criaturas controladas por los jugadores que eligieron paz obtienen +0/+3. Archangel of Thune|Arcángel de Thune|Criatura — Ángel|Vuela.Vínculo vital. (El daño hecho por esta criatura también hace que ganes esa misma cantidad de vidas.)Siempre que ganes vidas, pon un contador +1/+1 sobre cada criatura que controles. Archangel of Tithes|Arcángel de los diezmos|Criatura — Ángel|Vuela.Mientras el Arcángel de los diezmos esté enderezado, las criaturas no pueden atacarte a ti o a un planeswalker que controlas a menos que su controlador pague {1} por cada una de esas criaturas.Mientras el Arcángel de los diezmos esté atacando, las criaturas no pueden bloquear a menos que su controlador pague {1} por cada una de esas criaturas. Archangel's Light|Luz del arcángel|Conjuro|Gana 2 vidas por cada carta en tu cementerio, luego baraja tu cementerio en tu biblioteca. -Archangel|Acángel|| +Archangel|Arcángel|Criatura — Ángel|Vuela, vigilancia Archdemon of Greed|Archidemonio de la avaricia|Criatura — Demonio|Vuela, arrolla.\nAl comienzo de tu mantenimiento, sacrifica un Humano. Si no puedes, gira al Archidemonio de la avaricia y te hace 9 puntos de daño. Archdemon of Unx|Archidemonio de Unx|Criatura — Demonio|Vuela, arrolla.\nAl comienzo de tu mantenimiento, sacrifica una criatura que no sea Zombie y luego pon en juego una ficha de criatura Zombie negra 2/2. Archers of Qarsi|Arqueros de Qarsi|Criatura — Arquero naga|Defensor.\nAlcance. (Esta criatura puede bloquear a criaturas con la habilidad de volar.) Archers' Parapet|Parapeto de los arqueros|Criatura — Muro|Defensor.\n{1}{B}, {T}: Cada oponente pierde 1 vida. -Archery Training|Entrenamiento de arquería|| +Archery Training|Entrenamiento de arquería|Encantamiento — Aura|Encantar criatura\nAl comienzo de tu mantenimiento, puedes poner un contador de flechas en el Entrenamiento de arquería.\nLa criatura encantada tiene "{T}: Esta criatura inflige X de daño a la criatura que ataca o bloquea, donde X es el número de contadores de flecha en el Entrenamiento de arquería." Archetype of Aggression|Prototipo de agresión|Criatura encantamiento — Guerrero humano|Las criaturas que controlas tienen la habilidad de arrollar.\nLas criaturas que controlan tus oponentes pierden la habilidad de arrollar y no pueden tener ni ganar esa habilidad. Archetype of Courage|Prototipo de valor|Criatura encantamiento — Soldado humano|Las criaturas que controlas tienen la habilidad de dañar primero.\nLas criaturas que controlan tus oponentes pierden la habilidad de dañar primero y no pueden tener ni ganar esa habilidad. Archetype of Endurance|Prototipo de resistencia|Criatura encantamiento — Jabalí|Las criaturas que controlas tienen la habilidad de antimaleficio.\nLas criaturas que controlan tus oponentes pierden la habilidad de antimaleficio y no pueden tener ni ganar esa habilidad. @@ -697,19 +698,19 @@ Archwing Dragon|Dragón ala arqueada|Criatura — Dragón|Vuela, prisa.\nAl comi Arclight Phoenix|Fénix arcobrillante|Criatura — Fénix|Vuela, prisa.\nAl comienzo del combate en tu turno, si lanzaste tres o más hechizos de instantáneo y/o de conjuro este turno, regresa el Fénix arcobrillante de tu cementerio al campo de batalla. Arctic Aven|Aven ártico|Criatura — Hechicero ave|Vuela.\nEl Aven ártico obtiene +1/+1 mientras controles una llanura.\n{W}: El Aven ártico gana la habilidad de vínculo vital hasta el final del turno. (El daño hecho por esta criatura también hace que ganes esa misma cantidad de vidas.) Arctic Flats|Planicies árticas|Tierra nevada|Las Planicies árticas entran en juego giradas.\n{T}: Agrega {G} o {W} a tu reserva de maná. -Arctic Foxes|Zorros árticos|| -Arctic Merfolk|Tritón ártica|| +Arctic Foxes|Zorros árticos|Criatura — Zorro|Los Zorros árticos no pueden ser bloqueados por criaturas con fuerza 2 o superior mientras el jugador defensor controle una tierra nevada. +Arctic Merfolk|Tritón ártica|Criatura — Tritón|Estímulo — Devuelve una criatura que controlas a la mano de su dueño. (Puedes devolver una criatura que controlas a la mano de su dueño además de cualquier otro coste mientras lanzas este hechizo.)\nSi la Tritón ártica fue estimulada, entra en juego con una contador +1/+1. Arctic Nishoba|Nishoba ártica|Criatura — Guerrero felino|Arrolla.\nMantenimiento acumulativo {G} o {W} (Al comienzo de tu mantenimiento, pon un contador de edad sobre este permanente, luego sacrifícalo a menos que pagues su coste de mantenimiento por cada contador de edad sobre él.)\nCuando la Nishoba ártica vaya a un cementerio desde el juego, ganas 2 vidas por cada contador de edad sobre ella. -Arctic Wolves|Lobos árticos|| +Arctic Wolves|Lobos árticos|Criatura — Lobo|Mantenimiento acumulativo {2} (Al comienzo de tu mantenimiento, pon un contador de edad sobre este permanente, luego sacrifícalo a menos que pagues su coste de mantenimiento por cada contador de edad sobre él.)\nCuando los Lobos árticos entren en juego, roba una carta. Arcum Dagsson|Arcum Dagsson|Criatura legendaria — Artífice humano|{T}: El controlador de la criatura artefacto objetivo la sacrifica. Ese jugador puede buscar en su biblioteca una carta de artefacto que no sea criatura, ponerla en juego y barajar su biblioteca. Arcum's Astrolabe|Astrolabio de Arcum|Artefacto nevado|({S} puede pagarse con un maná de un permanente nevado.)\nCuando el Astrolabio de Arcum entre al campo de batalla, roba una carta.\n{1}, {T}: Agrega un maná de cualquier color. -Arcum's Sleigh|Trineo de Arcum|| -Arcum's Weathervane|Veleta de Arcum|| -Arcum's Whistle|Silbato de Arcum|| -Ardent Militia|Milicia enfervorecida|| +Arcum's Sleigh|Trineo de Arcum|Artefacto|{2}, {T}: La criatura objetivo gana vigilancia hasta el final del turno. Activa esta habilidad sólo durante el combate y sólo si el jugador defensor controla una tierra nevado. +Arcum's Weathervane|Veleta de Arcum|Artefacto|{2}, {T}: La tierra de nieve objetivo ya no es nieve.\n{2}, {T}:La tierra básica objetivo que no es nieve se convierte en nieve. +Arcum's Whistle|Silbato de Arcum|Artefacto|{3}, {T}: Elige una criatura objetivo que no sea Muro que el jugador activo haya controlado continuamente desde el comienzo del turno. Ese jugador puede pagar {X}, donde X es el coste de maná convertido de esa criatura. Si no pagan, la criatura ataca este turno si puede, y al comienzo del siguiente paso final, destrúyelo si no atacó este turno. Activa esta habilidad sólo antes de que los atacantes sean declarados. +Ardent Militia|Milicia enfervorecida|Criatura — Soldado humano|Vigilancia Ardent Plea|Plegaria ardorosa|Encantamiento|Exaltado. (Siempre que una criatura que controles ataque sola, esa criatura obtiene +1/+1 hasta el final del turno.)\nCascada. (Cuando juegues este hechizo, remueve del juego las primeras cartas de tu biblioteca hasta que remuevas una carta que no sea tierra que cueste menos. Puedes jugar esa carta sin pagar su coste de maná. Pon las cartas removidas en el fondo de tu biblioteca en un orden aleatorio.) Ardent Recruit|Recluta ferviente|Criatura — Soldado humano|Metalurgia — El Recluta ferviente obtiene +2/+2 mientras controles tres o más artefactos. -Ardent Soldier|Soldado Ardoroso|| +Ardent Soldier|Soldado Ardoroso|Criatura — Soldado humano|Estímulo {2} (Puedes pagar {2} adicionales al lanzar este hechizo.)\nVigilancia\nSi el Soldado Ardoroso fue estimulado, entra en juego con una contador +1/+1. Ardenvale Paladin|Paladín del Valle de Arden|Criatura — Caballero humano|Tesón — Si se usaron al menos tres manás blancos para lanzar este hechizo, la Paladín del Valle de Arden entra al campo de batalla con un contador +1/+1 sobre ella. Ardenvale Tactician|Estratega del Valle de Arden|Criatura — Caballero humano|Vuela. Arena Athlete|Atleta de la arena|Criatura — Humano|Heroísmo — Siempre que lances un hechizo que haga objetivo al Atleta de la arena, la criatura objetivo que controla un oponente no puede bloquear este turno. @@ -3346,6 +3347,7 @@ Curio Vendor|Vendedora de rarezas|Criatura — Vedalken| Curiosity|Curiosidad|Encantamiento — Aura|Encantar criatura.\nSiempre que la criatura encantada haga daño a un oponente, puedes robar una carta. Curious Homunculus|Homúnculo curioso|Criatura — Homúnculo|{T}: Agrega {C} a tu reserva de maná. Usa este maná solo para lanzar un hechizo de instantáneo o de conjuro.\nAl comienzo de tu mantenimiento, si hay tres o más cartas de instantáneo o de conjuro en tu cementerio, transforma al Homúnculo curioso. Curious Obsession|Curiosidad obsesiva|Encantamiento — Aura|Encantar criatura.\nLa criatura encantada obtiene +1/+1 y tiene "Siempre que esta criatura haga daño de combate a un jugador, puedes robar una carta".\nAl comienzo de tu paso final, si no atacaste con una criatura este turno, sacrifica la Curiosidad obsesiva. +Curious Pair|Par de curiosos|Criatura — Plebeyo humano| Curry Favor|Ganarse el favor|Conjuro — Aventura|Ganas X vidas y cada oponente pierde X vidas, donde X es la cantidad de Caballeros que controlas. Curse of Bloodletting|Maldición de sangrado|Encantamiento — Aura maldición|Encantar jugador.\nSi una fuente fuera a hacer daño al jugador encantado, en vez de eso, le hace el doble de ese daño a ese jugador. Curse of Bounty|Maldición de abundancia|Encantamiento — Aura maldición|Encantar jugador.\nSiempre que el jugador encantado sea atacado, endereza todos los permanentes que no sean tierra que controles. Cada oponente que ataque a ese jugador endereza todos los permanentes que no sean tierra que controla. @@ -3444,6 +3446,7 @@ Damping Sphere|Esfera de amortiguamiento|Artefacto|Si una tierra se gira para ob Dance of Many|Danza de espejos|| Dance of Shadows|Baile de sombras|Conjuro - Arcano|Las criaturas que controles obtienen +1/+0 y ganan la habilidad de inspirar temor hasta el final del turno. Dance of the Dead|Danza de los muertos|| +Dance of the Manse|Mansión en movimiento|Conjuro|Regresa de tu cementerio al campo de batalla hasta X cartas de artefacto y/o encantamiento objetivo que no sean Auras, cada una con un coste de maná convertido de X o menos. Si X es 6 o más, esos permanentes son criaturas 4/4 además de sus otros tipos. Dance of the Skywise|Danza sabioceleste|Instantáneo|Hasta el final del turno, la criatura objetivo que controlas se convierte en una Ilusión Dragón azul con fuerza y resistencia base de 4/4, pierde todas sus habilidades y gana la habilidad de volar. Dance with Devils|Baile demoníaco|Instantáneo|Pon en el campo de batalla dos fichas de criatura Diablo rojas 1/1. Tienen "Cuando esta criatura muera, hace 1 punto de daño a la criatura o jugador objetivo". Dancing Scimitar|Cimitarra danzante|Criatura artefacto — Espíritu|Vuela. (Esta criatura no puede ser bloqueada excepto por criaturas que tengan la habilidad de volar.) @@ -4170,6 +4173,7 @@ Domri, City Smasher|Domri, devastador de la ciudad|Planeswalker legendario — D Donate|Donar|| Doom Blade|Cuchilla fatal|Instantáneo|Destruye la criatura objetivo que no sea negra. Doom Cannon|Cañón condenador|Artefacto|En cuanto el Cañón condenador entre en juego, elige un tipo de criatura.\n{3}, {T}, sacrificar una criatura del tipo elegido: El Cañón condenador hace 3 puntos de daño a la criatura o jugador objetivo. +Doom Foretold|Destrucción presagiada|Encantamiento|Al comienzo del mantenimiento de cada jugador, ese jugador sacrifica un permanente que no sea tierra ni ficha. Si ese jugador no puede, ese jugador descarta una carta y pierde 2 vidas; tú robas una carta, ganas 2 vidas y creas una ficha de criatura Caballero blanca 2/2 con la habilidad de vigilancia. Luego, sacrificas la Destrucción presagiada. Doom Whisperer|Susurrador de la fatalidad|Criatura — Demonio pesadilla|Vuela, arrolla.\nPagar 2 vidas: Escruta 2. (Mira las dos primeras cartas de tu biblioteca, luego pon cualquier cantidad de ellas en tu cementerio y el resto en la parte superior de tu biblioteca en cualquier orden.) Doomed Artisan|Artesano maldito|Criatura — Artífice humano|Las Esculturas que controlas no pueden atacar ni bloquear.\nAl comienzo de tu paso final, crea una ficha de criatura artefacto Escultura incolora con "Tanto la fuerza como la resistencia de esta criatura son iguales a la cantidad de Esculturas que controlas". Doomed Dissenter|Disidente condenado|Criatura — Humano|Cuando el Disidente condenado muera, crea una ficha de criatura Zombie negra 2/2. @@ -4402,6 +4406,7 @@ Drove of Elves|Gentío de elfos|Criatura — Elfo|Antimaleficio.\nTanto la fuerz Drover of the Mighty|Pastor de los colosos|Criatura — Druida humano|El Pastor de los colosos obtiene +2/+2 mientras controles un Dinosaurio.\n{T}: Agrega un maná de cualquier color a tu reserva de maná. Drown in Filth|Ahogado en mugre|Conjuro|Elige una criatura objetivo. Pon las cuatro primeras cartas de tu biblioteca en tu cementerio, luego esa criatura obtiene -1/-1 hasta el final del turno por cada carta de tierra en tu cementerio. Drown in Sorrow|Ahogado en pena|Conjuro|Todas las criaturas obtienen -2/-2 hasta el final del turno. Adivina 1. (Mira la primera carta de tu biblioteca. Puedes poner esa carta en el fondo de tu biblioteca.) +Drown in the Loch|Ahogar en el lago|Instantáneo|Elige uno:\n• Contrarresta el hechizo objetivo con coste de maná convertido menor o igual que la cantidad de cartas en el cementerio de su controlador.\n• Destruye la criatura objetivo con coste de maná convertido menor o igual que la cantidad de cartas en el cementerio de su controlador. Drowned Catacomb|Catacumba inundada|Tierra|La Catacumba inundada entra al campo de batalla girada a menos que controles una Isla o un Pantano.\n{T}: Agrega {U} o {B} a tu reserva de maná. Drowned Rusalka|Rusalka ahogada|Criatura — Espíritu|{U}, sacrificar una criatura: Descarta una carta, luego roba una carta. Drowned Secrets|Secretos ahogados|Encantamiento|Siempre que lances un hechizo azul, el jugador objetivo pone las dos primeras cartas de su biblioteca en su cementerio. @@ -4590,6 +4595,7 @@ Edge of Autumn|Al borde del otoño|Conjuro|Si controlas cuatro o menos tierras, Edge of Malacol|Borde de Málacol|Plano — Bélenon|Si una criatura que controlas se fuera a enderezar durante tu paso de enderezar, en vez de eso, pon dos contadores +1/+1 sobre ella.\nSiempre que lances caos, endereza cada criatura que controlas. Edge of the Divinity|Filo de la divinidad|Encantamiento — Aura|Encantar criatura.\nMientras la criatura encantada sea blanca, obtiene +1/+2.\nMientras la criatura encantada sea negra, obtiene +2/+1. Edgewalker|Andaborde|Criatura — Clérigo|Te cuesta {W}{B} menos jugar los hechizos de Clérigo. Este efecto sólo reduce la cantidad de maná de color que pagas. (Por ejemplo, si juegas un Clérigo con coste de maná {1}{W}, te cuesta {1} jugarlo.) +Edgewall Innkeeper|Posadero de Extremuro|Criatura — Plebeyo humano|Siempre que lances un hechizo de criatura que tenga una Aventura, roba una carta. (No tiene por qué haberse ido de aventuras antes.) Edifice of Authority|Edificio de autoridad|Artefacto|{1}, {T}: La criatura objetivo no puede atacar este turno. Pon un contador de bloque sobre el Edificio de autoridad.\n{1}, {T}: Hasta tu próximo turno, la criatura objetivo no puede atacar ni bloquear y sus habilidades activadas no pueden activarse. Activa esta habilidad solo si hay tres o más contadores de bloque sobre el Edificio de autoridad. Edric, Spymaster of Trest|Edric, maestro espía de Trest|Criatura legendaria — Bribón elfo|Siempre que una criatura haga daño de combate a uno de tus oponentes, su controlador puede robar una carta. Eel Umbra|Umbra de anguila|Encantamiento — Aura|Destello. (Puedes lanzar este hechizo en cualquier momento en que pudieras lanzar un instantáneo.)\nEncantar criatura.\nLa criatura encantada obtiene +1/+1.\nArmadura tótem. (Si la criatura encantada fuera a ser destruida, en vez de eso, remueve todo el daño de ella y destruye este aura.) @@ -4956,6 +4962,7 @@ Ertai, the Corrupted|Ertai, el Corrupto|| Erupting Dreadwolf|Pavor licano en erupción|Criatura — Licántropo eldrazi|Siempre que el Pavor licano en erupción ataque, hace 2 puntos de daño a la criatura o jugador objetivo. Escape Artist|Artista del escape|Criatura — Hechicero|La Artista del escape es imbloqueable.\n{U}, descartar una carta de tu mano: Regresa la Artista del escape a la mano de su propietario. Escape Routes|Rutas de escape|| +Escape to the Wilds|Huir a las tierras salvajes|Conjuro|Exilia las cinco primeras cartas de tu biblioteca. Puedes jugar las cartas exiliadas de esta manera hasta el final de tu próximo turno.\nPuedes jugar una tierra adicional este turno. Escaped Null|Nulo fugado|Criatura — Berserker zombie|Vínculo vital.\nSiempre que el Nulo fugado bloquee o sea bloqueado, obtiene +5/+0 hasta el final del turno. Escaped Shapeshifter|Metamorfo evadido|| Esper Battlemage|Maga de guerra esperiana|Criatura artefacto — Hechicero humano|{W}, {T}: Prevén los siguientes 2 puntos de daño que se te fueran a hacer este turno.\n{B}, {T}: La criatura objetivo obtiene -1/-1 hasta el final del turno. @@ -5172,7 +5179,8 @@ Fact or Fiction|Realidad o Ficción|| Fade Away|Desaparecer|| Fade from Memory|Desvanecerse del recuerdo|Instantáneo|Remueve del juego la carta objetivo de un cementerio.\nCiclo {B}. ({B}, descartar esta carta de tu mano: Roba una carta.) Fade into Antiquity|Desvanecerse en la antigüedad|Conjuro|Exilia el artefacto o encantamiento objetivo. -Fae of Wishes|Deseo concedido|Conjuro — Aventura|Puedes elegir una carta que no sea de criatura de fuera del juego de la cual eres propietario, mostrarla y ponerla en tu mano. +Fae of Wishes|Hadas de los deseos|Criatura — Hechicero hada|Vuela.\n{1}{U}, descartar dos cartas: Regresa las Hadas de los deseos a la mano de su propietario. +Faeburrow Elder|Anciana del Cubil Feérico|Criatura — Druida pueblo-arbóreo|Vigilancia.\nLa Anciana del Cubil Feérico obtiene +1/+1 por cada color entre los permanentes que controlas.\n{T}: Por cada color entre los permanentes que controlas, agrega un maná de ese color. Faerie Artisans|Hadas artesanas|Criatura — Artífice hada|Vuela.\nSiempre que una criatura que no sea ficha entre al campo de batalla bajo el control de un oponente, crea una ficha que es una copia de esa criatura, excepto que es un artefacto además de sus otros tipos. Luego exilia todas las demás fichas creadas con las Hadas artesanas. Faerie Conclave|Cónclave de hadas|Tierra|El Cónclave de hadas entra al campo de batalla girado.{T}: Agrega {U} a tu reserva de maná.{1}{U}: El Cónclave de hadas se convierte en una criatura Hada azul 2/1 con la habilidad de volar hasta el final del turno. Sigue siendo una tierra. Faerie Duelist|Duelista hada|Criatura — Bribón hada|Destello.\nVuela.\nCuando el Duelista hada entre al campo de batalla, la criatura objetivo que controla un oponente obtiene -2/-0 hasta el final del turno. @@ -5185,7 +5193,7 @@ Faerie Mechanist|Hada mecanista|Criatura artefacto — Artífice hada|Vuela.\nCu Faerie Miscreant|Hada malhechora|Criatura — Bribón hada|Vuela. (Esta criatura no puede ser bloqueada excepto por criaturas que tengan la habilidad de volar o alcance.)Cuando el Hada malhechora entre al campo de batalla, si controlas otra criatura llamada Hada malhechora, roba una carta. Faerie Noble|Noble duende|| Faerie Seer|Vidente hada|Criatura — Hechicero hada|Vuela.\nCuando el Vidente hada entre al campo de batalla, adivina 2. -Faerie Squadron|Escudaron de Hadas|| +Faerie Squadron|Escuadrón de hadas|| Faerie Swarm|Enjambre de hadas|Criatura — Hada|Vuela.\nTanto la fuerza como la resistencia del Enjambre de hadas son iguales a la cantidad de permanentes azules que controlas. Faerie Tauntings|Burlas faéricas|Encantamiento tribal — Hada|Siempre que juegues un hechizo durante el turno de un oponente, puedes hacer que cada oponente pierda 1 vida. Faerie Trickery|Artimañas faéricas|Instantáneo tribal — Hada|Contrarresta el hechizo objetivo que no sea de Hada. Si ese hechizo se contrarresta de esta manera, remuévelo del juego en vez de ponerlo en el cementerio de su propietario. @@ -5311,6 +5319,7 @@ Feast of the Unicorn|Banquete del unicornio|| Feast on the Fallen|Devorar a los caídos|Encantamiento|Al comienzo de cada mantenimiento, si un oponente perdió vidas el turno anterior, pon un contador +1/+1 sobre la criatura objetivo que controlas. Feast or Famine|Abundancia o escasez|| Feaster of Fools|Devorador de necios|Criatura — Demonio|Convocar. (Tus criaturas pueden ayudar a lanzar este hechizo. Cada criatura que gires al lanzar este hechizo cuenta como un pago de {1} o de un maná del color de esa criatura.)\nVuela.\nDevorar 2. (En cuanto esta carta entre al campo de batalla, puedes sacrificar cualquier cantidad de criaturas. Esta criatura entra al campo de batalla con el doble de esa cantidad de contadores +1/+1 sobre ella.) +Feasting Troll King|Rey trol atiborrándose|Criatura — Noble trol|Vigilancia, arrolla.\nCuando el Rey trol atiborrándose entre al campo de batalla, si lo lanzaste desde tu mano, crea tres fichas de Comida.\nSacrificar tres Comidas: Regresa el Rey trol atiborrándose de tu cementerio al campo de batalla. Activa esta habilidad solo durante tu turno. Feat of Resistance|Hito de resistencia|Instantáneo|Pon un contador +1/+1 sobre la criatura objetivo que controlas. Esa criatura gana protección contra el color de tu elección hasta el final del turno. Feather, the Redeemed|Pluma, la Redimida|Criatura legendaria — Ángel|Vuela.\nSiempre que lances un hechizo de instantáneo o de conjuro que haga objetivo a una criatura que controlas, exilia esa carta en vez de ponerla en tu cementerio en cuanto se resuelve. Si lo haces, regrésala a tu mano al comienzo del próximo paso final. Fecundity|Fecundidad|Encantamiento|Siempre que una criatura muera, el controlador de esa criatura puede robar una carta. @@ -5337,6 +5346,7 @@ Fell Flagship|Navío siniestro|Artefacto — Vehículo|Los Piratas que controlas Fell Shepherd|Pastor siniestro|Criatura — Avatar|Siempre que el Pastor siniestro haga daño de combate a un jugador, puedes regresar a tu mano todas las cartas de criatura que fueron puestas en tu cementerio desde el campo de batalla este turno.{B}, sacrificar otra criatura: La criatura objetivo obtiene -2/-2 hasta el final del turno. Fell Specter|Espectro maligno|Criatura — Espectro|Vuela.\nCuando el Espectro maligno entre al campo de batalla, el oponente objetivo descarta una carta.\nSiempre que un oponente descarte una carta, ese jugador pierde 2 vidas. Fell the Mighty|Tumbar a los poderosos|Conjuro|Destruye todas las criaturas con una fuerza mayor que la fuerza de la criatura objetivo. +Fell the Pheasant|Cazar faisanes|Instantáneo|Cazar faisanes hace 5 puntos de daño a la criatura objetivo con la habilidad de volar. Crea una ficha de Comida. (Es un artefacto con "{2}, {T}, sacrificar este artefacto: Ganas 3 vidas".) Fellwar Stone|Piedra de Fellwar|Artefacto|{T}: Agrega a tu reserva de maná un maná de cualquier color que pudiera producir una tierra que controla un oponente. Femeref Archers|Arqueros de Femeref|Criatura — Arquero humano|{T}: Los Arqueros de Femeref hacen 4 puntos de daño a la criatura atacante objetivo que tenga la habilidad de volar. Femeref Enchantress|Encantadora femeref|| @@ -5423,6 +5433,7 @@ Fiend of the Shadows|Demonio de las sombras|Criatura — Hechicero vampiro|Vuela Fiendslayer Paladin|Paladín matamalvados|Criatura — Caballero humano|Daña primero. (Esta criatura hace daño de combate antes que las criaturas sin la habilidad de dañar primero.) Vínculo vital. (El daño hecho por esta criatura también hace que ganes esa misma cantidad de vidas.)El Paladín matamalvados no puede ser objetivo de hechizos negros o rojos que controlen tus oponentes. Fierce Empath|Émpata fiero|Criatura — Elfo|Cuando el Émpata fiero entre al campo de batalla, puedes buscar en tu biblioteca una carta de criatura con coste de maná convertido de 6 o mayor, mostrarla, ponerla en tu mano y luego barajar tu biblioteca. Fierce Invocation|Invocación fiera|Conjuro|Manifiesta la primera carta de tu biblioteca, luego pon dos contadores +1/+1 sobre ella. (Para manifestar una carta, ponla en el campo de batalla boca abajo como una criatura 2/2. Ponla boca arriba en cualquier momento por su coste de maná si es una carta de criatura.) +Fierce Witchstalker|Acechabrujas feroz|Criatura — Lobo|Arrolla.\nCuando el Acechabrujas feroz entre al campo de batalla, crea una ficha de Comida. (Es un artefacto con "{2}, {T}, sacrificar este artefacto: Ganas 3 vidas".) Fiery Bombardment|Bombardeo ardiente|Encantamiento|Croma {2}, sacrificar una criatura: El Bombardeo ardiente hace daño a la criatura o jugador objetivo igual a la cantidad de símbolos de maná rojo en el coste de maná de la criatura sacrificada. Fiery Cannonade|Cañonazo ardiente|Instantáneo|El Cañonazo ardiente hace 2 puntos de daño a cada criatura que no sea Pirata. Fiery Conclusion|Conclusión ardiente|Instantáneo|Como coste adicional para jugar la Conclusión ardiente, sacrifica una criatura.\nLa Conclusión ardiente hace 5 puntos de daño a la criatura objetivo. @@ -5603,6 +5614,7 @@ Flashfires|Tormenta ígnea|Conjuro|Destruye todas las llanuras. Flashfreeze|Congelación repentina|Instantáneo|Contrarresta el hechizo objetivo rojo o verde. Flash|Destello|| Flatten|Aplanar|Instantáneo|La criatura objetivo obtiene -4/-4 hasta el final del turno. +Flaxen Intruder|Intrusa rubita|Criatura — Berserker humano|Siempre que la Intrusa rubita haga daño de combate a un jugador, puedes sacrificarla. Cuando lo hagas, destruye el artefacto o encantamiento objetivo. Flayed Nim|Nim degollado|Criatura — Esqueleto|Siempre que el Nim degollado haga daño de combate a una criatura, el controlador de esa criatura pierde la misma cantidad de vida.\n{2}{B}: Regenera el Nim degollado. Flayer Drone|Zángano desollador|Criatura — Zángano eldrazi|Vacío. (Esta carta no tiene ningún color.)\nDaña primero.\nSiempre que otra criatura incolora entre al campo de batalla bajo tu control, el oponente objetivo pierde 1 vida. Flayer Husk|Caparazón desollador|Artefacto — Equipo|Arma viviente. (Cuando este equipo entre al campo de batalla, pon en el campo de batalla una ficha de criatura negra Germen 0/0, luego anéxalo a ella.)\nLa criatura equipada obtiene +1/+1.\nEquipar {2}. @@ -5776,6 +5788,7 @@ Foresee|Antever|Conjuro|Adivina 4, luego roba dos cartas. (Para adivinar 4, mira Foreshadow|Premonición|| Foresight|Prever|| Forest|Bosque|Tierra básica - Bosque|({T}: Agrega {G}.) +Forever Young|Juventud eterna|Conjuro|Pon cualquier cantidad de cartas de criatura objetivo de tu cementerio en la parte superior de tu biblioteca.\nRoba una carta. Forfend|Amparar|Instantáneo|Prevén todo el daño que se le fuera a hacer a las criaturas este turno. Forge Armor|Forjar armadura|Instantáneo|Como coste adicional para jugar Forjar armadura, sacrifica un artefacto.\nPon X contadores +1/+1 sobre la criatura objetivo, donde X es el coste de maná convertido del artefacto sacrificado. Forge Devil|Diablo de la fragua|Criatura — Diablo|Cuando el Diablo de la fragua entre al campo de batalla, le hace 1 punto de daño a la criatura objetivo y 1 punto de daño a ti. @@ -5828,6 +5841,7 @@ Foul Renewal|Renovación hedionda|Instantáneo|Regresa la carta de criatura obje Foul Spirit|Espiritu inmundo|| Foul-Tongue Invocation|Invocación en lenguainfame|Instantáneo|Como coste adicional para lanzar la Invocación en lenguainfame, puedes mostrar una carta de Dragón de tu mano.\nEl jugador objetivo sacrifica una criatura. Si mostraste una carta de Dragón o controlabas un Dragón al lanzar la Invocación en lenguainfame, ganas 4 vidas. Foul-Tongue Shriek|Grito en lenguainfame|Instantáneo|El oponente objetivo pierde 1 vida por cada criatura atacante que controlas. Tú ganas esa misma cantidad de vidas. +Foulmire Knight|Caballero pantanopútrido|Criatura — Caballero zombie|Toque mortal. Foundry Assembler|Ensamblador de la fundición|Criatura artefacto — Operario|Improvisar. (Tus artefactos pueden ayudar a lanzar este hechizo. Cada artefacto que gires una vez que termines de activar habilidades de maná paga {1}.) Foundry Champion|Campeón de la Fundición|Criatura — Soldado elemental|Cuando el Campeón de la Fundición entre al campo de batalla, hace daño a la criatura o jugador objetivo igual al número de criaturas que controlas.{R}: El Campeón de la Fundición obtiene +1/+0 hasta el final del turno.{W}: El Campeón de la Fundición obtiene +0/+1 hasta el final del turno. Foundry Hornet|Avispa de la fundición|Criatura — Insecto|Vuela.\nCuando la Avispa de la fundición entre al campo de batalla, si controlas una criatura con un contador +1/+1 sobre ella, las criaturas que controlan tus oponentes obtienen -1/-1 hasta el final del turno. @@ -6022,6 +6036,9 @@ Gang of Devils|Banda de diablos|Criatura — Diablo|Cuando la Banda de diablos m Gang of Elk|Manada de alces|| Gangrenous Goliath|Goliat gangrenoso|Criatura — Gigante zombie|Girar tres Clérigos enderezados que controles: Regresa el Goliat gangrenoso de tu cementerio a tu mano. Gangrenous Zombies|Zombis gangrenosos|| +Garenbrig Carver|Tallista del Coto de Garen|Criatura — Guerrero humano| +Garenbrig Paladin|Paladín del Coto de Garen|Criatura — Caballero gigante|Tesón — Si se usaron al menos tres manás verdes para lanzar este hechizo, el Paladín del Coto de Garen entra al campo de batalla con un contador +1/+1 sobre él.\nEl Paladín del Coto de Garen no puede ser bloqueado por criaturas con fuerza de 2 o menos. +Garenbrig Squire|Escudero del Coto de Garen|Criatura — Soldado humano|Siempre que lances un hechizo de criatura que tenga una Aventura, el Escudero del Coto de Garen obtiene +1/+1 hasta el final del turno. (No tiene por qué haberse ido de aventuras antes.) Gargantuan Gorilla|Gorila gargantuesco|| Gargos, Vicious Watcher|Gargos, vigilante brutal|Criatura legendaria — Hidra|Vigilancia.\nTe cuesta {4} menos lanzar los hechizos de Hidra.\nSiempre que una criatura que controlas sea objetivo de un hechizo, Gargos, vigilante brutal lucha contra hasta una criatura objetivo que no controlas. Gargoyle Castle|Castillo de las gárgolas|Tierra|{T}: Agrega {1} a tu reserva de maná.\n{5}, {T}, sacrificar el Castillo de las gárgolas: Pon en el campo de batalla una ficha de criatura artefacto Gárgola incolora 3/4 con la habilidad de volar. @@ -6036,6 +6053,7 @@ Garruk's Horde|Horda de Garruk|Criatura — Bestia|Arrolla. (Esta criatura puede Garruk's Packleader|Líder de manada de Garruk|Criatura — Bestia|Siempre que otra criatura con fuerza de 3 o más entre al campo de batalla bajo tu control, puedes robar una carta. Garruk, Apex Predator|Garruk, depredador arquetípico|Planeswalker — Garruk|+1: Destruye otro planeswalker objetivo.\n+1: Pon en el campo de batalla una ficha de criatura Bestia negra 3/3 con la habilidad de toque mortal.\n-3: Destruye la criatura objetivo. Ganas una cantidad de vidas igual a su resistencia.\n-8: El oponente objetivo obtiene un emblema con "Siempre que una criatura te ataque, obtiene +5/+5 y gana la habilidad de arrollar hasta el final del turno". Garruk, Caller of Beasts|Garruk, llamador de bestias|Planeswalker — Garruk|+1: Muestra las primeras cinco cartas de tu biblioteca. Pon todas las cartas de criatura mostradas de esta manera en tu mano y el resto en la parte inferior de tu biblioteca en cualquier orden.-3: Puedes poner en el campo de batalla una carta de criatura verde de tu mano.-7: Obtienes un emblema con "Siempre que lances un hechizo de criatura, puedes buscar en tu biblioteca una carta de criatura, ponerla en el campo de batalla, y luego barajar tu biblioteca". +Garruk, Cursed Huntsman|Garruk, cazador maldito|Planeswalker legendario — Garruk|0: Crea dos fichas de criatura Lobo negras y verdes 2/2 con "Cuando esta criatura muera, pon un contador de lealtad sobre cada Garruk que controlas".\n−3: Destruye la criatura objetivo. Roba una carta.\n−6: Obtienes un emblema con "Las criaturas que controlas obtienen +3/+3 y tienen la habilidad de arrollar". Garruk, Primal Hunter|Garruk, cazador primordial|Planeswalker legendario — Garruk|+1: Crea una ficha de criatura Bestia verde 3/3.\n−3: Roba una cantidad de cartas igual a la mayor fuerza entre las criaturas que controlas.\n−6: Crea una ficha de criatura Sierpe verde 6/6 por cada tierra que controlas. Garruk, the Veil-Cursed|Garruk, maldito por el Velo|Planeswalker — Garruk|+1: Pon en el campo de batalla una ficha de criatura Lobo negra 1/1 con la habilidad de toque mortal.\n-1: Sacrifica una criatura. Si lo haces, busca en tu biblioteca una carta de criatura, muéstrala y ponla en tu mano. Luego baraja tu biblioteca.\n-3: Las criaturas que controlas ganan la habilidad de arrollar y obtienen +X/+X hasta el final del turno, donde X es el número de cartas de criatura en tu cementerio. Garza Zol, Plague Queen|Garza Zol, reina de la peste|Criatura legendaria — Vampiro|Vuela, prisa.\nSiempre que una criatura que haya recibido daño de Garza Zol, reina de la peste este turno vaya a un cementerio, pon un contador +1/+1 sobre Garza Zol.\nSiempre que Garza Zol haga daño de combate a un jugador, puedes robar una carta. @@ -6226,6 +6244,7 @@ Giant Harbinger|Heraldo gigante|Criatura — Chamán gigante|Cuando el Heraldo g Giant Killer|Matagigantes|Criatura — Plebeyo humano|{1}{W}, {T}: Gira la criatura objetivo. Giant Mantis|Mantis gigante|Criatura — Insecto|Alcance. (Esta criatura puede bloquear a criaturas con la habilidad de volar.) Giant Octopus|Pulpo gigante|| +Giant Opportunity|Oportunidad gigantesca|Conjuro|Puedes sacrificar dos Comidas. Si lo haces, crea una ficha de criatura Gigante verde 7/7. De lo contrario, crea tres fichas de Comida. (Son artefactos con "{2}, {T}, sacrificar este artefacto: Ganas 3 vidas".) Giant Oyster|Ostra gigante|Criatura — Ostra|Puedes elegir no enderezar la Ostra gigante durante tu paso de enderezar.\n{T}: Mientras la Ostra gigante permanezca girada, la criatura girada objetivo no se endereza durante el paso de enderezar de su controlador y al principio de cada uno de tus pasos de robar, pon un contador -1/-1 sobre esa criatura. Cuando la Ostra gigante deje el juego o sea enderezada, remueve todos los contadores -1/-1 de esa criatura. Giant Scorpion|Escorpión gigante|Criatura — Escorpión|Toque mortal. (Cualquier cantidad de daño que esto haga a una criatura es suficiente para destruirla.) Giant Solifuge|Solífugo gigante|Criatura — Insecto|({R/G} puede pagarse con {R} o con {G}.)\nArrolla, prisa.\nEl Solífugo gigante no puede ser objetivo de hechizos o habilidades. @@ -6236,6 +6255,7 @@ Giant Tortoise|Galápago gigante|| Giant Trap Door Spider|Araña cavadora gigante|| Giant Warthog|Facoquero gigante|Criatura — Bestia|Arrolla. Giant's Ire|Ira de gigante|Conjuro tribal — Gigante|La Ira de gigante hace 4 puntos de daño al jugador objetivo. Si controlas un Gigante, roba una carta. +Giant's Skewer|Brocheta de gigante|Artefacto — Equipo|La criatura equipada obtiene +2/+1.\nSiempre que la criatura equipada haga daño de combate a una criatura, crea una ficha de Comida. (Es un artefacto con "{2}, {T}, sacrificar este artefacto: Ganas 3 vidas".)\nEquipar {3}. ({3}: Anexa este Equipo a la criatura objetivo que controlas. Activa la habilidad de equipar como un conjuro.) Giantbaiting|Carnada para gigantes|Conjuro|Pon en juego una ficha de criatura Guerrero Gigante verde y roja 4/4 con la habilidad de prisa. Remuévela del juego al final del turno.\nConspirar. (En cuanto juegues este hechizo puedes girar dos criaturas enderezadas que controles que compartan un color con él. Cuando lo hagas, cópialo.) Gibbering Descent|Descenso quejumbroso|Encantamiento|Al comienzo del mantenimiento de cada jugador, ese jugador pierde 1 vida y descarta una carta.
Temerario Sáltate tu mantenimiento si no tienes cartas en tu mano.
Demencia {2}{B}{B} (Si descartas esta carta, puedes jugarla por su coste de demencia en vez de ponerla en tu cementerio.) Gibbering Fiend|Demonio farfullador|Criatura — Diablo|Cuando el Demonio farfullador entre al campo de batalla, hace 1 punto de daño a cada oponente.\nDelirio — Al comienzo del mantenimiento de cada oponente, si entre las cartas de tu cementerio hay cuatro o más tipos de cartas, el Demonio farfullador hace 1 punto de daño a ese jugador. @@ -6283,6 +6303,7 @@ Gigantosaurus|Gigantosaurio|Criatura — Dinosaurio| Gigapede|Gigapodo|Criatura — Insecto|El Gigapodo no puede ser objetivo de hechizos o habilidades.\nAl comienzo de tu mantenimiento, si el Gigapodo está en tu cementerio, puedes descartar una carta de tu mano. Si lo haces, regresa el Gigapodo a tu mano. Gilded Cerodon|Cerodonte de oropel|Criatura — Bestia|Siempre que el Cerodonte de oropel ataque, si controlas un Desierto o hay una carta de Desierto en tu cementerio, la criatura objetivo no puede bloquear este turno. Gilded Drake|Draco de oropel|| +Gilded Goose|Gansa dorada|Criatura — Ave|Vuela.\nCuando la Gansa dorada entre al campo de batalla, crea una ficha de Comida. (Es un artefacto con "{2}, {T}, sacrificar este artefacto: Ganas 3 vidas".)\n{1}{G}, {T}: Crea una ficha de Comida.\n{T}, sacrificar una Comida: Agrega un maná de cualquier color. Gilded Light|Luz de oropel|Instantáneo|Ganas la habilidad de velo hasta el final del turno. (No puedes ser objetivo de hechizos o habilidades.)\nCiclo {2}. ({2}, descartar esta carta: Roba una carta.) Gilded Lotus|Loto de oropel|Artefacto|{T}: Agrega tres maná de un color cualquiera a tu reserva de maná. Gilded Sentinel|Centinela de oropel|Criatura artefacto — Gólem| @@ -6681,7 +6702,7 @@ Granger Guildmage|Mago del gremio de los granjeros|| Granite Grip|Abrazo de granito|| Granite Shard|Fragmento de granito|Artefacto|{3}, {T} o {R}, {T}: El Fragmento de granito hace 1 punto de daño a la criatura o al jugador objetivo. Granitic Titan|Titán granítico|Criatura — Elemental|Amenaza.\nCiclo {2}. ({2}, descartar esta carta: Roba una carta.) -Granted|Hadas de los deseos|Criatura — Hechicero hada|Vuela.\n{1}{U}, descartar dos cartas: Regresa las Hadas de los deseos a la mano de su propietario. +Granted|Deseo concedido|Conjuro — Aventura|Puedes elegir una carta que no sea de criatura de fuera del juego de la cual eres propietario, mostrarla y ponerla en tu mano. Granulate|Granular|Conjuro|Destruye cada artefacto que no sea tierra con coste de maná convertido de 4 o menos. Grapeshot Catapult|Catapulta de metralla|| Grapeshot|Metralla|Conjuro|La Metralla hace 1 punto de daño a la criatura o jugador objetivo.\nTormenta (Cuando juegues este hechizo, cópialo por cada hechizo jugado antes que él en este turno. Puedes elegir nuevos objetivos para las copias.) @@ -6896,6 +6917,7 @@ Gruesome Fate|Destino terrible|Conjuro|Cada oponente pierde 1 vida por cada cria Gruesome Menagerie|Criadero macabro|Conjuro|Elige una carta de criatura con coste de maná convertido de 1 en tu cementerio. Luego, haz lo mismo con cartas de criatura con coste de maná convertido de 2 y 3. Regresa esas cartas al campo de batalla. Gruesome Scourger|Flagelador horripilante|Criatura — Guerrero orco|Cuando el Flagelador horripilante entre al campo de batalla, hace una cantidad de daño al oponente o planeswalker objetivo igual a las criaturas que controlas. Gruesome Slaughter|Masacre horripilante|Conjuro|Hasta el final del turno, las criaturas incoloras que controlas ganan "{T}: Esta criatura hace una cantidad de daño igual a su fuerza a la criatura objetivo". +Grumgully, the Generous|Grumgully, el Generoso|Criatura legendaria — Chamán trasgo|Cada otra criatura que no sea Humano que controlas entra al campo de batalla con un contador +1/+1 adicional sobre ella. Grunn, the Lonely King|Grunn, el rey solitario|Criatura legendaria — Guerrero simio|Estímulo {3}. (Puedes pagar {3} adicionales al lanzar este hechizo.)\nSi Grunn, el rey solitario fue estimulado, entra al campo de batalla con cinco contadores +1/+1 sobre él.\nSiempre que Grunn ataque solo, duplica su fuerza y resistencia hasta el final del turno. Gruul Beastmaster|Domadora gruul|Criatura — Chamán humano|Insurgencia. (Esta criatura entra al campo de batalla con lo que elijas: un contador +1/+1 o la habilidad de prisa.)\nSiempre que la Domadora gruul ataque, otra criatura objetivo que controlas obtiene +X/+0 hasta el final del turno, donde X es la fuerza de la Domadora gruul. Gruul Charm|Amuleto gruul|Instantáneo|Elige uno: Las criaturas sin la habilidad de volar no pueden bloquear este turno; o gana el control de todos los permanentes de los cuales eres propietario; o el Amuleto gruul hace 3 puntos de daño a cada criatura con la habilidad de volar. @@ -7187,6 +7209,7 @@ Heart of Kiran|Corazón de Kiran|Artefacto legendario — Vehículo|Vuela, vigil Heart of Light|Corazón de luz|Encantamiento — Aura|Encantar criatura. (Haz objetivo a una criatura al jugarlo. Esta carta entra en juego anexada a esa criatura.)\nPrevén todo el daño que se le fuera a hacer y que fuera a hacer la criatura encantada. Heart of Ramos|Corazón de Ramos|| Heart of Yavimaya|Corazón de Yavimaya|| +Heart's Desire|Deseo del corazón|Conjuro — Aventura|Crea una ficha de criatura Humano blanca 1/1. (Luego, exilia esta carta. Puedes lanzar la criatura más adelante desde el exilio.) Heart-Piercer Bow|Arco perforacorazones|Artefacto — Equipo|Siempre que la criatura equipada ataque, el Arco perforacorazones hace 1 punto de daño a la criatura objetivo que controla el jugador defensor.\nEquipar {1}. Heart-Piercer Manticore|Mantícora perforacorazones|Criatura — Mantícora|Cuando la Mantícora perforacorazones entre al campo de batalla, puedes sacrificar otra criatura. Cuando lo hagas, la Mantícora perforacorazones hace daño a la criatura o jugador objetivo igual a la fuerza de esa criatura.\nEmbalsamar {5}{R}. ({5}{R}, exiliar esta carta de tu cementerio: Crea una ficha que es una copia de esta carta, excepto que es una Mantícora Zombie blanca sin coste de maná. Activa la habilidad de embalsamar solo como un conjuro.) Heartbeat of Spring|Latido de la primavera|Encantamiento|Siempre que un jugador gire una tierra para obtener maná, ese jugador agrega un maná de ese tipo a su reserva de maná. @@ -7777,6 +7800,7 @@ Imposing Sovereign|Soberana imponente|Criatura — Humano|Las criaturas que cont Imposing Visage|Imagen imponente|| Impostor of the Sixth Pride|Impostor de la Sexta Manada|Criatura — Metamorfo|Cambiaformas. (Esta carta es de todos los tipos de criatura.) Imprisoned in the Moon|Prisión lunar|Encantamiento — Aura|Encantar criatura, tierra o planeswalker.\nEl permanente encantado es una tierra incolora con "{T}: Agrega {C} a tu reserva de maná" y pierde todos sus otros tipos de carta y habilidades. +Improbable Alliance|Alianza improbable|Encantamiento|Siempre que robes tu segunda carta cada turno, crea una ficha de criatura Hada azul 1/1 con la habilidad de volar.\n{4}{U}{R}: Roba una carta, luego descarta una carta. Impromptu Raid|Incursión improvisada|Encantamiento|{2}{R/G}: Muestra la primera carta de tu biblioteca. Si no es una carta de criatura, ponla en tu cementerio. De lo contrario, pon en juego esa carta. Esa criatura tiene la habilidad de prisa. Sacrifícala al final del turno. Improvised Armor|Armadura improvisada|Encantar criatura|La criatura encantada obtiene +2/+5.\nCiclo {3}. ({3}, descartar esta carta de tu mano: Roba una carta.) Imps' Taunt|Burla de los diablillos|| @@ -7911,6 +7935,7 @@ Inquisitor Exarch|Exarca inquisidor|Criatura — Clérigo|Cuando el Exarca inqui Inquisitor's Flail|Mayal del inquisidor|Artefacto — Equipo|Si la criatura equipada fuera a hacer daño de combate, en vez de eso, hace el doble de ese daño.\nSi otra criatura fuera a hacer daño de combate a la criatura equipada, en vez de eso, le hace el doble de ese daño a la criatura equipada.\nEquipar {2}. Inquisitor's Ox|Buey del inquisidor|Criatura — Buey|Delirio — El Buey del inquisidor obtiene +1/+0 y tiene la habilidad de vigilancia mientras entre las cartas de tu cementerio haya cuatro o más tipos de cartas Inquisitor's Snare|Trampa del inquisidor|Instantáneo|Prevén todo el daño que fuera a hacer la criatura atacante o bloqueadora objetivo este turno. Si esa criatura es negra o roja, destrúyela. +Insatiable Appetite|Apetito insaciable|Instantáneo|Puedes sacrificar una Comida. Si lo haces, la criatura objetivo obtiene +5/+5 hasta el final del turno. De lo contrario, esa criatura obtiene +3/+3 hasta el final del turno. Insatiable Gorgers|Engullidores insaciables|Criatura — Berserker vampiro|Los Engullidores insaciables atacan cada combate si pueden.\nDemencia {3}{R}. (Si descartas esta carta, exíliala. Cuando lo hagas, lánzala por su coste de demencia o ponla en tu cementerio.) Insatiable Harpy|Arpía insaciable|Criatura — Arpía|Vuela, vínculo vital. Insatiable Souleater|Devoraalmas insaciable|Criatura artefacto — Bestia|{G/P}: El Devoraalmas insaciable gana la habilidad de arrollar hasta el final del turno. ({G/P} puede pagarse con {G} o con 2 vidas.) @@ -7934,6 +7959,7 @@ Inspiring Roar|Rugido inspirador|Conjuro|Pon un contador +1/+1 sobre cada criatu Inspiring Statuary|Estatuas inspiradoras|Artefacto|Los hechizos que no sean de artefacto que lances tienen la habilidad de improvisar. (Tus artefactos pueden ayudar a lanzar esos hechizos. Cada artefacto que gires una vez que termines de activar habilidades de maná paga {1}.) Inspiring Unicorn|Unicornio inspirador|Criatura — Unicornio|Siempre que el Unicornio inspirador ataque, las criaturas que controlas obtienen +1/+1 hasta el final del turno. Inspiring Vantage|Atalaya inspiradora|Tierra|La Atalaya inspiradora entra al campo de batalla girada a menos que controles otras dos o menos tierras.\n{T}: Agrega {R} o {W} a tu reserva de maná. +Inspiring Veteran|Veterano inspirador|Criatura — Caballero humano|Los otros Caballeros que controlas obtienen +1/+1. Inspirit|Alentar|Instantáneo|Endereza la criatura objetivo. Obtiene +2/+4 hasta el final del turno. Instigator Gang|Banda instigadora|Criatura — Licántropo humano|Las criaturas atacantes que controles obtienen +1/+0.\nAl comienzo de cada mantenimiento, si no se lanzaron hechizos en el último turno, transforma a la Banda instigadora. Instigator|Instigadora|| @@ -8429,6 +8455,7 @@ Keening Apparition|Aparición atormentada|Criatura — Espíritu|Sacrificar la A Keening Banshee|Banshee atormentada|Criatura — Espíritu|Vuela.\nCuando la Banshee atormentada entre al campo de batalla, la criatura objetivo obtiene -2/-2 hasta el final del turno. Keening Stone|Piedra atormentadora|Artefacto|{5}, {T}: El jugador objetivo pone las X primeras cartas de su biblioteca en su cementerio, donde X es la cantidad de cartas en el cementerio de ese jugador. Keep Watch|Hacer guardia|Instantáneo|Roba una carta por cada criatura atacante. +Keeper of Fables|Custodio de las fábulas|Criatura — Felino|Siempre que una o más criaturas que no sean Humano que controlas hagan daño de combate a un jugador, roba una carta. Keeper of Kookus|Guardián de Kookus|| Keeper of Progenitus|Guardián de Progenitus|Criatura — Druida elfo|Siempre que un jugador gire una montaña, bosque o llanura para obtener maná, ese jugador agrega un maná a su reserva de maná de algún tipo que produzca esa tierra. Keeper of Tresserhorn|Custodio de Tresserhorn|| @@ -8466,6 +8493,7 @@ Kemba's Legion|Legión de Kemba|Criatura — Soldado felino|Vigilancia.\nLa Legi Kemba's Skyguard|Guardia celeste de Kemba|Criatura — Caballero felino|Vuela.\nCuando el Guardia celeste de Kemba entre al campo de batalla, ganas 2 vidas. Kemba, Kha Regent|Kemba, regente del Kha|Criatura legendaria — Clérigo felino|Al comienzo de tu mantenimiento, crea una ficha de criatura Felino blanca 2/2 por cada equipo anexado a Kemba, regente del Kha. Kemuri-Onna|Kemuri-Onna|Criatura - Espíritu|Cuando la Kemuri-Onna entre en juego, el jugador objetivo descarta una carta.\nSiempre que juegues un hechizo arcano o de Espíritu, puedes regresar la Kemuri-Onna a la mano de su propietario. +Kenrith's Transformation|La transformación de Kenrith|Encantamiento — Aura|Encantar criatura.\nCuando La transformación de Kenrith entre al campo de batalla, roba una carta.\nLa criatura encantada pierde todas las habilidades y es una criatura Alce verde con fuerza y resistencia base de 3/3. (Pierde todos los otros tipos de carta y de criatura.) Kenrith, the Returned King|Kenrith, el Rey Regresado|Criatura legendaria — Noble humano|{R}: Todas las criaturas ganan las habilidades de arrollar y prisa hasta el final del turno.\n{1}{G}: Pon un contador +1/+1 sobre la criatura objetivo.\n{2}{W}: El jugador objetivo gana 5 vidas.\n{3}{U}: El jugador objetivo roba una carta.\n{4}{B}: Pon en el campo de batalla bajo el control de su propietario la carta de criatura objetivo de un cementerio. Kentaro, the Smiling Cat|Kentaro, el gato sonriente|Criatura legendaria - Samurái humano|Bushido 1 (Cuando esta criatura bloquee o sea bloqueada, obtiene +1/+1 hasta el final del turno).\nPuedes pagar {X} en lugar de pagar el coste de maná de los hechizos de Samurái que juegues, donde X es el coste de maná convertido de ese hechizo. Keranos, God of Storms|Keranos, dios de las tormentas|Criatura encantamiento legendaria — Deidad|Indestructible.\nMientras tu devoción al azul y al rojo sea menor que siete, Keranos no es una criatura.\nMuestra la primera carta que robes en cada uno de tus turnos. Siempre que muestres una carta de tierra de esta manera, roba una carta. Siempre que muestres una carta que no sea tierra de esta manera, Keranos hace 3 puntos de daño a la criatura o jugador objetivo. @@ -8847,6 +8875,7 @@ Laquatus's Disdain|Desdén de Laquatus|Instantáneo|Contrarresta el hechizo obje Larceny|Latrocinio|Encantamiento|Siempre que una criatura que controles haga daño de combate a un jugador, ese jugador descarta una carta de su mano. Larger Than Life|Desmesura inusitada|Conjuro|La criatura objetivo obtiene +4/+4 y gana la habilidad de arrollar hasta el final del turno. Lash Out|Arrojar con violencia|Instantáneo|Arrojar con violencia hace 3 puntos de daño a la criatura objetivo. Enfréntate con un oponente. Si ganas, Arrojar con violencia hace 3 puntos de daño al controlador de la criatura. (Cada jugador enfrentado muestra la primera carta de su biblioteca, luego pone esa carta en la parte superior o inferior. Gana el jugador cuya carta tenga el mayor coste de maná convertido.) +Lash of Thorns|Latigazo espinoso|Instantáneo|La criatura objetivo obtiene +2/+1 y gana la habilidad de toque mortal hasta el final del turno. Lash of the Whip|Restallido de látigo|Instantáneo|La criatura objetivo obtiene -4/-4 hasta el final del turno. Lashknife Barrier|Barrera de cadena con cuchillo|| Lashknife|Cadena en cuchillo|| @@ -9202,9 +9231,11 @@ Lobber Crew|Lanzadores de boleas|Criatura — Guerrero trasgo|Defensor.\n{T}: Lo Lobotomy|Lobotomía|| Loch Dragon|Dragón del lago|Criatura — Dragón|Vuela.\nSiempre que el Dragón del lago entre al campo de batalla o ataque, puedes descartar una carta. Si lo haces, roba una carta. Loch Korrigan|Korrigan del lago|Criatura — Espíritu|{U/B}: La Korrigan del lago obtiene +1/+1 hasta el final del turno. +Lochmere Serpent|Serpiente de Lochmere|Criatura — Serpiente|Destello.\n{U}, sacrificar una Isla: La Serpiente de Lochmere no puede ser bloqueada este turno.\n{B}, sacrificar un Pantano: Ganas 1 vida y robas una carta.\n{U}{B}: Exilia cinco cartas objetivo del cementerio de un oponente. Regresa la Serpiente de Lochmere de tu cementerio a tu mano. Activa esta habilidad solo cuando puedas lanzar un conjuro. Locket of Yesterdays|Relicario del ayer|Artefacto|Te cuesta {1} menos jugar hechizos por cada carta con el mismo nombre que ese hechizo en tu cementerio. Lockjaw Snapper|Mordedor trampero|Criatura artefacto — Espantapájaros|Debilitar. (Esta fuente hace daño a las criaturas en forma de contadores -1/-1.)\nCuando el Mordedor trampero vaya a un cementerio desde el juego, pon un contador -1/-1 sobre cada criatura con un contador -1/-1 sobre ella. Locthwain Gargoyle|Gárgola de Nimboscuro|Criatura artefacto — Gárgola|{4}: La Gárgola de Nimboscuro obtiene +2/+0 y gana la habilidad de volar hasta el final del turno. +Locthwain Paladin|Paladín de Nimboscuro|Criatura — Caballero humano|Amenaza. (Esta criatura no puede ser bloqueada excepto por dos o más criaturas.)\nTesón — Si se usaron al menos tres manás negros para lanzar este hechizo, la Paladín de Nimboscuro entra al campo de batalla con un contador +1/+1 sobre ella. Locust Miser|Ávido de langostas|Criatura - Chamán rata|El tamaño máximo de mano de cada oponente se reduce en dos. Locust Swarm|Plaga de langostas|| Lodestone Bauble|Baratija imantada|| @@ -9252,6 +9283,7 @@ Lose Hope|Perder la esperanza|Instantáneo|La criatura objetivo obtiene -1/-1 ha Lost Auramancers|Auramantes perdidos|Criatura — Hechicero humano|Desmaterializarse 3 (Este permanente entra en juego con tres contadores de tiempo sobre él. Al comienzo de tu mantenimiento, remueve un contador de tiempo de él. Cuando sea removido el último, sacrifícalo.)
Cuando los Auramantes perdidos vayan a un cementerio desde el juego, si no tenían contadores de tiempo sobre ellos, puedes buscar en tu biblioteca una carta de encantamiento y ponerla en juego. Si lo haces, baraja tu biblioteca. Lost Hours|Horas perdidas|Conjuro|El jugador objetivo muestra su mano. Elige de ahí una carta que no sea tierra. Ese jugador pone esa carta en su biblioteca tercera desde la parte superior. Lost Legacy|Legado extraviado|Conjuro|Nombra una carta que no sea tierra ni artefacto. Busca en el cementerio, mano y biblioteca del jugador objetivo cualquier cantidad de cartas con ese nombre y exílialas. Ese jugador baraja su biblioteca y luego roba una carta por cada carta exiliada de su mano de esta manera. +Lost Legion|Legión perdida|Criatura — Caballero espíritu|Cuando la Legión perdida entre al campo de batalla, adivina 2. (Mira las dos primeras cartas de tu biblioteca, luego pon cualquier cantidad de ellas en el fondo de tu biblioteca y el resto en la parte superior en cualquier orden.) Lost Leonin|Leonino perdido|Criatura — Soldado felino|Infectar. (Esta criatura hace daño a las criaturas en forma de contadores -1/-1 y a los jugadores en forma de contadores de veneno.) Lost Order of Jarkeld|Orden Perdida de Jarkeld|| Lost Soul|Alma en pena|| @@ -9271,6 +9303,7 @@ Lotus Path Djinn|Djinn senda de loto|Criatura — Monje djinn|Vuela.\nDestreza. Lotus Petal|Pétalo de loto|| Lotus Vale|Valle de los lotos|| Lotus-Eye Mystics|Místicos ojo de loto|Criatura — Monje humano|Destreza. (Siempre que lances un hechizo que no sea de criatura, esta criatura obtiene +1/+1 hasta el final del turno.)\nCuando los Místicos ojo de loto entren al campo de batalla, regresa la carta de encantamiento objetivo de tu cementerio a tu mano. +Lovestruck Beast|Bestia enamoradiza|Criatura — Noble bestia|La Bestia enamoradiza no puede atacar a menos que controles una criatura 1/1. Lovisa Coldeyes|Lovisa Ojosfríos|Criatura legendaria — Señor humano|Los Bárbaros, Guerreros y Berserkers obtienen +2/+2 y tienen la habilidad de prisa. Lowland Basilisk|Basilisco de las tierras bajas|| Lowland Giant|Gigante de las tierras bajas|| @@ -9475,6 +9508,7 @@ Malakir Cullblade|Espadachín de Malakir|Criatura — Guerrero vampiro|Siempre q Malakir Familiar|Familiar de Malakir|Criatura — Murciélago|Vuela, toque mortal.Siempre que ganes vidas, el Familiar de Malakir obtiene +1/+1 hasta el final del turno. Malakir Soothsayer|Augur de Malakir|Criatura — Chamán vampiro aliado|Secuaz — {T}, girar un Aliado enderezado que controlas: Robas una carta y pierdes 1 vida. Malevolent Awakening|Despertar malevolente|Encantamiento|{1}{B}{B}, sacrificar una criatura: Regresa la carta objetivo de criatura de tu cementerio a tu mano. +Malevolent Noble|Noble malévolo|Criatura — Noble humano|{2}, sacrificar un artefacto u otra criatura: Pon un contador +1/+1 sobre el Noble malévolo. Malevolent Whispers|Susurros malevolentes|Conjuro|Gana el control de la criatura objetivo hasta el final del turno. Endereza esa criatura. Obtiene +2/+0 y gana la habilidad de prisa hasta el final del turno.\nDemencia {3}{R}. (Si descartas esta carta, exíliala. Cuando lo hagas, lánzala por su coste de demencia o ponla en tu cementerio.) Malfegor|Malfegor|Criatura legendaria — Dragón demonio|Vuela.\nCuando Malfegor entre al campo de batalla, descarta tu mano. Cada oponente sacrifica una criatura por cada carta descartada de esta manera. Malfunction|Avería|Encantamiento — Aura|Encantar artefacto o criatura.\nCuando la Avería entre al campo de batalla, gira el permanente encantado.\nEl permanente encantado no se endereza durante el paso de enderezar de su controlador. @@ -9550,6 +9584,8 @@ Mantle of Leadership|Manto de liderazgo|Encantamiento — Aura|Destello (Puedes Mantle of Tides|Manto de mareas|Artefacto — Equipo|La criatura equipada obtiene +1/+2.\nSiempre que robes tu segunda carta cada turno, anexa el Manto de mareas a la criatura objetivo que controlas.\nEquipar {3}. ({3}: Anexa este Equipo a la criatura objetivo que controlas. Activa la habilidad de equipar como un conjuro.) Mantle of Webs|Manto de telarañas|Encantamiento — Aura|Encantar criatura.La criatura encantada obtiene +1/+3 y tiene la habilidad de alcance. (Puede bloquear a criaturas con la habilidad de volar.) Map the Wastes|Explorar los yermos|Conjuro|Busca en tu biblioteca una carta de tierra básica, ponla en el campo de batalla girada y luego baraja tu biblioteca. Fortalece 1. (Elige la criatura con menor resistencia entre las criaturas que controlas y pon un contador +1/+1 sobre ella.) +Maraleaf Pixie|Duendecilla de Marahoja|Criatura — Hada|Vuela.\n{T}: Agrega {G} o {U}. +Maraleaf Rider|Jinete de Marahoja|Criatura — Caballero elfo|Sacrificar una Comida: La criatura objetivo bloquea a la Jinete de Marahoja este turno si puede. Maralen of the Mornsong|Maralen de los Mornsong|Criatura legendaria — Hechicero elfo|Los jugadores no pueden robar cartas.\nAl comienzo del paso de robar de cada jugador, ese jugador pierde 3 vidas, busca en su biblioteca una carta, la pone en su mano y luego baraja su biblioteca. Marang River Prowler|Rondador del río Marang|Criatura — Bribón humano|El Rondador del río Marang no puede bloquear y no puede ser bloqueado.\nPuedes lanzar el Rondador del río Marang desde tu cementerio mientras controles un permanente negro o verde. Marang River Skeleton|Esqueleto del río Marang|Criatura — Esqueleto|{B}: Regenera el Esqueleto del río Marang.\nMegametamorfosis {3}{B}. (Puedes lanzar esta carta boca abajo como una criatura 2/2 pagando {3}. Ponla boca arriba en cualquier momento pagando su coste de megametamorfosis y pon un contador +1/+1 sobre ella.) @@ -9777,6 +9813,7 @@ Memory Jar|Jarra del recuerdo|| Memory Lapse|Lapsus|| Memory Plunder|Saquear la memoria|Instantáneo|Puedes jugar la carta de instantáneo o de conjuro objetivo del cementerio de un oponente sin pagar su coste de maná. Memory Sluice|Anegar la memoria|Conjuro|El jugador objetivo pone las primeras cuatro cartas de su biblioteca en su cementerio.\nConspirar. (En cuanto juegues este hechizo puedes girar dos criaturas enderezadas que controles que compartan un color con él. Cuando lo hagas, cópialo y puedes elegir un nuevo objetivo para la copia.) +Memory Theft|Robo de recuerdos|Conjuro|El oponente objetivo muestra su mano. Tú eliges de ahí una carta que no sea tierra. Ese jugador descarta esa carta. Puedes poner en el cementerio de ese jugador desde el exilio una carta de la cual ese jugador sea propietario que tenga una Aventura. Memory's Journey|Viaje del recuerdo|Instantáneo|El jugador objetivo baraja hasta tres cartas objetivo de su cementerio en su biblioteca.\nRetrospectiva {G}. (Puedes lanzar esta carta desde tu cementerio pagando su coste de retrospectiva. Luego exíliala.) Memory|Recuerdo|Conjuro|Secuela. (Lanza este hechizo solo desde tu cementerio. Luego exílialo.)\nCada jugador baraja su mano y cementerio en su biblioteca, luego roba siete cartas. Menacing Ogre|Ogro amenazador|Criatura — Ogro|Arrolla, prisa.\nCuando el Ogro amenazador entre en juego, cada jugador elige un número en secreto. Luego se muestran esos números. Cada jugador con el número más alto pierde esa cantidad de vida. Si tú eres uno de esos jugadores, pon dos contadores +1/+1 sobre el Ogro amenazador. @@ -10368,6 +10405,7 @@ Murderous Betrayal|Traición asesina|Encantamiento|{B}{B}, pagar la mitad de tu Murderous Compulsion|Pulsión asesina|Conjuro|Destruye la criatura objetivo girada.\nDemencia {1}{B}. (Si descartas esta carta, exíliala. Cuando lo hagas, lánzala por su coste de demencia o ponla en tu cementerio.) Murderous Cut|Tajo asesino|Instantáneo|Excavar. (Cada carta que exilies de tu cementerio al lanzar este hechizo cuenta como un pago de {1}.)\nDestruye la criatura objetivo. Murderous Redcap|Asesino gorro rojo|Criatura — Asesino trasgo|Cuando el Asesino gorro rojo entre en juego le hace una cantidad de daño igual a su fuerza a la criatura o jugador objetivo.\nPersistir. (Cuando esta criatura vaya a un cementerio desde el juego, si no tenía contadores -1/-1 sobre ella, regrésala al juego bajo el control de su propietario con un contador -1/-1.) +Murderous Rider|Jinete homicida|Criatura — Caballero zombie|Vínculo vital.\nCuando la Jinete homicida muera, ponla en el fondo de la biblioteca de su propietario. Murderous Spoils|Despojos asesinos|Instantáneo|Destruye la criatura objetivo que no sea negra. No puede ser regenerada. Ganas el control de todo el equipo anexado a ella. (Este efecto no termina al final del turno.) Murder|Asesinato|Instantáneo|Destruye la criatura objetivo. Murk Dwellers|Moradores de las tinieblas|| @@ -10909,9 +10947,11 @@ Nyxborn Wolf|Loba nativa de Nyx|Criatura encantamiento — Lobo|Concesión {4}{G O-Kagachi, Vengeful Kami|O-Kagachi, kami vengativo|Criatura legendaria — Espíritu dragón|Vuela, arrolla.\nSiempre que O-Kagachi, kami vengativo haga daño de combate a un jugador, si ese jugador te atacó durante su último turno, exilia el permanente objetivo que no sea tierra que controla ese jugador. O-Naginata|O-Naginata|Artefacto - Equipo|O-Naginata puede ser anexada sólo a una criatura con fuerza 3 o más.\nLa criatura equipada obtiene +3/+0 y tiene la habilidad de arrollar.\nEquipar {2} ({2}: Anexa este equipo a la criatura objetivo que controles. Juega la habilidad de equipar como un conjuro). Oak Street Innkeeper|Tabernera de la Calle Roble|Criatura — Elfo|Mientras no sea tu turno, las criaturas giradas que controlas tienen la habilidad de antimaleficio. +Oaken Boon|Bendición del roble|Conjuro — Aventura|Pon dos contadores +1/+1 sobre la criatura objetivo. (Luego, exilia esta carta. Puedes lanzar la criatura más adelante desde el exilio.) Oaken Brawler|Roble pendenciero|Criatura — Guerrero pueblo-arbóreo|Cuando el Roble pendenciero entre en juego, enfréntate con un oponente. Si ganas, pon un contador +1/+1 sobre el Roble pendenciero. (Cada jugador enfrentado muestra la primera carta de su biblioteca, luego pone esa carta en la parte superior o inferior. Gana el jugador cuya carta tenga el mayor coste de maná convertido.) Oakenform|Forma de roble|Encantamiento — Aura|Encantar criatura.\nLa criatura encantada obtiene +3/+3. Oakgnarl Warrior|Guerrero nudo de roble|Criatura — Guerrero pueblo-arbóreo|Vigilancia, arrolla. +Oakhame Adversary|Adversario de Roblehogar|Criatura — Guerrero elfo|Te cuesta {2} lanzar este hechizo si un oponente controla un permanente verde.\nToque mortal.\nSiempre que el Adversario de Roblehogar haga daño de combate a un jugador, roba una carta. Oakhame Ranger|Guardabosque de Roblehogar|Criatura — Caballero elfo|{T}: Las criaturas que controlas obtienen +1/+1 hasta el final del turno. Oakheart Dryads|Dríadas corarroble|Criatura encantamiento — Dríada ninfa|Constelación — Siempre que las Dríadas corarroble u otro encantamiento entren al campo de batalla bajo tu control, la criatura objetivo gana +1/+1 hasta el final del turno. Oashra Cultivator|Cultivadora de Oashra|Criatura — Druida humano|{2}{G}, {T}, sacrificar la Cultivadora de Oashra: Busca en tu biblioteca una carta de tierra básica, ponla en el campo de batalla girada y luego baraja tu biblioteca. @@ -10934,6 +10974,7 @@ Oath of Teferi|Juramento de Teferi|Encantamiento legendario|Cuando el Juramento Oath of the Ancient Wood|Juramento de madera antigua|Encantamiento|Siempre que el Juramento de madera antigua u otro encantamiento entre al campo de batalla bajo tu control, puedes poner un contador +1/+1 sobre la criatura objetivo. Oathkeeper, Takeno's Daisho|Guardián de promesas, daisho de Takeno|Artefacto legendario - Equipo|La criatura equipada obtiene +3/+1.\nSiempre que la criatura equipada sea puesta en un cementerio desde el juego, si es una carta de Samurái, regresa esa carta al juego bajo tu control.\nCuando Guardián de promesas, daisho de Takeno vaya a un cementerio desde el juego, remueve del juego la criatura equipada.\nEquipar {2}. Oathsworn Giant|Gigante jurado|Criatura — Soldado gigante|Vigilancia.\nLas otras criaturas que controlas obtienen +0/+2 y tienen vigilancia. +Oathsworn Knight|Caballero jurado|Criatura — Caballero humano|El Caballero jurado entra al campo de batalla con cuatro contadores +1/+1 sobre él.\nEl Caballero jurado ataca cada combate si puede.\nSi el Caballero jurado fuera a recibir daño mientras tiene un contador +1/+1 sobre él, prevén ese daño y remueve un contador +1/+1 de él. Oathsworn Vampire|Vampiro jurado|Criatura — Caballero vampiro|El Vampiro jurado entra al campo de batalla girado.\nPuedes lanzar el Vampiro jurado desde tu cementerio si ganaste vidas este turno. Ob Nixilis Reignited|Ob Nixilis reavivado|Planeswalker legendario — Nixilis|+1: Robas una carta y pierdes 1 vida.\n−3: Destruye la criatura objetivo.\n−8: El oponente objetivo obtiene un emblema con "Siempre que un jugador robe una carta, pierdes 2 vidas". Ob Nixilis of the Black Oath|Ob Nixilis del juramento sombrío|Planeswalker — Nixilis|+2: Cada oponente pierde 1 vida. Ganas una cantidad de vidas igual a las vidas perdidas de esta manera.\n-2: Pon en el campo de batalla una ficha de criatura Demonio negra 5/5 con la habilidad de volar. Pierdes 2 vidas.\n-8: Obtienes un emblema con "{1}{B}, sacrificar una criatura: Ganas X vidas y robas X cartas, donde X es la fuerza de la criatura sacrificada".\nOb Nixilis del juramento sombrío puede ser tu comandante. @@ -11030,6 +11071,7 @@ Okina, Temple to the Grandfathers|Okina, templo a los antepasados|Tierra legenda Okk|Okk|Criatura — Trasgo|El Okk no puede atacar a menos que también ataque una criatura con mayor fuerza que él.\nEl Okk no puede bloquear a menos que también bloquee una criatura con mayor fuerza que él. Oko's Accomplices|Cómplices de Oko|Criatura — Hada|Vuela. Oko's Hospitality|Hospitalidad de Oko|Instantáneo|Las criaturas que controlas tienen una fuerza y resistencia base de 3/3 hasta el final del turno. Puedes buscar en tu biblioteca y/o cementerio una carta llamada Oko, el Embaucador, mostrarla y ponerla en tu mano. Si buscas en tu biblioteca de esta manera, barájala. +Oko, Thief of Crowns|Oko, Ladrón de Coronas|Planeswalker legendario — Oko|+2: Crea una ficha de Comida.\n+1: El artefacto o criatura objetivo pierde todas las habilidades y se convierte en una criatura Alce verde con fuerza y resistencia base de 3/3.\n−5: Intercambia el control del artefacto o criatura objetivo que controlas y la criatura objetivo con fuerza de 3 o menos que controla un oponente. Oko, the Trickster|Oko, el Embaucador|Planeswalker legendario — Oko|+1: Pon dos contadores +1/+1 sobre hasta una criatura objetivo que controlas.\n0: Hasta el final del turno, Oko, el Embaucador se convierte en una copia de la criatura objetivo que controlas. Prevén todo el daño que se le fuera a hacer este turno.\n−7: Hasta el final del turno, cada criatura que controlas tiene una fuerza y resistencia base de 10/10 y gana la habilidad de arrollar. Old Ghastbark|Cortezapálida anciano|Criatura — Guerrero pueblo-arbóreo| Old-Growth Dryads|Dríadas de la espesura antigua|Criatura — Dríada|Cuando las Dríadas de la espesura antigua entren al campo de batalla, cada oponente puede buscar en su biblioteca una carta de tierra básica, ponerla en el campo de batalla girada y luego barajar su biblioteca. @@ -11055,6 +11097,8 @@ On Serra's Wings|Con las alas de Serra|Encantamiento legendario — Aura|Encanta On Thin Ice|Situación delicada|Encantamiento nevado — Aura|Encantar tierra nevada que controlas.\nCuando la Situación delicada entre al campo de batalla, exilia la criatura objetivo que controla un oponente hasta que la Situación delicada deje el campo de batalla. Onakke Catacomb|Catacumba Onakke|Plano — Shandalar|Todas las criaturas son negras y tienen la habilidad de toque mortal.\nSiempre que lances caos, las criaturas que controlas obtienen +1/+0 y ganan la habilidad de dañar primero hasta el final del turno. Onakke Ogre|Ogro onakke|Criatura — Guerrero ogro| +Once Upon a Time|Había una vez|Instantáneo|Si este hechizo es el primer hechizo que lanzas este juego, puedes lanzarlo sin pagar su coste de maná.\nMira las cinco primeras cartas de tu biblioteca. Puedes mostrar una carta de criatura o de tierra que se encuentre entre ellas y ponerla en tu mano. Pon el resto en el fondo de tu biblioteca en un orden aleatorio. +Once and Future|Pasado y futuro|Instantáneo|Regresa la carta objetivo de tu cementerio a tu mano. Pon hasta otra carta objetivo de tu cementerio en la parte superior de tu biblioteca. Exilia el Pasado y futuro.\nTesón — Si se usaron al menos tres manás verdes para lanzar este hechizo, en vez de eso, regresa esas cartas a tu mano y exilia el Pasado y futuro. Ondu Champion|Campeón de Ondu|Criatura — Guerrero minotauro aliado|Alianza — Siempre que el Campeón de Ondu u otro Aliado entre al campo de batalla bajo tu control, las criaturas que controlas ganan la habilidad de arrollar hasta el final del turno. Ondu Cleric|Clérigo de Ondu|Criatura — Clérigo kor aliado|Siempre que el Clérigo de Ondu u otro Aliado entre al campo de batalla bajo tu control, puedes ganar vidas igual a la cantidad de Aliados que controles. Ondu Giant|Gigante de Ondu|Criatura — Druida gigante|Cuando el Gigante de Ondu entre al campo de batalla, puedes buscar en tu biblioteca una carta de tierra básica, ponerla en el campo de batalla girada y luego barajar tu biblioteca. @@ -11165,6 +11209,7 @@ Ordeal of Heliod|Ordalía de Heliod|Encantamiento — Aura|Encantar criatura.\nS Ordeal of Nylea|Ordalía de Nylea|Encantamiento — Aura|Encantar criatura.\nSiempre que la criatura encantada ataque, pon un contador +1/+1 sobre ella. Luego, si tiene tres o más contadores +1/+1 sobre ella, sacrifica la Ordalía de Nylea.\nCuando sacrifiques la Ordalía de Nylea, busca en tu biblioteca hasta dos cartas de tierra básica, ponlas en el campo de batalla giradas y luego baraja tu biblioteca. Ordeal of Purphoros|Ordalía de Purforos|Encantamiento — Aura|Encantar criatura.\nSiempre que la criatura encantada ataque, pon un contador +1/+1 sobre ella. Luego, si tiene tres o más contadores +1/+1 sobre ella, sacrifica la Ordalía de Purforos.\nCuando sacrifiques la Ordalía de Purforos, hace 3 puntos de daño a la criatura o jugador objetivo. Ordeal of Thassa|Ordalía de Tassa|Encantamiento — Aura|Encantar criatura.\nSiempre que la criatura encantada ataque, pon un contador +1/+1 sobre ella. Luego, si tiene tres o más contadores +1/+1 sobre ella, sacrifica la Ordalía de Tassa.\nCuando sacrifiques la Ordalía de Tassa, roba dos cartas. +Order of Midnight|Orden de la Medianoche|Criatura — Caballero humano|Vuela.\nLa Orden de la Medianoche no puede bloquear. Order of Succession|Orden sucesorio|Conjuro|Elige izquierda o derecha. Comenzando contigo y siguiendo en la dirección elegida, cada jugador elige una criatura controlada por el siguiente jugador en esa dirección. Cada jugador gana el control de la criatura que eligió. Order of Whiteclay|Orden del Barro Blanco|Criatura — Clérigo kithkin|{1}{W}{W}, {Q}: Regresa la carta de criatura objetivo con coste de maná convertido de 3 o menos de tu cementerio al juego. ({Q} es el símbolo de enderezar.) Order of Yawgmoth|Orden de Yawgmoth|| @@ -11235,7 +11280,9 @@ Outbreak|Brote|| Outflank|Flanquear|Instantáneo|Flanquear hace una cantidad de daño a la criatura atacante o bloqueadora objetivo igual a la cantidad de criaturas que controlas. Outland Boar|Jabalí de provincia|Criatura — Jabalí|El Jabalí de provincia no puede ser bloqueado por criaturas con fuerza de 2 o menos. Outland Colossus|Coloso forastero|Criatura — Gigante|Prestigio 6. (Cuando esta criatura haga daño de combate a un jugador, si no tiene prestigio, pon seis contadores +1/+1 sobre ella y gana prestigio.)El Coloso forastero no puede ser bloqueado por más de una criatura. +Outlaws' Merriment|Alegría de los forajidos|Encantamiento|Al comienzo de tu mantenimiento, elige una opción al azar. Crea una ficha de criatura roja y blanca con esas características.\n• Guerrero Humano 3/1 con las habilidades de arrollar y prisa.\n• Clérigo Humano 2/1 con las habilidades de vínculo vital y prisa.\n• Bribón Humano 1/2 con la habilidad de prisa y "Cuando esta criatura entre al campo de batalla, hace 1 punto de daño a cualquier objetivo". Outmaneuver|Maniobrar mejor|| +Outmuscle|Fuerza superior|Conjuro|Pon un contador +1/+1 sobre la criatura objetivo que controlas. Luego, lucha contra la criatura objetivo que no controlas. (Cada una hace un daño igual a su fuerza a la otra.)\nTesón — Si se usaron al menos tres manás verdes para lanzar este hechizo, la criatura que controlas gana la habilidad de indestructible hasta el final del turno. Outnumber|Superar en número|Instantáneo|Superar en número hace una cantidad de daño a la criatura objetivo igual a las criaturas que controlas. Outpost Siege|Asedio al destacamento|Encantamiento|En cuanto el Asedio al destacamento entre al campo de batalla, elige kans o dragones.\n• Kans — Al comienzo de tu mantenimiento, exilia la primera carta de tu biblioteca. Hasta el final del turno, puedes jugar esa carta.\n• Dragones — Siempre que una criatura que controlas deje el campo de batalla, el Asedio al destacamento hace 1 punto de daño a la criatura o el jugador objetivo. Outrage Shaman|Chamán del ultraje|Criatura — Chamán trasgo|Croma Cuando la Chamán del ultraje entre en juego, hace daño a la criatura objetivo igual a la cantidad de símbolos de maná rojo en los costes de maná de los permanentes que controles. @@ -11975,6 +12022,7 @@ Prodigal Pyromancer|Piromante pródigo|Criatura — Hechicero humano|{T}: El Pir Prodigal Sorcerer|Hechicero pródigo|Criatura — Hechicero humano|{T}: El Hechicero pródigo hace 1 punto de daño a la criatura o jugador objetivo. Prodigious Growth|Crecimiento prodigioso|Encantamiento — Aura|Encantar criatura.\nLa criatura encantada obtiene +7/+7 y tiene la habilidad de arrollar. Profane Command|Dictado profano|Conjuro|Elige dos: El jugador objetivo pierde X vidas; o regresa al juego la carta de criatura objetivo con coste de maná convertido de X o menos de tu cementerio; o la criatura objetivo obtiene -X/-X hasta el final del turno; o hasta X criaturas objetivo ganan la habilidad de inspirar temor hasta el final del turno. +Profane Insight|Visión profana|Instantáneo — Aventura|Robas una carta y pierdes 1 vida. (Luego, exilia esta carta. Puedes lanzar la criatura más adelante desde el exilio.) Profane Memento|Recuerdo profano|Artefacto|Siempre que una carta de criatura vaya al cementerio de un oponente desde cualquier parte, ganas 1 vida. Profane Prayers|Plegarias profanas|Conjuro|Las Plegarias profanas hacen X puntos de daño a la criatura o jugador objetivo y ganas X vidas, donde X es el número de Clérigos en juego. Profane Procession|Procesión profana|Encantamiento legendario|{3}{W}{B}: Exilia la criatura objetivo. Luego, si hay tres o más cartas exiliadas con la Procesión profana, transfórmala. @@ -12193,6 +12241,7 @@ Quest for the Goblin Lord|Búsqueda del Señor trasgo|Encantamiento|Siempre que Quest for the Gravelord|Búsqueda del Señor de la Tumba|Encantamiento|Siempre que una criatura vaya a un cementerio desde el campo de batalla, puedes poner un contador de búsqueda sobre la Búsqueda del Señor de la Tumba.\nRemover tres contadores de búsqueda del Búsqueda del Señor de la Tumba y sacrificarla: Pon en el campo de batalla una ficha de criatura Gigante Zombie negra 5/5. Quest for the Holy Relic|Búsqueda de la reliquia sagrada|Encantamiento|Siempre que lances un hechizo de criatura, puedes poner un contador de búsqueda sobre la Búsqueda de la reliquia sagrada.\nRemover cinco contadores de búsqueda de la Búsqueda de la reliquia sagrada y sacrificarla: Busca en tu biblioteca una carta de equipo, ponla en el campo de batalla, y anéxala a una criatura que controles. Luego baraja tu biblioteca. Quest for the Nihil Stone|Búsqueda de la piedra nihil|Encantamiento|Siempre que un oponente descarte una carta, puedes poner un contador de búsqueda sobre la Búsqueda de la piedra nihil.\nAl comienzo del mantenimiento de cada oponente, si ese jugador no tiene cartas en su mano y la Búsqueda de la piedra nihil tiene dos o más contadores de búsqueda sobre ella, puedes hacer que ese jugador pierda 5 vidas. +Questing Beast|La Bestia Buscada|Criatura legendaria — Bestia|Vigilancia, toque mortal, prisa.\nLa Bestia Buscada no puede ser bloqueada por criaturas con fuerza de 2 o menos.\nEl daño de combate que fueran a hacer las criaturas que controlas no puede ser prevenido.\nSiempre que La Bestia Buscada haga daño de combate a un oponente, hace esa misma cantidad de daño al planeswalker objetivo que controla ese jugador. Questing Phelddagrif|Phelddagrif Buscador|| Quick Sliver|Fragmentado veloz|Criatura — Fragmentado|Puedes jugar el Fragmentado veloz en cualquier momento en que pudieras jugar un instantáneo.\nCualquier jugador puede jugar cartas de Fragmentado en cualquier momento en que pudiera jugar un instantáneo. Quickchange|Cambio rápido|Instantáneo|El color de la criatura objetivo es el color o colores de tu elección hasta el final del turno.\nRoba una carta. @@ -12784,6 +12833,7 @@ Retrofitter Foundry|Fundición reconvertidora|Artefacto|{3}: Endereza la Fundici Retromancer|Retromante|| Return from Extinction|Regresar de la extinción|Conjuro|Elige uno:\n• Regresa la carta de criatura objetivo de tu cementerio a tu mano.\n• Regresa dos cartas de criatura objetivo que comparten un tipo de criatura de tu cementerio a tu mano. Return of the Nightstalkers|Regrero de los cazadores nocturnos|| +Return of the Wildspeaker|Regreso del Portavoz Salvaje|Instantáneo|Elige uno:\n• Roba una cantidad de cartas igual a la mayor fuerza entre las criaturas que no sean Humano que controlas.\n• Las criaturas que no sean Humano que controlas obtienen +3/+3 hasta el final del turno. Return to Dust|Volver al polvo|Instantáneo|Exilia el artefacto o encantamiento objetivo. Si lanzas este hechizo durante tu fase principal, puedes exiliar otro artefacto o encantamiento objetivo. Return to Nature|Regreso a la naturaleza|Instantáneo|Elige uno:\n• Destruye el artefacto objetivo.\n• Destruye el encantamiento objetivo.\n• Exilia la carta objetivo de un cementerio. Return to the Earth|Regreso a la tierra|Instantáneo|Destruye el artefacto, encantamiento o criatura con la habilidad de volar objetivo. @@ -13099,6 +13149,8 @@ Rootwater Shaman|Chamán de Raicesanegadas|| Rootwater Thief|Ladrón de Raicesanegadas|| Rorix Bladewing|Rórix Alacortante|Criatura — Dragón legendario|Vuela, prisa. Rosemane Centaur|Centauro melena de rosas|Criatura — Soldado centauro|Convocar. (Tus criaturas pueden ayudar a lanzar este hechizo. Cada criatura que gires al lanzar este hechizo cuenta como un pago de {1} o de un maná del color de esa criatura.)\nVigilancia. +Rosethorn Acolyte|Acólita de espinas de rosa|Criatura — Druida elfo|{T}: Agrega un maná de cualquier color. +Rosethorn Halberd|Alabarda de espinas de rosa|Artefacto — Equipo|Cuando la Alabarda de espinas de rosa entre al campo de batalla, anéxala a la criatura objetivo que no sea Humano que controlas.\nLa criatura equipada obtiene +2/+1.\nEquipar {5}. ({5}: Anexa este Equipo a la criatura objetivo que controlas. Activa la habilidad de equipar como un conjuro.) Rosheen Meanderer|Rosheen Meanderer|Criatura legendaria — Chamán gigante|{T}: Agrega {4} a tu reserva de maná. Usa este maná sólo en costes que contengan {X}. Rot Farm Skeleton|Esqueleto de podredumbre|Criatura — Esqueleto planta|El Esqueleto de podredumbre no puede bloquear.\n{2}{B}{G}, poner las primeras cuatro cartas de tu biblioteca en tu cementerio: Regresa el Esqueleto de podredumbre de tu cementerio al campo de batalla. Activa esta habilidad sólo cuando puedas lanzar un conjuro. Rot Shambler|Reptador pútrido|Criatura — Hongo|Siempre que otra criatura que controles muera, pon un contador +1/+1 sobre el Reptador pútrido. @@ -13724,6 +13776,7 @@ Seaside Citadel|Ciudadela costera|Tierra|La Ciudadela costera entra al campo de Seaside Haven|Refugio costero|Tierra|{T}: Agrega {1} a tu reserva de maná.\n{W}{U}, {T}, sacrificar un Ave: Roba una carta. Seasinger|Sirena|| Season of Growth|Estación de crecimiento|Encantamiento|Siempre que una criatura entre al campo de batalla bajo tu control, adivina 1. (Mira la primera carta de tu biblioteca. Puedes poner esa carta en el fondo de tu biblioteca.)\nSiempre que lances un hechizo que haga objetivo a una criatura que controlas, roba una carta. +Seasonal Ritual|Ritual de temporada|Conjuro — Aventura|Agrega un maná de cualquier color. (Luego, exilia esta carta. Puedes lanzar la criatura más adelante desde el exilio.) Seasoned Marshal|Mariscal competente|| Seasoned Pyromancer|Piromante experimentado|Criatura — Chamán humano|Cuando el Piromante experimentado entre al campo de batalla, descarta dos cartas, luego roba dos cartas. Por cada carta que no sea tierra descartada de esta manera, crea una ficha de criatura Elemental roja 1/1.\n{3}{R}{R}, exiliar el Piromante experimentado de tu cementerio: Crea dos fichas de criatura Elemental rojas 1/1. Seasoned Tactician|Estratega experimentado|| @@ -14072,6 +14125,7 @@ Shield of the Avatar|Escudo del avatar|Artefacto — Equipo|Si una fuente fuera Shield of the Oversoul|Escudo del Alma suprema|Encantamiento — Aura|Encantar criatura.\nMientras la criatura encantada sea verde, obtiene +1/+1 y es indestructible. (Los efectos que dicen "destruir" y el daño letal no la destruyen. Si su resistencia es 0 o menos, igual va al cementerio de su propietario.)\nMientras la criatura encantada sea blanca, obtiene +1/+1 y tiene la habilidad de volar. Shield of the Realm|Escudo del reino|Artefacto — Equipo|Si una fuente fuera a hacerle daño a la criatura equipada, prevén 2 puntos de ese daño.\nEquipar {1}. Shield of the Righteous|Escudo de los justos|Artefacto — Equipo|La criatura equipada obtiene +0/+2 y tiene la habilidad de vigilancia.\nSiempre que la criatura equipada bloquee a una criatura, esa criatura no se endereza durante el próximo paso de enderezar de su controlador.\nEquipar {2}. +Shield's Might|Poder del escudo|Instantáneo — Aventura|La criatura objetivo obtiene +2/+2 hasta el final del turno. (Luego, exilia esta carta. Puedes lanzar la criatura más adelante desde el exilio.) Shielded Aether Thief|Ladrón de éter con escudo|Criatura — Bribón vedalken|Destello. (Puedes lanzar este hechizo en cualquier momento en que pudieras lanzar un instantáneo.)\nSiempre que el Ladrón de éter con escudo bloquee, obtienes {E} (un contador de energía).\n{T}, pagar {E}{E}{E}: Roba una carta. Shielded Passage|Pasaje protegido|Instantáneo|Prevén todo el daño que se le fuera a hacer a la criatura objetivo este turno. Shielded by Faith|Resguardado por la fe|Encantamiento — Aura|Encantar criatura.La criatura encantada tiene la habilidad de indestructible.Siempre que una criatura entre al campo de batalla, puedes anexarle Resguardado por la fe a esa criatura. @@ -15139,7 +15193,7 @@ Spore Burst|Estallido de esporas|Conjuro|Dominio Pon en juego una ficha de criat Spore Frog|Rana de Esporas|| Spore Swarm|Enjambre de esporas|Instantáneo|Crea tres fichas de criatura Saprolín verdes 1/1. Sporeback Troll|Trol espalda de esporas|Criatura — Trol mutante|Injertar 2 (Esta criatura entra en juego con dos contadores +1/+1 sobre ella. Siempre que otra criatura entre en juego, puedes mover un contador +1/+1 de esta criatura a esa.)\n{1}{G}: Regenera la criatura objetivo con un contador +1/+1 sobre ella. -Sporecap Spider|Araña cubierta de esporas|Criatura — Araña|Alcance. (Esta criatura puede bloquear criaturas con la habilidad de volar.) +Sporecap Spider|Araña cubierta de esporas|Criatura — Araña|Alcance. Sporecrown Thallid|Tálido corona de esporas|Criatura — Hongo|Cada otra criatura que controlas que sea Hongo o Saprolín obtiene +1/+1. Sporemound|Montículo de esporas|Criatura — Hongo|Siempre que una tierra entre al campo de batalla bajo tu control, pon en el campo de batalla una ficha de criatura Saprolin verde 1/1. Sporesower Thallid|Tálido siembraesporas|Criatura — Hongo|Al comienzo de tu mantenimiento, pon un contador de espora sobre cada Hongo que controlas.\nRemover tres contadores de espora del Tálido siembraesporas: Pon en juego una ficha de criatura Saprolín verde 1/1. @@ -15746,6 +15800,7 @@ Swell of Growth|Ola de crecimiento|Instantáneo|La criatura objetivo obtiene +2/ Sweltering Suns|Soles abrasadores|Conjuro|Los Soles abrasadores hacen 3 puntos de daño a cada criatura.\nCiclo {3}. ({3}, descartar esta carta: Roba una carta.) Swelter|Sofocarse de calor|Conjuro|El Sofocarse de calor hace 2 puntos de daño a cada una de dos criaturas objetivo. Swerve|Virar|Instantáneo|Cambia el objetivo del hechizo objetivo que tenga un solo objetivo. +Swift End|Deceso rápido|Instantáneo — Aventura|Destruye la criatura o planeswalker objetivo. Pierdes 2 vidas. (Luego, exilia esta carta. Puedes lanzar la criatura más adelante desde el exilio.) Swift Justice|Justicia rápida|Instantáneo|Hasta el final del turno, la criatura objetivo obtiene +1/+0 y gana las habilidades de dañar primero y vínculo vital. Swift Kick|Patada repentina|Instantáneo|La criatura objetivo que controlas obtiene +1/+0 hasta el final del turno. Esa criatura lucha contra la criatura objetivo que no controlas. Swift Maneuver|Maniobra rápida|Instantáneo|Prevén los siguientes 2 puntos de daño que fueran a ser hechos a la criatura o jugador objetivo este turno.\nRoba una carta al comienzo del mantenimiento del próximo turno. @@ -15835,6 +15890,7 @@ Syphon Soul|Alma de sifón|| Syr Alin, the Lion's Claw|Syr Alin, la Garra del León|Criatura legendaria — Caballero humano|Daña primero.\nSiempre que Syr Alin, la Garra del León ataque, las otras criaturas que controlas obtienen +1/+1 hasta el final del turno. Syr Carah, the Bold|Syr Carah, la Osada|Criatura legendaria — Caballero humano|Siempre que Syr Carah, la Osada o un hechizo de instantáneo o de conjuro que controlas haga daño a un jugador, exilia la primera carta de tu biblioteca. Puedes jugar esa carta este turno.\n{T}: Syr Carah hace 1 punto de daño a cualquier objetivo. Syr Elenora, the Discerning|Syr Elenora, la Perspicaz|Criatura legendaria — Caballero humano|La fuerza de Syr Elenora, la Perspicaz es igual a la cantidad de cartas en tu mano.\nCuando Syr Elenora entre al campo de batalla, roba una carta.\nA tus oponentes les cuesta {2} más lanzar hechizos que hagan objetivo a Syr Elenora. +Syr Faren, the Hengehammer|Syr Faren, la Maza del Crómlech|Criatura legendaria — Caballero humano|Siempre que Syr Faren, la Maza del Crómlech ataque, otra criatura atacante objetivo obtiene +X/+X hasta el final del turno, donde X es la fuerza de Syr Faren. Syr Konrad, the Grim|Syr Konrad, el Tétrico|Criatura legendaria — Caballero humano|Siempre que otra criatura muera, que una carta de criatura vaya a un cementerio desde cualquier parte que no sea el campo de batalla, o que una carta de criatura deje tu cementerio, Syr Konrad, el Tétrico hace 1 punto de daño a cada oponente.\n{1}{B}: Cada jugador pone la primera carta de su biblioteca en su cementerio. Szadek, Lord of Secrets|Szadek, señor de los secretos|Criatura legendaria — Vampiro|Vuela.\nSi Szadek, señor de los secretos fuera a hacer daño de combate a un jugador, en vez de eso, pon esa misma cantidad de contadores +1/+1 sobre Szadek y ese jugador pone esa misma cantidad de cartas de la parte superior de su biblioteca en su cementerio. Séance|Sesión de espiritismo|Encantamiento|Al comienzo de cada mantenimiento, puedes exiliar la carta de criatura objetivo de tu cementerio. Si lo haces, pon en el campo de batalla una ficha que es una copia de esa carta, excepto que es un Espíritu además de sus otros tipos. Exíliala al comienzo del próximo paso final. @@ -15901,6 +15957,7 @@ Talisman of Indulgence|Talismán de la indulgencia|Artefacto|{T}: Agrega {1} a t Talisman of Progress|Talismán del progreso|Artefacto|{T}: Agrega {1} a tu reserva de maná.{T}: Agrega {W} o {U} a tu reserva de maná.\n El Talismán del progreso te hace 1 punto de daño. Talisman of Resilience|Talismán de resiliencia|Artefacto|{T}: Agrega {C}.\n{T}: Agrega {B} o {G}. El Talismán de resiliencia te hace 1 punto de daño. Talisman of Unity|Talismán de la unidad|Artefacto|{T}: Agrega {1} a tu reserva de maná.{T}: Agrega {G} o {W} a tu reserva de maná.\n El Talismán de la unidad te hace 1 punto de daño. +Tall as a Beanstalk|Crecer con habichuelas mágicas|Encantamiento — Aura|Encantar criatura.\nLa criatura encantada obtiene +3/+3, tiene la habilidad de alcance y es un Gigante además de sus otros tipos. Tallowisp|Centella de sebo|Criatura - Espíritu|Siempre que juegues un hechizo arcano o de Espíritu, puedes buscar una carta de encantar criatura en tu biblioteca, mostrarla y ponerla en tu mano. Si lo haces, baraja tu biblioteca. Talon Gates|Portal de Garras|Plano — Dominaria|En cualquier momento en que pudieras lanzar un conjuro, puedes exiliar con X contadores de tiempo sobre ella una carta que no sea tierra de tu mano, donde X es su coste de maná convertido. Si la carta exiliada no tiene la habilidad de suspender, gana suspender. (Al comienzo del mantenimiento de su propietario, remueve un contador de tiempo. Cuando sea removido el último, el jugador la lanza sin pagar su coste de maná. Si es una criatura, tiene la habilidad de prisa.)\nSiempre que lances caos, remueve dos contadores de tiempo de cada carta suspendida de la cual eres propietario. Talon Sliver|Fragmentado de las garras|| @@ -16212,6 +16269,7 @@ The Fourth Sphere|La Cuarta Esfera|Plano — Pirexia|Al comienzo de tu mantenimi The Gitrog Monster|El monstruo Gitrog|Criatura legendaria — Horror rana|Toque mortal.\nAl comienzo de tu mantenimiento, sacrifica a El monstruo Gitrog a menos que sacrifiques una tierra.\nPuedes jugar una tierra adicional en cada uno de tus turnos.\nSiempre que una o más cartas de tierra vayan a tu cementerio desde cualquier parte, roba una carta. The Great Aurora|La Gran Aurora|Conjuro|Cada jugador baraja todas las cartas de su mano y todos los permanentes de los que es propietario en su biblioteca, luego roba esa misma cantidad de cartas. Cada jugador puede poner cualquier cantidad de cartas de tierra de su mano en el campo de batalla. Exilia La Gran Aurora. The Great Forest|El Gran Bosque|Plano — Lorwyn|Cada criatura asigna daño de combate igual a su resistencia en lugar de su fuerza.\nSiempre que lances caos, las criaturas que controlas obtienen +0/+2 y ganan la habilidad de arrollar hasta el final del turno. +The Great Henge|El Gran Crómlech|Artefacto legendario|Te cuesta {X} menos lanzar este hechizo, donde X es la mayor fuerza entre las criaturas que controlas.\n{T}: Agrega {G}{G}. Ganas 2 vidas.\nSiempre que una criatura que no sea ficha entre al campo de batalla bajo tu control, pon un contador +1/+1 sobre ella y roba una carta. The Haunt of Hightower|El Espanto de la torre alta|Criatura legendaria — Vampiro|Vuela, vínculo vital.\nSiempre que El Espanto de la torre alta ataque, el jugador defensor descarta una carta.\nSiempre que una carta vaya al cementerio de un oponente desde cualquier parte, pon un contador +1/+1 sobre El Espanto de la torre alta. The Hippodrome|El Hipódromo|Plano — Segovia|Todas las criaturas obtienen -5/-0.\nSiempre que lances caos, puedes destruir la criatura objetivo si su fuerza es 0 o menos. The Hive|La colmena|Artefacto|{5}, {T}: Pon en juego una ficha de criatura artefacto Insecto 1/1 con la habilidad de volar llamada Avispa. (No puede ser bloqueada excepto por criaturas que tengan la habilidad de volar o alcance.) @@ -16223,6 +16281,7 @@ The Mending of Dominaria|La Reparación de Dominaria|Encantamiento — Saga|(En The Mimeoplasm|El Mimeoplasma|Criatura legendaria — Cieno|En cuanto El Mimeoplasma entre al campo de batalla, puedes exiliar dos cartas de criatura de cementerios. Si lo haces, entra al campo de batalla como una copia de una de esas cartas y con una cantidad de contadores +1/+1 adicionales sobre él igual a la fuerza de la otra carta. The Mirari Conjecture|La conjetura del Mirari|Encantamiento — Saga|(En cuanto esta Saga entre y después de tu paso de robar, agrega un contador de sabiduría. Sacrifícala después de III.)\nI — Regresa la carta de instantáneo objetivo de tu cementerio a tu mano.\nII — Regresa la carta de conjuro objetivo de tu cementerio a tu mano.\nIII — Hasta el final del turno, siempre que lances un hechizo de instantáneo o de conjuro, cópialo. Puedes elegir nuevos objetivos para la copia. The Rack|El potro|Artefacto|En cuanto El potro entre en juego, elige un oponente.\nAl comienzo del mantenimiento del jugador elegido, El potro hace X puntos de daño a ese jugador, donde X es 3 menos la cantidad de cartas en su mano. +The Royal Scions|Los Vástagos Reales|Planeswalker legendario — Will Rowan|+1: Roba una carta, luego descarta una carta.\n+1: La criatura objetivo obtiene +2/+0 y gana las habilidades de dañar primero y arrollar hasta el final del turno.\n−8: Roba cuatro cartas. Cuando lo hagas, Los Vástagos Reales hacen una cantidad de daño a cualquier objetivo igual a la cantidad de cartas en tu mano. The Scarab God|El Dios Escarabajo|Criatura legendaria — Deidad|Al comienzo de tu mantenimiento, cada oponente pierde X vidas y tú adivinas X, donde X es la cantidad de Zombies que controlas.\n{2}{U}{B}: Exilia la carta de criatura objetivo de un cementerio. Crea una ficha que es una copia de esa criatura, excepto que es un Zombie negro 4/4.\nCuando El Dios Escarabajo muera, regrésalo a la mano de su propietario al comienzo del próximo paso final. The Scorpion God|El Dios Escorpión|Criatura legendaria — Deidad|Siempre que una criatura con un contador -1/-1 sobre ella muera, roba una carta.\n{1}{B}{R}: Pon un contador -1/-1 sobre otra criatura objetivo.\nCuando El Dios Escorpión muera, regrésalo a la mano de su propietario al comienzo del próximo paso final. The Unspeakable|El innombrable|Criatura legendaria - Espíritu|Vuela, arrolla.\nSiempre que El innombrable haga daño de combate a un jugador, puedes regresar la carta de arcano objetivo de tu cementerio a tu mano. @@ -16665,6 +16724,7 @@ Tragic Arrogance|Arrogancia funesta|Conjuro|Por cada jugador, eliges de entre lo Tragic Lesson|Lección trágica|Instantáneo|Roba dos cartas. Luego descarta una carta a menos que regreses una tierra que controlas a la mano de su propietario. Tragic Poet|Poetisa trágica|Criatura — Humano|{T}, sacrificar la Poetisa trágica: Regresa la carta de encantamiento objetivo de tu cementerio a tu mano. Tragic Slip|Desliz trágico|Instantáneo|La criatura objetivo obtiene -1/-1 hasta el final del turno.\nNecrario — En vez de eso, esa criatura obtiene -13/-13 hasta el final del turno si una criatura murió este turno. +Trail of Crumbs|Rastro de migajas|Encantamiento|Cuando el Rastro de migajas entre al campo de batalla, crea una ficha de Comida.\nSiempre que sacrifiques una Comida, puedes pagar {1}. Si lo haces, mira las dos primeras cartas de tu biblioteca. Puedes mostrar una carta de permanente que se encuentre entre ellas y ponerla en tu mano. Pon el resto en el fondo de tu biblioteca en cualquier orden. Trail of Evidence|Rastro de pruebas|Encantamiento|Siempre que lances un hechizo de instantáneo o de conjuro, investiga. (Pon en el campo de batalla una ficha de artefacto Pista incolora con "{2}, sacrificar este artefacto: Roba una carta".) Trail of Mystery|Rastro de misterio|Encantamiento|Siempre que una criatura boca abajo entre al campo de batalla bajo tu control, puedes buscar en tu biblioteca una carta de tierra básica, mostrarla, ponerla en tu mano y luego barajar tu biblioteca.\nSiempre que un permanente que controlas se ponga boca arriba, si es una criatura, obtiene +2/+2 hasta el final del turno. Trail of the Mage-Rings|Senda de los anillos mágicos|Plano — Vryn|Los hechizos instantáneos y conjuros tienen la habilidad de rebote. (El controlador del hechizo exilia el hechizo mientras se resuelve si lo lanzó de su mano. Al comienzo del próximo mantenimiento de ese jugador, él puede lanzar esa carta desde el exilio sin pagar su coste de maná.)\nSiempre que lances caos, puedes buscar en tu biblioteca una carta de instantáneo o conjuro, mostrarla, ponerla en tu mano y luego barajar tu biblioteca. @@ -16738,6 +16798,7 @@ Treasure Nabber|Ladronzuelo de tesoros|Criatura — Bribón trasgo|Siempre que u Treasure Trove|Descubrimiento del tesoro|Encantamiento|{2}{U}{U}: Roba una carta. Treasured Find|Hallazgo preciado|Conjuro|Regresa la carta objetivo de tu cementerio a tu mano. Exilia el Hallazgo preciado Treasury Thrull|Thrull del tesoro|Criatura — Thrull|Extorsionar. (Siempre que lances un hechizo, puedes pagar {W/B}. Si lo haces, cada oponente pierde 1 vida y tú ganas esa cantidad de vidas.)Siempre que el Thrull del tesoro ataque, puedes regresar la carta de artefacto, criatura o encantamiento objetivo de tu cementerio a tu mano. +Treats to Share|Dulces que compartir|Conjuro — Aventura|Crea una ficha de Comida. (Luego, exilia esta carta. Puedes lanzar la criatura más adelante desde el exilio.) Tree Monkey|Mono de los arboles|| Tree of Perdition|Árbol de la perdición|Criatura — Planta|Defensor.\n{T}: Intercambia el total de vidas del oponente objetivo con la resistencia del Árbol de la perdición. Tree of Redemption|Árbol de la redención|Criatura — Planta|Defensor.\n{T}: Intercambia tu total de vidas con la resistencia del Árbol de la redención. @@ -16858,6 +16919,7 @@ Tsabo's Assassin|Asesino de Tsabo|| Tsabo's Decree|Decreto de Tsabo|| Tsabo's Web|Red de Tsabo|| Tsunami|Tsunami|| +Tuinvale Treefolk|Pueblo arbóreo del Valle de Tuin|Criatura — Druida pueblo-arbóreo| Tukatongue Thallid|Tálido tukatong|Criatura — Hongo|Cuando el Tálido tukatong muera, pon en el campo de batalla una ficha de criatura Saprolín verde 1/1. Tuktuk Grunts|Soldados de Tuktuk|Criatura — Guerrero trasgo aliado|Prisa.\nSiempre que los Soldados de Tuktuk u otro Aliado entre al campo de batalla bajo tu control, puedes poner un contador +1/+1 sobre los Soldados de Tuktuk. Tuktuk Scrapper|Pendenciero de Tuktuk|Criatura — Artífice trasgo aliado|Siempre que el Pendenciero de Tuktuk u otro Aliado entre al campo de batalla bajo tu control, puedes destruir el artefacto objetivo. Si ese artefacto va a un cementerio de esta manera, el Pendenciero de Tuktuk hace daño al controlador de ese artefacto igual al número de Aliados que controlas. @@ -17969,6 +18031,7 @@ Weird Harvest|Cosecha extraña|Conjuro|Cada jugador puede buscar en su bibliotec Weirded Vampire|Vampira grotesca|Criatura — Horror vampiro|Demencia {2}{B}. (Si descartas esta carta, exíliala. Cuando lo hagas, lánzala por su coste de demencia o ponla en tu cementerio.) Weirding Shaman|Chamán multiplicador|Criatura — Chamán trasgo|{3}{B}, sacrificar un Trasgo: Pon en juego dos fichas de criatura Bribón Trasgo negras 1/1. Weirding Wood|Bosque extravagante|Encantamiento — Aura|Encantar tierra.\nCuando el Bosque extravagante entre al campo de batalla, investiga. (Pon en el campo de batalla una ficha de artefacto Pista incolora con "{2}, sacrificar este artefacto: Roba una carta".)\nLa tierra encantada tiene "{T}: Agrega dos manás de un color cualquiera a tu reserva de maná". +Welcome Home|Bienvenida a casa|Conjuro — Aventura|Crea tres fichas de criatura Oso verdes 2/2. (Luego, exilia esta carta. Puedes lanzar la criatura más adelante desde el exilio.) Welcome to the Fold|Bienvenida al redil|Conjuro|Demencia {X}{U}{U}. (Si descartas esta carta, exíliala. Cuando lo hagas, lánzala por su coste de demencia o ponla en tu cementerio.)\nGanas el control de la criatura objetivo si su resistencia es 2 o menos. Si se pagó el coste de demencia de Bienvenida al redil, en vez de eso, ganas el control de la criatura objetivo si su resistencia es X o menos. Welder Automaton|Autómata soldador|Criatura artefacto — Constructo|{3}{R}: El Autómata soldador hace 1 punto de daño a cada oponente. Weldfast Engineer|Ingeniero de Sueldafirme|Criatura — Artífice humano|Al comienzo del combate en tu turno, la criatura artefacto objetivo que controlas obtiene +2/+0 hasta el final del turno. @@ -18061,6 +18124,7 @@ Wicked Akuba|Akuba perversa|Criatura - Espíritu|{B}: El jugador objetivo que ha Wicked Guardian|Guardiana vil|Criatura — Noble humano|Cuando la Guardiana vil entre al campo de batalla, puedes hacer que le haga 2 puntos de daño a otra criatura que controlas. Si lo haces, roba una carta. Wicked Pact|Pacto maligno|| Wicked Reward|Recompensa perversa|| +Wicked Wolf|Lobo feroz|Criatura — Lobo|Cuando el Lobo feroz entre al campo de batalla, lucha contra hasta una criatura objetivo que no controlas.\nSacrificar una Comida: Pon un contador +1/+1 sobre el Lobo feroz. Gana la habilidad de indestructible hasta el final del turno. Gíralo. Wicker Warcrawler|Rondador guerrero de mimbre|Criatura artefacto — Espantapájaros|Siempre que el Rondador guerrero de mimbre ataque o bloquee, pon un contador -1/-1 sobre él al final del combate. Wicker Witch|Bruja de paja|Criatura artefacto — Espantapájaros| Wickerbough Elder|Anciano brazos de mimbre|Criatura — Chamán pueblo-arbóreo|El Anciano brazos de mimbre entra en juego con un contador -1/-1 sobre él.\n{G}, remover un contador -1/-1 del Anciano brazos de mimbre: Destruye el artefacto o encantamiento objetivo. @@ -18100,6 +18164,7 @@ Wild Wanderer|Errante de lo agreste|Criatura — Druida elfo|Cuando la Errante d Wild Wurm|Sierpe salvaje|| Wild-Field Scarecrow|Espantapájaros del campo salvaje|Criatura artefacto — Espantapájaros|Defensor.\n{2}, sacrificar el Espantapájaros del campo salvaje: Busca en tu biblioteca hasta dos cartas de tierra básica, muéstralas y ponlas en tu mano. Luego baraja tu biblioteca. Wildblood Pack|Manada Sangre Salvaje|Criatura — Licántropo|Arrolla.\nLas criaturas atacantes que controlas obtienen +3/+0.\nAl comienzo de cada mantenimiento, si un jugador lanzó dos o más hechizos en el último turno, transforma a la Manada Sangre Salvaje. +Wildborn Preserver|Preservador salvagénito|Criatura — Arquero elfo|Destello.\nAlcance.\nSiempre que otra criatura que no sea Humano entre al campo de batalla bajo tu control, puedes pagar {X}. Cuando lo hagas, pon X contadores +1/+1 sobre el Preservador salvagénito. Wildcall|Llamada salvaje|Conjuro|Manifiesta la primera carta de tu biblioteca, luego pon X contadores +1/+1 sobre ella. (Para manifestar una carta, ponla en el campo de batalla boca abajo como una criatura 2/2. Ponla boca arriba en cualquier momento por su coste de maná si es una carta de criatura.) Wilderness Elemental|Elemental salvaje|Criatura — Elemental|Arrolla.\nLa fuerza de la Elemental salvaje es igual al número de tierras no básicas que controlan tus oponentes. Wilderness Hypnotist|Hipnotista salvaje|Criatura — Hechicero tritón|{T}: La criatura roja o verde objetivo obtiene -2/-0 hasta el final del turno. @@ -18118,6 +18183,7 @@ Wildsize|Tamaño salvaje|Instantáneo|La criatura objetivo obtiene +2/+2 y gana Wildslayer Elves|Elfos destructores salvajes|Criatura — Guerrero elfo|Debilitar. (Esta fuente hace daño a las criaturas en forma de contadores -1/-1.) Wildwood Geist|Geist del bosque salvaje|Criatura — Espíritu|El Geist del bosque salvaje obtiene +2/+2 mientras sea tu turno. Wildwood Rebirth|Renacimiento de madera salvaje|Instantáneo|Regresa la carta de criatura objetivo de tu cementerio a tu mano. +Wildwood Tracker|Rastreador del bosque salvaje|Criatura — Guerrero elfo|Siempre que el Rastreador del bosque salvaje ataque o bloquee, si controlas otra criatura que no sea Humano, el Rastreador del bosque salvaje obtiene +1/+1 hasta el final del turno. Will of the Naga|La voluntad de la naga|Instantáneo|Excavar. (Cada carta que exilies de tu cementerio al lanzar este hechizo cuenta como un pago de {1}.)\nGira hasta dos criaturas objetivo. Esas criaturas no se enderezan durante el próximo paso de enderezar de su controlador. Will-Forged Golem|Gólem autoforjado|Criatura artefacto — Gólem|Convocar. (Tus criaturas pueden ayudar a lanzar este hechizo. Cada criatura que gires al lanzar este hechizo cuenta como un pago de {1} o de un maná del color de esa criatura.) Will-o'-the-Wisp|Fuego fatuo|Criatura — Espíritu|Vuela. (Esta criatura no puede ser bloqueada excepto por criaturas que tengan la habilidad de volar.)\n{B}: Regenera el Fuego fatuo (La próxima vez que esta criatura fuera a ser destruida este turno, no lo es. En vez de eso, gírala, remueve todo el daño de ella y remuévela del combate.) @@ -18263,6 +18329,7 @@ Wojek Embermage|Mago ígneo wojek|Criatura — Hechicero humano|Irradiar {T}: El Wojek Halberdiers|Alabarderos Wojek|Criatura — Soldado humano|Batallón — Siempre que los Alabarderos Wojek y al menos otras dos criaturas ataquen, los Alabarderos Wojek ganan la habilidad de dañar primero hasta el final del turno. Wojek Siren|Sirena wojek|Instantáneo|Irradiar La criatura objetivo y cada una de las otras criaturas que compartan un color con ella obtienen +1/+1 hasta el final del turno. Wolf of Devil's Breach|Lobo de Brecha del Diablo|Criatura — Lobo elemental|Siempre que el Lobo de Brecha del Diablo ataque, puedes pagar {1}{R} y descartar una carta. Si lo haces, el Lobo de Brecha del Diablo hace una cantidad de daño a la criatura o planeswalker objetivo igual al coste de maná convertido de la carta descartada. +Wolf's Quarry|Presas del lobo|Conjuro|Crea tres fichas de criatura Jabalí verdes 1/1 con "Cuando esta criatura muera, crea una ficha de Comida". (Una ficha de Comida es un artefacto con "{2}, {T}, sacrificar este artefacto: Ganas 3 vidas.") Wolf-Skull Shaman|Chamán cráneo de lobo|Criatura — Chamán elfo|Hermandad Al comienzo de tu mantenimiento, puedes mirar la primera carta de tu biblioteca. Si comparte un tipo de criatura con el Chamán cráneo de lobo, puedes mostrarla. Si lo haces, pon en juego una ficha de criatura Lobo verde 2/2. Wolfbitten Captive|Cautivo mordido por los lobos|Criatura — Licántropo humano|{1}{G}: El Cautivo mordido por los lobos obtiene +2/+2 hasta el final del turno. Activa esta habilidad sólo una vez cada turno.\nAl comienzo de cada mantenimiento, si no se lanzaron hechizos en el último turno, transforma al Cautivo mordido por los lobos. Wolfbriar Elemental|Elemental lobo de brezo|Criatura — Elemental|Multiestímulo {G}. (Puedes pagar {G} adicional tantas veces como quieras al lanzar este hechizo.)\nCuando el Elemental lobo de brezo entre al campo de batalla, pon en el campo de batalla una ficha de criatura Lobo verde 2/2 por cada vez que fue estimulado. @@ -18436,6 +18503,7 @@ Yoked Ox|Buey sometido|Criatura — Buey| Yoked Plowbeast|Bestiarado del yugo|Criatura — Bestia|Ciclo {2}. ({2}, descartar esta carta: Roba una carta.) Yomiji, Who Bars the Way|Yomiji, el que impide el paso|Criatura legendaria - Espíritu|Siempre que un permanente legendario que no sea Yomiji, el que impide el paso vaya a un cementerio desde el juego, regresa esa carta a la mano de su propietario. Yore-Tiller Nephilim|Nefilim vástago de antaño|Criatura — Nefilim|Siempre que el Nefilim vástago de antaño ataque, regresa la carta de criatura objetivo de tu cementerio al juego girada y atacando. +Yorvo, Lord of Garenbrig|Yorvo, lord del Coto de Garen|Criatura legendaria — Noble gigante|Yorvo, lord del Coto de Garen entra al campo de batalla con cuatro contadores +1/+1 sobre él.\nSiempre que otra criatura verde entre al campo de batalla bajo tu control, pon un contador +1/+1 sobre Yorvo. Luego, si la fuerza de esa criatura es mayor que la fuerza de Yorvo, pon otro contador +1/+1 sobre Yorvo. Yosei, the Morning Star|Yosei, la estrella de la mañana|Criatura legendaria - Espíritu dragón|Vuela.\nCuando Yosei, la estrella de la mañana vaya a un cementerio desde el juego, el jugador objetivo se salta su próximo paso de enderezar. Gira hasta cinco permanentes objetivo que controle ese jugador. Yotian Soldier|Soldado yotiano|Criatura artefacto — Soldado|El Soldado yotiano no se gira al atacar. Young Pyromancer|Piromante joven|Criatura — Chamán humano|Siempre que lances un hechizo de instantáneo o de conjuro, pon en el campo de batalla una ficha de criatura Elemental roja 1/1. diff --git a/forge-gui/res/languages/cardnames-zh-CN.txt b/forge-gui/res/languages/cardnames-zh-CN.txt index d6910a7d050..9e33577f08a 100644 --- a/forge-gui/res/languages/cardnames-zh-CN.txt +++ b/forge-gui/res/languages/cardnames-zh-CN.txt @@ -280,6 +280,7 @@ Altar of Dementia|痴呆祭坛|神器|牺牲一个生物:目标牌手将其牌 Altar of the Brood|族群祭坛|神器|每当另一个永久物在你的操控下进战场时,每位对手各将其牌库顶牌置入其坟墓场。 Altar of the Lost|逝者祭坛|神器|逝者祭坛须横置进战场。{T}:加两点法术力到你的法术力池中,其颜色组合由你选择。此法术力只能用来从坟墓场中施放具返照的咒语。 Altar's Reap|祭坛夺命|瞬间|牺牲一个生物,以作为施放祭坛夺命的额外费用。\n抓两张牌。 +Alter Fate|改变命运|法术~历险|将目标生物牌从你的坟墓场移回你手上。(然后放逐此牌。之后你还可以从放逐区中施放该生物。) Altered Ego|另我离影|生物~变形兽|另我离影不能被反击。\n你可以使另我离影当成战场上任一生物的复制品来进入战场,但它进战场时上面额外有X个+1/+1指示物。 Always Watching|时刻戒护|结界|由你操控且非衍生物的生物得+1/+1且具有警戒异能。 Amaranthine Wall|不朽之壁|神器生物 ~墙|守军\n{2}:不朽之壁获得不灭异能直到回合结束。(伤害与注明「消灭」的效应不会将它消灭。) @@ -2565,6 +2566,7 @@ Dampening Pulse|抑制鼓动|结界|由对手操控的生物得-1/-0。 Damping Matrix|滞阻间质|神器|除了法术力异能之外,神器与生物的起动式异能都不能起动。 Damping Sphere|滞阻法球|神器|如果横置某个地以产生两点或更多法术力,则它改为产生{C},而非其他类别和数量。\n牌手施放的咒语增加若干费用来施放,其数量为「该牌手本回合每施放过一个其他咒语,便需增加{1}」。 Dance of Shadows|影身飞舞|法术~古咒|由你操控的生物得+1/+0并获得恐惧异能直到回合结束。 +Dance of the Manse|全宅起舞|法术|选择至多X张目标在你坟墓场中的神器和/或非灵气结界牌,且其总法术力费用均须等于或小于X。将它们移回战场。如果X等于或大于6,则这些永久物为4/4生物,且仍具有原本类别。 Dance of the Skywise|穹慧龙舞|瞬间|直到回合结束,目标由你操控的生物成为基础力量和防御力为4/4的蓝色龙/虚影,失去所有异能,并获得飞行异能。 Dance with Devils|与魔共舞|瞬间|将两个1/1红色魔鬼衍生生物放进战场。它们具有「当此生物死去时,它对目标生物或牌手造成1点伤害。」 Dancing Scimitar|飞舞的弯刀|神器生物~精怪|飞行(只有具飞行异能的生物才能阻挡它。) @@ -3102,6 +3104,7 @@ Domri, Chaos Bringer|致乱多密|传奇鹏洛客 ~多密|+1:加{R}或{G}。 Domri, City Smasher|焚城暴徒多密|传奇鹏洛客 ~多密|+2:直到回合结束,由你操控的生物得+1/+1且获得敏捷异能。\n−3:焚城暴徒多密对任意一个目标造成3点伤害。\n−8:在每个由你操控的生物上各放置三个+1/+1指示物。这些生物获得践踏异能直到回合结束。 Dong Zhou, the Tyrant|Dong Zhou, the Tyrant|| Doom Blade|送终刀锋|瞬间|消灭目标非黑色的生物。 +Doom Foretold|末日前兆|结界|在每位牌手的维持开始时,该牌手牺牲一个非地且非衍生物的永久物。若该牌手无法如此作,则他弃一张牌、失去2点生命,你抓一张牌、获得2点生命、派出一个2/2,具警戒异能的白色骑士衍生生物;然后你牺牲末日前兆。 Doom Whisperer|毁灭低语魔|生物 ~梦魇/恶魔|飞行,践踏\n支付2点生命:刺探2。(检视你牌库顶的两张牌,然后将其中任意数量的牌置入你的坟墓场,其余则以任意顺序置于你牌库顶。) Doomed Dissenter|注亡逆徒|生物 ~人类|当注亡逆徒死去时,派出一个2/2黑色灵俑衍生生物。 Doomed Necromancer|败亡死灵术士|生物~人类/僧侣/佣兵|{B},{T},牺牲败亡死灵术士:将目标生物牌从你的坟墓场移回场上。 @@ -3283,6 +3286,7 @@ Drover of the Mighty|巨兽牧者|生物 ~人类/德鲁伊|只要你操控 Drown in Filth|污秽灭顶|法术|选择目标生物。将你牌库顶的四张牌置入你的坟墓场,然后你的坟墓场中每有一张地牌,该生物便得-1/-1直到回合结束。 Drown in Shapelessness|溺于无形|瞬间|将目标生物移回其拥有者手上。 Drown in Sorrow|陷入悲痛|法术|所有生物得-2/-2直到回合结束。占卜1。(检视你牌库顶的牌。你可以将该牌置于你的牌库底。) +Drown in the Loch|拖入湖底|瞬间|选择一项~\n•反击目标咒语,且其总法术力费用须等于或小于其操控者坟墓场中牌的数量。\n•消灭目标生物,且其总法术力费用须等于或小于其操控者坟墓场中牌的数量。 Drowned Catacomb|水没墓穴|地|除非你操控海岛或沼泽,否则水没墓穴须横置进战场。\n{T}:加{U}或{B}到你的法术力池中。 Drowned Rusalka|溺水怨魂|生物~精怪|{U},牺牲一个生物:弃一张牌,然后抓一张牌。 Drowned Secrets|冲尽秘密|结界|每当你施放蓝色咒语时,目标牌手将其牌库顶的两张牌置入其坟墓场。 @@ -3410,6 +3414,7 @@ Echoing Truth|真相回响|瞬间|将目标非地永久物及所有与其同名 Eddytrail Hawk|漩迹鹰|生物~鸟|飞行\n当漩迹鹰进战场时,你得到{E}{E}(两个能量指示物)。\n每当漩迹鹰攻击时,你可以支付{E}。若你如此作,则另一个目标进行攻击的生物获得飞行异能直到回合结束。 Edge of Autumn|暮秋|法术|如果你操控四个地或更少,则从你的牌库中搜寻一张基本地牌,将之横置进场,然后将你的牌库洗牌。\n循环~牺牲一个地。 (牺牲一个地,弃掉此牌:抓一张牌。) Edge of the Divinity|女神授恩|结界~灵气|生物结界\n只要受此结界的生物是白色,它便得+1/+2。\n只要受此结界的生物是黑色,它便得+2/+1。 +Edgewall Innkeeper|边墙镇旅店主|生物 ~人类/平民|每当你施放具有历险的生物咒语时,抓一张牌。(它不需先完成历险。) Edifice of Authority|威权高塔|神器|{1},{T}:目标生物本回合不能攻击。在威权高塔上放置一个石砖指示物。\n{1},{T}:直到你的下一个回合,目标生物不能进行攻击或阻挡,其起动式异能也不能起动。只能于威权高塔上有三个或更多石砖指示物时起动此异能。 Edric, Spymaster of Trest|崔斯特密探长埃卓克|传奇生物~妖精/浪客|每当一个生物向你的任一对手造成战斗伤害时,其操控者可以抓一张牌。 Eel Umbra|鳗本影|结界~灵气|闪现 (你可以于你能够施放瞬间的时机下施放此咒语。)\n结附于生物\n所结附的生物得+1/+1。\n替身甲 (如果所结附的生物将被消灭,则改为移除它受过的所有伤害,并消灭此灵气。) @@ -3670,6 +3675,7 @@ Erratic Visionary|古怪幻视师|生物 ~人类/法术师|{1}{U},{T}: Error|Error|Instant|Counter target multicolored spell. Erstwhile Trooper|故军士兵|生物 ~灵俑/士兵|弃一张生物牌:直到回合结束,故军士兵得+2/+2且获得践踏异能。此异能每回合只能起动一次。 Erupting Dreadwolf|纵焰恐狼|生物~ - 奥札奇/狼人|每当纵焰恐狼攻击时,它对目标生物或牌手造成2点伤害。 +Escape to the Wilds|逃往幻野|法术|放逐你牌库顶的五张牌。直到你下一个回合的回合结束,你可以使用以此法放逐的牌。\n本回合中,你可以额外使用一个地。 Escaped Null|脱逃躯壳|生物~灵俑/狂战士|系命\n每当脱逃躯壳阻挡或被阻挡时,它得+5/+0直到回合结束。 Esper Battlemage|艾斯波战法术师|神器生物~人类/法术师|{W},{T}:于本回合中,防止接下来将对你造成的2点伤害。\n{B},{T}:目标生物得-1/-1直到回合结束。 Esper Charm|艾斯波护符|瞬间|选择一项~消灭目标结界;或抓两张牌;或目标牌手弃两张牌。 @@ -3839,7 +3845,8 @@ Faceless Devourer|无面吞噬兽|生物~梦魇/惊惧兽|次元幽影(此 Facevaulter|跺脸客|生物~精灵/战士|{B},牺牲一个精灵:跺脸客得+2/+2直到回合结束。 Fact or Fiction|真伪莫辨|瞬间|展示你牌库顶的五张牌。由任一对手将它们分成两堆。将其中一堆置于你手上,另一堆置入你的坟墓场。 Fade into Antiquity|逐渐湮没|法术|放逐目标神器或结界。 -Fae of Wishes|心愿得遂|法术~历险|你可以从游戏外选择一张由你拥有的非生物牌,展示该牌,并将它置于你手上。 +Fae of Wishes|趁愿仙儿|生物 ~仙灵/法术师|飞行\n{1}{U},弃两张牌:将趁愿仙儿移回其拥有者手上。 +Faeburrow Elder|仙林境接骨木|生物 ~树妖/德鲁伊|警戒\n由你操控的永久物中每包括一种颜色,仙林境接骨木便得+1/+1。\n{T}:由你操控的永久物中每包括一种颜色,便加一点该色的法术力。 Faerie Artisans|仙灵工匠|生物~仙灵/神器师|飞行\n每当一个非衍生物的生物在对手的操控下进战场时,派出一个衍生物,该衍生物为该生物的复制品,但额外具有神器此类别。然后放逐所有以仙灵工匠派出的其他衍生物。 Faerie Conclave|仙灵议场|地|仙灵议场须横置进场。\n{T}:加{U}到你的法术力池中。\n{1}{U}:直到回合结束,仙灵议场成为2/1蓝色,具飞行异能的仙灵生物。 它仍然是地。 (只有具飞行或延势异能的生物才能阻挡它。) Faerie Duelist|仙灵斗客|生物 ~仙灵/浪客|闪现\n飞行\n当仙灵斗客进战场时,目标由对手操控的生物得-2/-0直到回合结束。 @@ -3949,6 +3956,7 @@ Feast of Flesh|活人生吃|法术|活人生吃对目标生物造成X点伤害 Feast of Worms|地虫盛宴|法术~古咒|消灭目标地。若该地为传奇地,则其操控者牺牲另一个地。 Feast on the Fallen|饱食死者|结界|在每个维持开始时,若上回合中曾有对手失去过生命,则在目标由你操控的生物上放置一个+1/+1指示物。 Feaster of Fools|愚者饕客|生物 ~恶魔|召集(此咒语能用你的生物来协助施放。你于施放此咒语时每横置一个生物,就能为此咒语支付{1}或一点该生物颜色之法术力。)\n飞行\n吞噬2(于该生物进战场时,你可以牺牲任意数量的生物。此生物进战场时上面有两倍于该数量的+1/+1指示物。) +Feasting Troll King|暴食巨魔侯|生物~巨魔/贵族|警戒,践踏\n当暴食巨魔侯进战场时,若你从你手上施放之,则派出三个食品衍生物。\n牺牲三个食品:将暴食巨魔侯从你的坟墓场移回战场。只能于你的回合中起动此异能。 Feat of Resistance|反抗技艺|瞬间|在目标由你操控的生物上放置一个+1/+1指示物。选择一种颜色。该生物获得反该色保护异能直到回合结束。 Feather, the Redeemed|复耀飞羽|传奇生物 ~天使|飞行\n每当你施放一个以由你操控之生物为目标的瞬间或法术咒语,于该咒语结算时,改为放逐该牌,而非将其置入你的坟墓场。若你如此作,则在下一个结束步骤开始时,将它移回你手上。 Feebleness|无力感|结界~灵气|闪现(你可以于你能够使用瞬间的时机下使用此咒语。)\n生物结界\n受此结界的生物得-2/-1。 @@ -3970,6 +3978,7 @@ Felidar Sovereign|晶角兽君王|生物~猫/野兽|警戒,系命\n在你 Fell Flagship|极恶旗舰|神器 ~载具|由你操控的海盗得+1/+0。\n每当极恶旗舰对任一牌手造成战斗伤害时,该牌手弃一张牌。\n搭载3(横置任意数量由你操控且力量总和等于或大于3的生物:此载具成为神器生物直到回合结束。) Fell Specter|骇人幽灵|生物 ~幽灵|飞行\n当骇人幽灵进战场时,目标对手弃一张牌。\n每当一位对手弃一张牌时,该牌手失去2点生命。 Fell the Mighty|以弱制强|法术|消灭所有力量大于目标生物的生物。 +Fell the Pheasant|猎取雉鸡|瞬间|猎取雉鸡对目标具飞行异能的生物造成5点伤害。派出一个食品衍生物。(食品衍生物是具有「{2},{T},牺牲此神器:你获得3点生命」的神器。) Fellwar Stone|战野之石|神器|{T}:加一点法术力到你的法术力池中,其颜色为由对手操控的地能产生之任一颜色。 Femeref Archers|费米瑞甫弓箭手|生物~人类/弓箭手|{T}:费米瑞甫弓箭手对目标具飞行异能、且进行攻击的生物造成4点伤害。 Fen Hauler|泽地驮虫|生物~昆虫|拼造(此咒语能用你的神器来协助施放。你起动完法术力异能之后每横置一个神器,就能为此咒语支付{1}。)\n泽地驮虫不能被神器生物阻挡。 @@ -4034,6 +4043,7 @@ Fiend of the Shadows|阴影邪鬼|生物~吸血鬼/法术师|每当阴影邪 Fiendslayer Paladin|克邪神圣武士|生物~人类/骑士|先攻(此生物会比不具先攻异能的生物提前造成战斗伤害。) 系命(此生物所造成的伤害会让你获得等量的生命。)克邪神圣武士不能成为由对手操控之黑色或红色咒语的目标。 Fierce Empath|好斗共感者|生物 ~妖精|当好斗共感者进战场时,你可以从你的牌库中搜寻一张总法术力费用等于或大于6的生物牌,展示该牌,将它置于你手上,然后将你的牌库洗牌。 Fierce Invocation|狂热祝愿|法术|显化你的牌库顶牌,然后在其上放置两个+1/+1指示物。(显化某张牌的流程是,将该牌面朝下地放进战场,当成2/2生物。如果该牌是生物牌,则可随时支付其法术力费用使其翻回正面。) +Fierce Witchstalker|凶猛猎巫狼|生物 ~狼|践踏\n当凶猛猎巫狼进战场时,派出一个食品衍生物。(食品衍生物是具有「{2},{T},牺牲此神器:你获得3点生命」的神器。) Fiery Bombardment|猛烈轰炸|结界|渲色~{2},牺牲一个生物:猛烈轰炸对目标生物或牌手造成伤害,其数量等同于所牺牲的生物之法术力费用中红色法术力符号之数量。 Fiery Cannonade|激烈炮击|瞬间|激烈炮击对每个非海盗的生物各造成2点伤害。 Fiery Conclusion|暴烈终局|瞬间|牺牲一个生物,以作为使用暴烈终局的额外费用。\n暴烈终局对目标生物造成5点伤害。 @@ -4174,6 +4184,7 @@ Flashfires|火烧旷野|法术|消灭所有平原。 Flashfreeze|快速冻结|瞬间|反击目标红色或绿色咒语。 Flash|闪现|瞬间|你可以将一张生物牌从你手上放进战场。如果你如此作,则除非你支付其至多减少{2}的法术力费用,否则牺牲之。 Flatten|踩扁|瞬间|目标生物得-4/-4直到回合结束。 +Flaxen Intruder|金发入侵者|生物 ~人类/狂战士|每当金发入侵者对任一牌手造成战斗伤害时,你可以将它牺牲。当你如此作时,消灭目标神器或结界。 Flayer Drone|劫命奴兽|生物~奥札奇/奴兽|虚色(此牌没有颜色。)\n先攻\n每当另一个无色生物在你的操控下进战场时,目标对手失去1点生命。 Flayer Husk|劫掠空壳|神器~武具|活化武器 (当此武具进战场时,将一个0/0黑色病菌衍生生物放进战场,然后将它装备上去。)\n佩带此武具的生物得+1/+1。\n佩带{2} ({2}:装备在目标由你操控的生物上; 佩带的时机视同法术。) Flayer of the Hatebound|怀恨劫掠者|生物~恶魔|不息(当此生物死去时,若其上没有+1/+1指示物,则将它在其拥有者的操控下返回战场,且其上有一个+1/+1指示物。)每当怀恨劫掠者或另一个生物从你的坟墓场进战场时,该生物对目标生物或牌手造成伤害,其数量等同于前者的力量。 @@ -4288,6 +4299,7 @@ Forerunner of the Legion|军团先驱|生物 ~吸血鬼/骑士|当军团先 Foresee|预知|法术|占卜4,然后抓两张牌。 (占卜4的流程是检视你牌库顶的四张牌,然后将其中任意数量的牌以任意顺序置于你牌库底,其余则以任意顺序置于你牌库顶。) Forest Bear|Forest Bear|| Forest|树林|基本地 ~树林|({T}: 添加 {G}.) +Forever Young|青春永驻|法术|将任意数量的目标生物牌从你的坟墓场置于你的牌库顶。\n抓一张牌。 Forfend|保卫|瞬间|防止本回合中将对生物造成的所有伤害。 Forge Devil|锻炉魔鬼|生物~恶魔|当锻炉魔鬼进战场时,它对目标生物造成1点伤害,且对你造成1点伤害。 Forgeborn Oreads|锻生山灵|结界生物~宁芙|星彩~每当锻生山灵或另一个结界在你的操控下进战场时,锻生山灵对目标生物或牌手造成1点伤害。 @@ -4323,6 +4335,7 @@ Foul Orchard|邪秽果园|地|邪秽果园须横置进战场。\n{T}:加{B}或 Foul Renewal|邪秽复生|瞬间|将目标生物牌从你的坟墓场移回你手上。目标生物得-X/-X直到回合结束,X为以此法移回之牌的防御力。 Foul-Tongue Invocation|秽言祝愿|瞬间|你可以从你手上展示一张龙牌,以作为施放秽言祝愿的额外费用。\n目标牌手牺牲一个生物。如果于你施放秽言祝愿时,你展示了龙牌或操控龙,则你获得4点生命。 Foul-Tongue Shriek|秽言啸鸣|瞬间|你每操控一个进行攻击的生物,目标对手便失去1点生命。你获得等量的生命。 +Foulmire Knight|朽沼骑士|生物 ~灵俑/骑士|死触 Foundry Assembler|铸造厂组装工|神器生物~组装工人|拼造(此咒语能用你的神器来协助施放。你起动完法术力异能之后每横置一个神器,就能为此咒语支付{1}。) Foundry Champion|锻炉斗士|生物~元素/士兵|当锻炉斗士进战场时,它对目标生物或牌手造成伤害,其数量等同于由你操控的生物数量。\n{R}:锻炉斗士得+1/+0直到回合结束。\n{W}:锻炉斗士得+0/+1直到回合结束。 Foundry Hornet|铸造厂黄蜂|生物~昆虫|飞行\n当铸造厂黄蜂进战场时,若你操控其上有+1/+1指示物的生物,则由对手操控的生物得-1/-1直到回合结束。 @@ -4459,6 +4472,9 @@ Gamekeeper|猎场看守人|生物~妖精|当猎场看守人死去时,你可 Gang Up|联袂出击|瞬间|助力(另一位牌手能够为此咒语的费用支付至多{X}。你选择X的数值。)\n消灭目标力量等于或小于X的生物。 Gang of Devils|魔鬼群|生物~魔鬼|当魔鬼群死去时,它对一个,两个,或三个目标生物和/或牌手造成共3点伤害,你可以任意分配。 Garbage Fire|弃物烈焰|瞬间|于你抽选弃物烈焰时展示之,并记下本轮抽圈次中包括弃物烈焰在内你已抽选的牌数。\n弃物烈焰对目标生物造成伤害,其数量等同于你替名称为弃物烈焰之牌记下的各数字间之最大值。 +Garenbrig Carver|盖伦碧雕匠|生物 ~人类/战士| +Garenbrig Paladin|盖伦碧神圣武士|生物 ~巨人/骑士|固色~如果施放此咒语时支付过至少三点绿色法术力,则盖伦碧神圣武士进战场时上面有一个+1/+1指示物。\n盖伦碧神圣武士不能被力量等于或小于2的生物阻挡。 +Garenbrig Squire|盖伦碧扈从|生物 ~人类/士兵|每当你施放具有历险的生物咒语时,盖伦碧扈从得+1/+1直到回合结束。(它不需先完成历险。) Gargos, Vicious Watcher|卫护恶龙加戈斯|传奇生物 ~多头龙|警戒\n你施放的多头龙咒语减少{4}来施放。\n每当一个由你操控的生物成为咒语的目标时,卫护恶龙加戈斯与至多一个目标不由你操控的生物互斗。 Gargoyle Castle|石像鬼城堡|地|{T}:加{1}到你的法术力池中。\n{5},{T},牺牲石像鬼城堡:将一个3/4无色,具飞行异能的石像鬼神器生物衍生物放进战场。 Gargoyle Sentinel|哨兵石像鬼|神器生物 ~石像鬼|守军(此生物不能攻击。)\n{3}:直到回合结束,哨兵石像鬼失去守军异能并获得飞行异能。 @@ -4472,6 +4488,7 @@ Garruk's Horde|贾路的兽群|生物~野兽|践踏 你以展示牌库顶牌 Garruk's Packleader|贾路的兽群长|生物~野兽|每当另一个力量大于或等于3的生物在你的操控下进战场时,你可以抓一张牌。 Garruk, Apex Predator|无上猎者贾路|鹏洛客~贾路|+1:消灭另一个目标鹏洛客。\n+1:将一个3/3黑色,具死触异能的野兽衍生生物放进战场。\n−3:消灭目标生物。你获得等同于其防御力的生命。\n−8:目标对手获得具有「每当一个生物攻击你时,直到回合结束,它得+5/+5且获得践踏异能」的徽记。 Garruk, Caller of Beasts|唤兽师贾路|鹏洛客~贾路|+1:展示你牌库顶的五张牌。将以此法展示出的所有生物牌置于你手上,其余则以任意顺序置于你的牌库底。-3:你可以将一张绿色生物牌从你手上放进战场。-7:你获得具有「每当你施放生物咒语时,你可以从你的牌库中搜寻一张生物牌,将之放进战场,然后将你的牌库洗牌。」的徽记。 +Garruk, Cursed Huntsman|遭诅猎人贾路|传奇鹏洛客 ~贾路|0:派出两个2/2,黑绿双色的狼衍生生物,它们具有「当此生物死去时,在每个由你操控的贾路上各放置一个忠诚指示物。」\n-3:消灭目标生物。抓一张牌。\n-6:你获得具有「由你操控的生物得+3/+3且具有践踏异能」的徽记。 Garruk, Primal Hunter|原初猎人贾路|鹏洛客~贾路|+1:将一个3/3绿色野兽衍生生物放进战场。-3:抓若干牌,其数量等同于由你操控的生物中力量最大者的数值。-6:你每操控一个地,便将一个6/6绿色亚龙衍生生物放进战场。 Garruk, the Veil-Cursed|面纱咒贾路|鹏洛客~ - 贾路|+1:将一个1/1黑色,具死触异能的狼衍生生物放进战场。\n-1:牺牲一个生物。 如果你如此作,从你的牌库中搜寻一张生物牌,展示该牌,并将它置入你手上,然后将你的牌库洗牌。\n-3:直到回合结束,由你操控的生物获得践踏异能并得+X/+X,X为你坟墓场中生物牌的数量。 Garrulous Sycophant|善辩奉承者|生物~人类/参谋|在你的结束步骤开始时,若你是君主,则每位对手各失去1点生命且你获得1点生命。 @@ -4626,6 +4643,7 @@ Giant Growth|变巨术|瞬间|目标生物得+3/+3直到回合结束。 Giant Harbinger|先兆巨人|生物~巨人/祭师|当先兆巨人进场时,你可以从你的牌库中搜寻一张巨人牌,展示该牌,然后将你的牌库洗牌,并将该牌置于其上。 Giant Killer|巨人杀手|生物 ~人类/平民|{1}{W},{T}:横置目标生物。 Giant Mantis|巨型螳螂|生物~昆虫|延势(此生物能阻挡具飞行异能的生物。) +Giant Opportunity|伟大机遇|法术|你可以牺牲两个食品。如果你如此作,则派出一个7/7绿色巨人衍生生物。若否,则派出三个食品衍生物。(食品衍生物是具有「{2},{T},牺牲此神器:你获得3点生命」的神器。) Giant Oyster|巨型牡蛎|生物~牡蛎|你可以选择于你的重置步骤中不重置巨型牡蛎。\n{T}:只要巨型牡蛎持续被横置,目标已横置的生物于其操控者的重置步骤中便不能重置,且在你的每个抓牌步骤开始时,在该生物上放置一个-1/-1指示物。 当巨型牡蛎离场或成为未横置时,移去该生物上所有的-1/-1指示物。 Giant Scorpion|巨型蝎子|生物~蝎子|死触 (受到此生物之伤害的生物会被消灭。 你可以将此生物之战斗伤害在阻挡它或被它阻挡的任何生物之间分配。) Giant Solifuge|巨型风蛛|生物~昆虫|践踏,敏捷\n帷幕(此生物不能成为咒语或异能的目标。) @@ -4633,6 +4651,7 @@ Giant Spectacle|巨大奇观|结界~灵气|结附于生物\n所结附的生物 Giant Spider|巨型蜘蛛|生物 ~蜘蛛|延势(此生物能阻挡具飞行异能的生物。) Giant Tortoise|巨龟|生物~龟|只要巨龟未横置,它便得+0/+3。 Giant's Ire|巨人怒火|部族法术~巨人|巨人怒火对目标牌手造成4点伤害。 若你操控巨人,则抓一张牌。 +Giant's Skewer|巨人烤叉|神器 ~武具|佩带此武具的生物得+2/+1。\n每当佩带此武具的生物对任一生物造成战斗伤害时,派出一个食品衍生物。(食品衍生物是具有「{2},{T},牺牲此神器:你获得3点生命」的神器。)\n佩带{3}({3}:装备在目标由你操控的生物上。佩带的时机视同法术。) Giantbaiting|饵诱巨人|法术|将一个4/4,红绿双色,具敏捷异能的巨人/战士衍生物放置进场。 在回合结束时将它移出对战。\n协力 (于你使用此咒语时,你可以横置两个由你操控、且与此咒语有共通颜色的未横置生物。 当你如此作,则复制此咒语。) Gibbering Descent|堕落谵语|结界|在每位牌手的维持开始时,该牌手失去1点生命且弃一张牌。\n背水战~若你没有手牌,则略过你的维持步骤。\n疯魔{2}{B}{B}(如果你弃掉此牌,可以改为使用它并支付其疯魔费用,而非直接将它置入你的坟墓场。) Gibbering Fiend|急叫邪鬼|生物~魔鬼|当急叫邪鬼进战场时,它向每位对手各造成1点伤害。\n躁狂~在每位对手的维持开始时,若你坟墓场中牌的类别有四种或更多,则急叫邪鬼对该牌手造成1点伤害。 @@ -4675,6 +4694,7 @@ Gigantomancer|庞巨术士|生物~人类/祭师|{1}:目标由你操控的 Gigantoplasm|庞巨原生质|生物~变形兽|你可以使庞巨原生质当成战场上任一生物的复制品来进入战场,但它额外获得「{X}:此生物的基础力量与防御力为X/X。」 Gigantosaurus|巨太龙|生物 ~恐龙| Gilded Cerodon|覆辉角牙兽|生物~野兽|每当覆辉角牙兽攻击时,若你操控沙漠或你坟墓场中有沙漠牌,则目标生物本回合不能进行阻挡。 +Gilded Goose|金鹅|生物 ~鸟|飞行\n当金鹅进战场时,派出一个食品衍生物。(食品衍生物是具有「{2},{T},牺牲此神器:你获得3点生命」的神器。)\n{1}{G},{T}:派出一个食品衍生物。\n{T},牺牲一个食品:加一点任意颜色的法术力。 Gilded Light|金光眩目|瞬间|你获得帷幕异能直到回合结束。(你不能成为咒语或异能的目标。)\n循环{2}({2},弃掉此牌:抓一张牌。) Gilded Lotus|金箔莲花|神器|{T}:加三点任意颜色的单色法术力。 Gilded Sentinel|覆金哨卫|神器生物 ~魔像| @@ -4972,7 +4992,7 @@ Grand Architect|高位构念师|生物~维多肯/神器师|由你操控的 Grand Coliseum|大竞技场|地|大竞技场须横置进战场。\n{T}:加{C}到你的法术力池中。\n{T}:加一点任意颜色的法术力到你的法术力池中。大竞技场对你造成1点伤害。 Grand Warlord Radha|大军阀拉妲|传奇生物 ~妖精/战士|敏捷\n每当由你操控的一个或数个生物攻击时,加等量的法术力,其颜色为{R}和/或{G}的任意组合。直到回合结束,你不会因步骤与阶段结束失去这份法术力。 Granitic Titan|花岗岩泰坦|生物~元素|威慑\n循环{2}({2},弃掉此牌:抓一张牌。) -Granted|趁愿仙儿|生物 ~仙灵/法术师|飞行\n{1}{U},弃两张牌:将趁愿仙儿移回其拥有者手上。 +Granted|心愿得遂|法术~历险|你可以从游戏外选择一张由你拥有的非生物牌,展示该牌,并将它置于你手上。 Granulate|化为碎粒|法术|消灭所有非地,且总法术力费用等于或小于4的神器。 Grapeshot|霰散弹|法术|霰散弹对目标生物或牌手造成1点伤害。\n风暴(当你使用此咒语时,本回合于它之前每使用过一个咒语,便将此咒语复制一次。) 你可以为每个复制品选择新的目标。) Grapple with the Past|纠结过往|瞬间|将你牌库顶的三张牌置入你的坟墓场,然后你可以将一张生物或地牌从你的坟墓场移回你手上。 @@ -5152,6 +5172,7 @@ Gruesome Fate|可怖命运|法术|你每操控一个生物,每位对手便各 Gruesome Menagerie|兽群惧集|法术|从你坟墓场中的生物牌中,总法术力费用为1,2,3的生物牌各选择一张。将这些牌移回战场。 Gruesome Scourger|可怖甩鞭客|生物 ~半兽人/战士|当可怖甩鞭客进战场时,它向目标对手或鹏洛客造成伤害,其数量等同于由你操控的生物数量。 Gruesome Slaughter|阴森屠戮|法术|直到回合结束,由你操控的无色生物获得「{T}:此生物对目标生物造成伤害,其数量等同于前者的力量。」 +Grumgully, the Generous|慷慨的咕加力|传奇生物 ~鬼怪/祭师|每个由你操控的其他非人类生物进战场时上面均额外有一个+1/+1指示物。 Grunn, the Lonely King|孤独猴王古恩|传奇生物 ~猿猴/战士|增幅{3}(你施放此咒语时可以额外支付{3}。)\n如果孤独猴王古恩已增幅,它进战场时上面有五个+1/+1指示物。\n每当古恩单独攻击时,将其力量与防御力加倍直到回合结束。 Gruul Beastmaster|古鲁驯兽师|生物 ~人类/祭师|起事(于此生物进战场时,你选择「+1/+1指示物」或「敏捷」异能。它进战场时上面有所选加成。)\n每当古鲁驯兽师攻击时,另一个目标由你操控的生物得+X/+0直到回合结束,X为古鲁驯兽师的力量。 Gruul Charm|古鲁护符|瞬间|选择一项~不具飞行异能的生物本回合不能进行阻挡;或获得所有你拥有之永久物的操控权;或古鲁护符对每个具飞行异能的生物各造成3点伤害。 @@ -5382,6 +5403,7 @@ Healing Leaves|疗伤木叶|瞬间|选择一项~目标牌手获得3点生命 Heap Doll|堆积人偶|神器生物~稻草人|牺牲堆积人偶:将目标牌从坟墓场移出对战。 Heart of Kiran|基岚之心号|传奇神器~载具|飞行,警戒\n搭载3(横置任意数量由你操控且力量总和等于或大于3的生物:此载具成为神器生物直到回合结束。)\n你可以从某个由你操控的鹏洛客上移去一个忠诚指示物,而不支付基岚之心号的搭载费用。 Heart of Light|净光之心|生物结界|防止受此结界的生物将受到或造成的所有伤害。 +Heart's Desire|心之所爱|法术~历险|派出一个1/1白色人类衍生生物。(然后放逐此牌。之后你还可以从放逐区中施放该生物。) Heart-Piercer Bow|穿心弓|神器 ~武具|每当佩带此武具的生物攻击时,穿心弓对目标由防御牌手操控的生物造成1点伤害。\n佩带{1}({1}:装备在目标由你操控的生物上。佩带的时机视同法术。) Heart-Piercer Manticore|穿心蝎狮|生物~翼狮|当穿心蝎狮进战场时,你可以牺牲另一个生物。当你如此作时,穿心蝎狮对目标生物或牌手造成伤害,其数量等同于所牺牲生物的力量。\n遗存{5}{R}({5}{R},从你的坟墓场放逐此牌:派出一个衍生物,且为此牌的复制品,但它是白色灵俑/翼狮,且没有法术力费用。遗存的时机视同法术。) Heartbeat of Spring|春之鼓动|结界|每当牌手横置地以产生法术力时,该牌手加一点同类别的法术力到他的法术力池中。 @@ -5850,6 +5872,7 @@ Implement of Malice|恶意擎具|神器|{B},牺牲恶意擎具:目标牌手 Imposing Sovereign|庄严君王|生物~人类|由对手操控的生物须横置进战场。 Impostor of the Sixth Pride|六战群伪刃|生物 ~变形兽|化形(此牌是所有生物类别。) Imprisoned in the Moon|禁锢于月|结界~灵气|结附于生物,地或鹏洛客\n所结附的永久物是无色地,并具有「{T}:加{C}到你的法术力池中」且失去所有其他类别和异能。 +Improbable Alliance|奇诡搭配|结界|每当你抓每回合中你的第二张牌时,派出一个1/1蓝色,具飞行异能的仙灵衍生生物。\n{4}{U}{R}:抓一张牌,然后弃一张牌。 Impromptu Raid|随兴掠夺|结界|{2}{R/G}:展示你的牌库顶牌。 若该牌不是生物牌,则将它置入你的坟墓场。若是生物牌,则将该牌放置进场。 该生物具有敏捷异能。 在回合结束时将之牺牲。 Impulse|冲动|瞬间|检视你牌库顶的四张牌。将其中一张置于你手上,其余的牌则以任意顺序置于你的牌库底。 In Bolas's Clutches|受制波拉斯|传奇结界 ~灵气|结附于永久物\n你操控所结附的永久物。\n所结附的永久物是传奇。 @@ -5960,6 +5983,7 @@ Inquisitor Exarch|审问督教|生物~僧侣|当审问督教进战场时,选 Inquisitor's Flail|审判官连枷|神器~武具|如果佩带此武具的生物将造成战斗伤害,则它改为造成两倍的伤害。\n如果另一个生物将对佩带此武具的生物造成战斗伤害,则它改为对佩带此武具的生物造成两倍的伤害。\n佩带{2} Inquisitor's Ox|审判官驮牛|生物~牛|躁狂~只要你坟墓场中牌的类别有四种或更多,审判官驮牛便得+1/+0且具有警戒异能。 Inquisitor's Snare|审判官罗网|瞬间|于本回合中,防止目标进行攻击或阻挡的生物将造成的所有伤害。 若该生物是红色或黑色,则将它消灭。 +Insatiable Appetite|无餍食欲|瞬间|你可以牺牲一个食品。如果你如此作,则目标生物得+5/+5直到回合结束。若否,则该生物得+3/+3直到回合结束。 Insatiable Gorgers|无餍噬客|生物~吸血鬼/狂战士|无餍噬客每次战斗若能攻击,则必须攻击。\n疯魔{3}{R}(如果你弃掉此牌,将之弃到放逐区。当你如此作时,支付其疯魔费用施放之,否则便将其置入你的坟墓场。) Insatiable Harpy|无餍哈痞|生物~哈痞|飞行,系命 Insatiable Souleater|无餍食灵妖|神器生物~野兽|{G/P}:无餍食灵妖获得践踏异能直到回合结束。 ({G/P}可用{G}或2点生命来支付。) @@ -5978,6 +6002,7 @@ Inspiring Roar|振奋怒吼|法术|在每个由你操控的生物上各放置一 Inspiring Statuary|启迪塑像|神器|你施放的非神器咒语具有拼造异能。(这些咒语能用你的神器来协助施放。你起动完法术力异能之后每横置一个神器,就能为此咒语支付{1}。) Inspiring Unicorn|振奋独角兽|生物 ~独角兽|每当振奋独角兽攻击时,由你操控的生物得+1/+1直到回合结束。 Inspiring Vantage|启迪胜地|地|除非由你操控的其他地数量为两个或更少,否则启迪胜地须横置进战场。\n{T}:加{R}或{W}到你的法术力池中。 +Inspiring Veteran|励志老兵|生物 ~人类/骑士|由你操控的其他骑士得+1/+1。 Inspirit|激扬|瞬间|重置目标生物。 它得+2/+4直到回合结束。 Instigator Gang|煽动党徒|生物~人类/狼人|由你操控且进行攻击的生物得+1/+0。\n在每个维持开始时,若上回合没有任一咒语施放过,转化煽动党徒。 Instill Furor|灌输狂热|结界~灵气|生物结界\n受此结界的生物具有「在你的回合结束时,除非此生物于本回合中曾进行攻击,否则牺牲之。」 @@ -6352,6 +6377,7 @@ Keen Sense|敏锐直觉|结界~灵气|生物结界\n每当受此结界的生 Keening Apparition|哭号幻影|生物~精怪|牺牲哭号幻影:消灭目标结界。 Keening Banshee|哭号女妖|生物~精怪|飞行\n当哭号女妖进场时,目标生物得-2/-2直到回合结束。 Keening Stone|恸哭石|神器|{5},{T}:目标牌手将其牌库顶的X张牌置入其坟墓场,X为该牌手坟墓场中牌的数量。 +Keeper of Fables|寓言守护兽|生物 ~猫|每当一个或数个由你操控的非人类生物对任一牌手造成战斗伤害时,抓一张牌。 Keeper of Keys|钥匙看守|生物~人类/浪客/突变体|当钥匙看守进战场时,你成为君主。\n在你的维持开始时,若你是君主,则由你操控的生物本回合不能被阻挡。 Keeper of Progenitus|祖神兽守卫|生物~地精/德鲁伊|每当牌手横置一个山脉,树林,或平原以产生法术力时,该牌手加一点法术力到他的法术力池中,其类别为该地刚才已产生之类别。 Keeper of the Lens|透镜守卫|神器生物~魔像|你可以检视不由你操控且牌面朝下的生物。(你可以随时如此作。) @@ -6372,6 +6398,7 @@ Kemba's Legion|肯芭军团兵|生物~猫/士兵|警戒\n肯芭军团兵上 Kemba's Skyguard|肯芭空护卫|生物~猫/骑士|飞行\n当肯芭空护卫进战场时,你获得2点生命。 Kemba, Kha Regent|摄政狮王肯芭|传奇生物~猫/僧侣|在你的维持开始时,摄政狮王肯芭上每装备一个武具,便将一个2/2白色的猫衍生生物放进战场。 Kemuri-Onna|烟女|生物~精怪|当烟女进场时,目标牌手弃一张牌。\n每当你使用精怪或古咒咒语时,你可以将烟女移回你手上。 +Kenrith's Transformation|肯理斯化身|结界 ~灵气|结附于生物\n当肯理斯化身进战场时,抓一张牌。\n所结附的生物失去所有异能,且是基础力量与防御力为3/3的绿色麋鹿生物。(它会失去其他牌张类别和生物类别。) Kenrith, the Returned King|复归国王肯理斯|传奇生物 ~人类/贵族|{R}:所有生物获得践踏与敏捷异能直到回合结束。\n{1}{G}:在目标生物上放置一个+1/+1指示物。\n{2}{W}:目标牌手获得5点生命。\n{3}{U}:目标牌手抓一张牌。\n{4}{B}:将目标生物牌在其拥有者的操控下从坟墓场放进战场。 Kentaro, the Smiling Cat|笑面猫宪太郎|传奇生物~人类/武士|武士道1 (每当它进行阻挡或被阻挡时,它得+1/+1直到回合结束。)\n你可支付{X},而不支付你所使用之武士咒语的法术力费用,X为该咒语的总法术力费用。 Keranos, God of Storms|风暴神刻拉诺斯|传奇结界生物~神|不灭\n只要你的蓝红两色献力小于七,刻拉诺斯便不是生物。\n展示你在自己的每个回合中所抓的第一张牌。每当你以此法展示出一张地牌时,抓一张牌。每当你以此法展示出一张非地牌时,刻拉诺斯对目标生物或牌手造成3点伤害。 @@ -6660,6 +6687,7 @@ Lapse of Certainty|丧失确信|瞬间|反击目标咒语。 如果以此法反 Laquatus's Champion|拉夸塔的斗士|生物 ~梦魇/惊惧兽|当拉夸塔的斗士进战场时,目标牌手失去6点生命。\n当拉夸塔的斗士离开战场时,该牌手获得6点生命。\n{B}:重生拉夸塔的斗士。 Larger Than Life|超越生灵|法术|直到回合结束,目标生物得+4/+4且获得践踏异能。 Lash Out|猛击|瞬间|猛击对目标生物造成3点伤害。 与一位对手比点。 若你赢,则猛击再对该生物的操控者造成3点伤害。 (参与比点的牌手各展示其牌库顶牌,然后将该牌置于牌库顶部或底部。 所展示的牌之总法术力费用比较高的牌手赢得比点。) +Lash of Thorns|荆棘鞭击|瞬间|直到回合结束,目标生物得+2/+1且获得死触异能。 Lash of the Whip|死神鞭击|瞬间|目标生物得-4/-4直到回合结束。 Lashweed Lurker|鞭草伏体|生物~奥札奇/惊惧兽|化生{5}{G}{U}(你可以牺牲一个生物并支付化生费用来施放此咒语,此时总费用会扣除该生物之总法术力费用。)\n当你施放鞭草伏体时,你可以将目标非地永久物置于其拥有者的牌库顶。 Lashwrithe|翻腾鞭|神器~武具|活化武器 (当此武具进战场时,将一个0/0黑色病菌衍生生物放进战场,然后将它装备上去。)\n你每操控一个沼泽,佩带此武具的生物便得+1/+1。\n佩带{B/P}{B/P} ({B/P}可用{B}或2点生命来支付。) @@ -6912,9 +6940,11 @@ Loathsome Catoblepas|恶憎牛身妖瞳|生物~野兽|{2}{G}:恶憎牛身妖 Lobber Crew|抛投小组|生物~鬼怪/战士|守军\n{T}:抛投小组向每位对手各造成1点伤害。\n每当你施放多色咒语时,重置抛投小组。 Loch Dragon|栖湖翔龙|生物 ~龙|飞行\n每当栖湖翔龙进战场或攻击时,你可以弃一张牌。若你如此作,则抓一张牌。 Loch Korrigan|湖岸夜水妖|生物~精怪|{U/B}:湖岸夜水妖得+1/+1直到回合结束。 +Lochmere Serpent|密尔湖巨蛇|生物 ~巨蛇|闪现\n{U},牺牲一个海岛:密尔湖巨蛇本回合不能被阻挡。\n{B},牺牲一个沼泽:你获得1点生命且抓一张牌。\n{U}{B}:将五张目标在同一对手坟墓场中的牌放逐。将密尔湖巨蛇从你的坟墓场移回你手上。只可以于你能施放法术的时机下起动此异能。 Locket of Yesterdays|昨日坠饰|神器|对你使用的咒语而言,你的坟墓场中每有一张与该咒语同名的牌,其费用便减少{1}来使用。 Lockjaw Snapper|紧咬草人|神器生物~稻草人|干枯 (此来源会以-1/-1指示物的方式对生物造成伤害。)\n当紧咬草人从场上置入坟墓场时,在每个上面有-1/-1指示物的生物上各放置一个-1/-1指示物。 Locthwain Gargoyle|洛司温石像鬼|神器生物 ~石像鬼|{4}:直到回合结束,洛司温石像鬼得+2/+0且获得飞行异能。 +Locthwain Paladin|洛司温神圣武士|生物 ~人类/骑士|威慑(此生物只能被两个或更多生物阻挡。)\n固色~如果施放此咒语时支付过至少三点黑色法术力,则洛司温神圣武士进战场时上面有一个+1/+1指示物。 Locust Miser|蝗虫守财奴|生物~老鼠/祭师|每位对手的手牌上限减少两张。 Lodestone Golem|磁石魔像|神器生物~魔像|非神器咒语增加{1}来施放。 Lodestone Myr|磁石秘耳|神器生物~秘耳|践踏\n横置一个由你操控且未横置的神器:磁石秘耳得+1/+1直到回合结束。 @@ -6956,6 +6986,7 @@ Lose Hope|丧失希望|瞬间|目标生物得-1/-1直到回合结束。\n占卜2 Lost Auramancers|迷失灵气法师|生物~人类/法术师|消逝3(此生物进场时上面有三个计时指示物。 在你的维持开始时,从其上移去一个计时指示物。 当移去最后一个时,将它牺牲。)\n当迷失灵气法师从场上置入坟墓场时,若其上没有计时指示物,则你可以从你的牌库中搜寻一张结界牌并将之放置进场。 若你如此作,则将你的牌库洗牌。 Lost Hours|损失时间|法术|目标牌手展示其手牌。 选择其中一张非地的牌。 该牌手将该牌置于牌库顶数来第三张的位置。 Lost Legacy|佚失遗物|法术|说出一个非神器且非地的牌之名称。从目标牌手的坟墓场,手牌及牌库中搜寻任意数量该名称的牌,并将它们放逐。该牌手将其牌库洗牌,然后每有一张以此法放逐的手牌,他便抓一张牌。 +Lost Legion|遗世军团|生物 ~精怪/骑士|当遗世军团进战场时,占卜2。(检视你牌库顶的两张牌,然后将其中任意数量的牌以任意顺序置于你牌库底,其余则以任意顺序置于你牌库顶。) Lost Leonin|丧心狮族|生物~猫/士兵|侵染 (此生物会以-1/-1指示物的方式对生物造成伤害,并以中毒指示物的方式对牌手造成伤害。) Lost Vale|未名谷|地|(由探源匕首转化。)\n{T}:加三点任意颜色的单色法术力到你的法术力池中。 Lost in a Labyrinth|迷宫迷途|瞬间|目标生物得-3/-0直到回合结束。占卜1。(检视你牌库顶的牌。你可以将该牌置于你的牌库底。) @@ -6968,6 +6999,7 @@ Lotus Cobra|莲花眼镜蛇|生物~蛇|地落~每当一个地在你的操控 Lotus Field|莲花田野|地|辟邪\n莲花田野须横置进战场。\n当莲花田野进战场时,牺牲两个地。\n{T}:加三点任意颜色的单色法术力。 Lotus Path Djinn|莲径巨灵|生物~巨灵/修行僧|飞行\n灵技(每当你施放非生物咒语时,此生物得+1/+1直到回合结束。) Lotus-Eye Mystics|莲目秘教徒|生物~人类/修行僧|灵技(每当你施放非生物咒语时,此生物得+1/+1直到回合结束。)\n当莲目秘教徒进战场时,将目标结界牌从你的坟墓场移回你手上。 +Lovestruck Beast|热恋野兽|生物 ~野兽/贵族|除非你操控1/1生物,否则热恋野兽不能攻击。 Lovisa Coldeyes|冷眼罗维莎|传奇生物~人类/领主|野蛮人,战士,以及狂战士得+2/+2并具有敏捷异能。 Lowland Oaf|低地蠢货|生物~巨人/战士|{T}:目标由你操控的精灵生物得+1/+0并获得飞行异能直到回合结束。 在回合结束时牺牲该生物。 Loxodon Anchorite|象族隐士|生物~象/僧侣|{T}:于本回合中,防止接下来将对目标生物或牌手造成的2点伤害。 @@ -7128,6 +7160,7 @@ Malakir Bloodwitch|马拉奇血祭师|生物~吸血鬼/祭师|飞行,反 Malakir Cullblade|马拉奇汰锋手|生物~吸血鬼/战士|每当一个由对手操控的生物死去时,在马拉奇汰锋手上放置一个+1/+1指示物。 Malakir Familiar|马拉奇佣兽|生物~蝙蝠|飞行,死触每当你获得生命时,马拉奇佣兽得+1/+1直到回合结束。 Malakir Soothsayer|马拉奇预言家|生物~吸血鬼/祭师/伙伴|齐力~{T},横置一个由你操控且未横置的伙伴:你抓一张牌且你失去1点生命。 +Malevolent Noble|恶毒贵族|生物 ~人类/贵族|{2},牺牲一个神器或另一个生物:在恶毒贵族上放置一个+1/+1指示物。 Malevolent Whispers|恶毒低语|法术|获得目标生物的操控权直到回合结束。重置该生物。直到回合结束,它得+2/+0且获得敏捷异能。\n疯魔{3}{R}(如果你弃掉此牌,将之弃到放逐区。当你如此作时,支付其疯魔费用施放之,否则便将其置入你的坟墓场。) Malfegor|墨非葛|传奇生物~恶魔/龙|飞行\n当墨非葛进场时,弃掉你的手牌。 每以此法弃掉一张牌,每位对手便牺牲一个生物。 Malfunction|失灵|结界~灵气|结附于神器或生物\n当失灵进战场时,横置所结附的永久物。\n所结附的永久物于其操控者的重置步骤中不能重置。 @@ -7178,6 +7211,8 @@ Mantle of Leadership|领袖披风|结界~灵气|闪现(你可以于你能够 Mantle of Tides|浪潮斗篷|神器 ~武具|佩带此武具的生物得+1/+2。\n每当你抓每回合中你的第二张牌时,将浪潮斗篷装备在目标由你操控的生物上。\n佩带{3}({3}:装备在目标由你操控的生物上。佩带的时机视同法术。) Mantle of Webs|蛛网披风|结界~灵气|结附于生物所结附的生物得+1/+3且具有延势异能。(此生物能阻挡具飞行异能的生物。) Map the Wastes|勘查荒漠|法术|从你的牌库中搜寻一张基本地牌,将之横置进战场,然后将你的牌库洗牌。振励1。(于由你操控的生物中选择一个防御力最小的生物,在其上放置一个+1/+1指示物。) +Maraleaf Pixie|马利夫碧仙|生物 ~仙灵|飞行\n{T}:加{G}或{U}。 +Maraleaf Rider|马利夫骑兵|生物 ~妖精/骑士|牺牲一个食品:目标生物本回合若能阻挡马利夫骑兵,则须阻挡之。 Maralen of the Mornsong|晨曲的马拉兰|传奇生物~地精/法术师|牌手不能抓牌。\n在每位牌手的抓牌步骤开始时,该牌手失去3点生命,从其牌库中搜寻一张牌,将该牌置于其手上,然后将他的牌库洗牌。 Marang River Prowler|马兰河游掠者|生物~人类/浪客|马兰河游掠者不能进行阻挡,也不能被阻挡。\n只要你操控黑色或绿色永久物,你便可以从你坟墓场中施放马兰河游掠者。 Marang River Skeleton|马兰河骷髅妖|生物~骷髅妖|{B}:重生马兰河骷髅妖。\n威力变身{3}{B}(你可牌面朝下地施放此牌并支付{3},将其当成2/2生物。可随时支付其威力变身费用使其翻回正面,并在其上放置一个+1/+1指示物。) @@ -7366,6 +7401,7 @@ Memory Erosion|侵蚀记忆|结界|每当任一对手使用咒语时,该牌手 Memory Lapse|记忆丧失|瞬间|反击目标咒语。如果以此法反击该咒语,则改为将它置于其拥有者的牌库顶,而非置入该牌手的坟墓场。 Memory Plunder|记忆劫夺|瞬间|你可以使用在对手坟墓场中的目标瞬间或法术牌,且不需支付其法术力费用。 Memory Sluice|记忆奔流|法术|目标牌手将其牌库顶的四张牌置入其坟墓场。\n协力 (于你使用此咒语时,你可以横置两个由你操控、且与此咒语有共通颜色的未横置生物。 当你如此作,则复制此咒语,且你可以为该复制品选择新的目标。) +Memory Theft|窃取记忆|法术|目标对手展示其手牌。你选择其中一张非地牌。该牌手弃掉该牌。你可以将一张由该牌手拥有且具有历险的牌从放逐区置入该牌手的坟墓场。 Memory's Journey|记忆之旅|瞬间|目标牌手将至多三张目标牌从他的坟墓场洗入其牌库。\n返照{G} (你可以从你的坟墓场施放此牌,并支付其返照费用,然后将它放逐。) Memory|记忆|法术|余响(此咒语只能从你的坟墓场中施放。然后将它放逐。)\n每位牌手将其手牌与坟墓场洗入其牌库,然后各抓七张牌。 Menagerie Liberator|困兽解放者|生物~人类/战士|践踏\n乱斗(每当此生物攻击时,本次战斗中每有一位受你以生物攻击的对手,此生物便得+1/+1直到回合结束。) @@ -7781,6 +7817,7 @@ Murderer's Axe|行凶利斧|神器~武具|佩带此武具的生物得+2/+2。\ Murderous Compulsion|谋杀冲动|法术|消灭目标已横置的生物。\n疯魔{1}{B}(如果你弃掉此牌,将之弃到放逐区。当你如此作时,支付其疯魔费用施放之,否则便将其置入你的坟墓场。) Murderous Cut|夺魂斩|瞬间|掘穴(你于施放此咒语时每从你坟墓场中放逐一张牌,就能为此咒语支付{1})。\n消灭目标生物。 Murderous Redcap|夺魂红帽客|生物~精灵/杀手|当夺魂红帽客进场时,它对目标生物或牌手造成伤害,其数量等同于其力量。\n留存 (当此生物从场上置入坟墓场时,若其上没有-1/-1指示物,则将它在其拥有者的操控下返回场上,且其上有一个-1/-1指示物。) +Murderous Rider|夺魂骑兵|生物 ~灵俑/骑士|系命\n当夺魂骑兵死去时,将它置于其拥有者的牌库底。 Murderous Spoils|杀人越货|瞬间|消灭目标非黑色的生物。 它不能重生。 你获得该生物装备的所有武具之操控权。 (此效应不因回合结束而终止) Murder|谋杀|瞬间|消灭目标生物。 Murk Strider|暗沼神行体|生物~奥札奇/噬体|虚色(此牌没有颜色。)当暗沼神行体进战场时,你可以将一张由对手拥有的牌从放逐区置入该玩家的坟墓场。若你如此作,则将目标生物移回其拥有者手上。 @@ -8187,9 +8224,11 @@ Nyxborn Triton|天裔屈东|结界生物~人鱼|神授{4}{U}(如果你支付 Nyxborn Wolf|天裔狼|结界生物~狼|神授{4}{G}(如果你支付此牌的神授费用来施放它,则它便是具「结附于生物」的灵气咒语。如果它未结附于生物上,就会再度成为生物。)\n所结附的生物得+3/+1。 O-Naginata|大薙刀|神器~武具|大薙刀只能装备在力量大于或等于3的生物上。\n佩带此武具的生物得+3/+0且具有践踏异能。\n佩带{2}({2}:装备在目标由你操控的生物上; 佩带的时机视同法术。) Oak Street Innkeeper|橡树街旅店主|生物~妖精|只要不是在你的回合中,由你操控且已横置的生物便具有辟邪异能。 +Oaken Boon|橡木恩泽|法术~历险|在目标生物上放置两个+1/+1指示物。(然后放逐此牌。之后你还可以从放逐区中施放该生物。) Oaken Brawler|橡树喧哗兵|生物~树妖/战士|当橡树喧哗兵进场时,与一位对手比点。 若你赢,则在橡树喧哗兵上放置一个+1/+1指示物。 (参与比点的牌手各展示其牌库顶牌,然后将该牌置于牌库顶部或底部。 所展示的牌之总法术力费用比较高的牌手赢得比点。) Oakenform|橡树形体|结界 ~灵气|结附于生物\n所结附的生物得+3/+3。 Oakgnarl Warrior|橡节战士|生物~树妖/战士|警戒,践踏 +Oakhame Adversary|橡树宫仇敌|生物 ~妖精/战士|如果任一对手操控绿色永久物,则此咒语减少{2}来施放。\n死触\n每当橡树宫仇敌对任一牌手造成战斗伤害时,抓一张牌。 Oakhame Ranger|橡树宫巡林客|生物 ~妖精/骑士|{T}:由你操控的生物得+1/+1直到回合结束。 Oakheart Dryads|橡心树灵|结界生物~宁芙/树灵|星彩~每当橡心树灵或另一个结界在你的操控下进战场时,目标生物得+1/+1直到回合结束。 Oashra Cultivator|欧夏拉耕者|生物~人类/德鲁伊|{2}{G},{T},牺牲欧夏拉耕者:从你的牌库中搜寻一张基本地牌,将之横置放进战场,然后将你的牌库洗牌。 @@ -8206,6 +8245,7 @@ Oath of Teferi|泰菲力的誓约|传奇结界|当泰菲力的誓约进战场时 Oath of the Ancient Wood|古林誓约|结界|每当古林誓约或另一个结界在你的操控下进战场时,你可以在目标生物上放置一个+1/+1指示物。 Oathkeeper, Takeno's Daisho|武野配刀正守|传奇神器~武具|佩带此武具的生物得+3/+1。\n每当佩带此武具的生物从场上进入坟墓场时,如果它是武士,则将该牌在你的操控下移回场上。\n当武野配刀正守从场上进入坟墓场时,将佩带此武具的生物移出对战。\n佩带{2} Oathsworn Giant|立誓巨人|生物~巨人/士兵|警戒\n由你操控的其它生物得+0/+2并具有警戒异能。 +Oathsworn Knight|守誓骑士|生物 ~人类/骑士|守誓骑士进战场时上面有四个+1/+1指示物。\n守誓骑士每次战斗若能攻击,则必须攻击。\n如果守誓骑士于其上有+1/+1指示物时将受到伤害,则防止该伤害,并从守誓骑士上移去一个+1/+1指示物。 Oathsworn Vampire|立誓吸血鬼|生物 ~吸血鬼/骑士|立誓吸血鬼须横置进战场。\n如果你于本回合中曾获得生命,则你可以从你的坟墓场中施放立誓吸血鬼。 Ob Nixilis Reignited|火花重燃的欧尼希兹|鹏洛客~尼希兹|+1:你抓一张牌且你失去1点生命。−3:消灭目标生物。−8:目标对手获得具有「每当一位牌手抓一张牌时,你失去2点生命」的徽记。 Ob Nixilis of the Black Oath|黯约者欧尼希兹|鹏洛客~尼希兹|+2:每位对手各失去1点生命。你获得若干生命,其数量等同于以此法失去的生命总和。\n−2:将一个5/5黑色,具飞行异能的恶魔衍生生物放进战场。你失去2点生命。\n−8:你获得具有「{1}{B},牺牲一个生物:你获得X点生命且抓X张牌,X为所牺牲生物的力量」的徽记。\n黯约者欧尼希兹可用作指挥官。 @@ -8285,6 +8325,7 @@ Okina Nightwatch|翁神社夜巡班|生物~人类/修行僧|只要你的手 Okina, Temple to the Grandfathers|翁神社|传奇地|{T}:加{G}到你的法术力池中。\n{G},{T}:目标传奇生物得+1/+1直到回合结束。 Oko's Accomplices|瓯柯的同伙|生物 ~仙灵|飞行 Oko's Hospitality|瓯柯式恭迎|瞬间|由你操控的生物之基础力量与防御力为3/3直到回合结束。你可以从你的牌库和/或坟墓场中搜寻一张名称为幻法仙灵瓯柯的牌,展示该牌,并将它置于你手上。如果你以此法搜寻你的牌库,则将它洗牌。 +Oko, Thief of Crowns|窃冠瓯柯|传奇鹏洛客 ~瓯柯|+2:派出一个食品衍生物。\n+1:目标神器或生物失去所有异能,且成为基础力量与防御力为3/3的绿色麋鹿生物。\n−5:选择目标由你操控的神器或生物和目标由对手操控且力量等于或小于3的生物。交换两者的操控权。 Oko, the Trickster|幻法仙灵瓯柯|传奇鹏洛客 ~瓯柯|+1:在至多一个目标由你操控的生物上放置两个+1/+1指示物。\n0:直到回合结束,幻法仙灵瓯柯成为目标由你操控的生物之复制品。防止本回合中将对他造成的所有伤害。\n−7:直到回合结束,每个由你操控的生物均获得践踏异能,且基础力量与防御力都为10/10。 Old Ghastbark|老白皮木|生物~树妖/战士| Old-Growth Dryads|古生树灵|生物 ~树灵|当古生树灵进战场时,每位对手各可以从其牌库中搜寻一张基本地牌,将之横置放进战场,然后将其牌库洗牌。 @@ -8305,6 +8346,8 @@ On Alert|警报戒备|瞬间~历险|目标生物得+2/+2直到回合结束。 On Serra's Wings|承撒拉之翼|传奇结界 ~灵气|结附于生物\n所结附的生物是传奇,得+1/+1,且具有飞行、警戒与系命异能。 On Thin Ice|孤囚悬冰|雪境结界 ~灵气|结附于由你操控的雪境地\n当孤囚悬冰进战场时,放逐目标由对手操控的生物,直到孤囚悬冰离开战场为止。 Onakke Ogre|欧纳克食人魔|生物 ~食人魔/战士| +Once Upon a Time|很久以前|瞬间|如果此咒语是你本盘游戏中施放的第一个咒语,则你施放它时可以不需支付其法术力费用。\n检视你牌库顶的五张牌。你可以展示其中的一张生物或地牌,并将它置于你手上。将其余的牌以随机顺序置于你的牌库底。 +Once and Future|王脉永传|瞬间|将目标牌从你的坟墓场移回你手上。将至多另一张目标牌从你坟墓场置于你的牌库顶。放逐王脉永传。\n固色~如果施放此咒语时支付过至少三点绿色法术力,则改为将这些牌移回你手上并放逐王脉永传。 Ondu Champion|昂度斗士|生物~牛头怪/战士/伙伴|奋扬~每当昂度斗士或另一个伙伴在你的操控下进战场时,由你操控的生物获得践踏异能直到回合结束。 Ondu Cleric|昂度僧侣|生物~寇族/僧侣/伙伴|每当昂度僧侣或另一个伙伴在你的操控下进战场时,你可以获得若干生命,其数量等同于由你操控的伙伴数量。 Ondu Giant|昂度巨人|生物~巨人/德鲁伊|当昂度巨人进战场时,你可以从你的牌库中搜寻一张基本地牌,将之横置进战场,然后将你的牌库洗牌。 @@ -8386,6 +8429,7 @@ Ordeal of Heliod|赫利欧德的试炼|结界 ~灵气|结附于生物\n每当 Ordeal of Nylea|倪勒娅的试炼|结界~灵气|结附于生物\n每当所结附的生物攻击时,在其上放置一个+1/+1指示物。然后如果该生物上有三个或更多+1/+1指示物,则牺牲倪勒娅的试炼。\n当你牺牲倪勒娅的试炼时,从你的牌库中搜寻至多两张基本地牌,将它们横置进战场,然后将你的牌库洗牌。 Ordeal of Purphoros|普罗烽斯的试炼|结界~灵气|结附于生物\n每当所结附的生物攻击时,在其上放置一个+1/+1指示物。然后如果该生物上有三个或更多+1/+1指示物,则牺牲普罗烽斯的试炼。\n当你牺牲普罗烽斯的试炼时,它对目标生物或牌手造成3点伤害。 Ordeal of Thassa|塔萨的试炼|结界~灵气|结附于生物\n每当所结附的生物攻击时,在其上放置一个+1/+1指示物。然后如果该生物上有三个或更多+1/+1指示物,则牺牲塔萨的试炼。\n当你牺牲塔萨的试炼时,抓两张牌。 +Order of Midnight|午夜骑士团|生物 ~人类/骑士|飞行\n午夜骑士团不能进行阻挡。 Order of Whiteclay|白土教士團|生物~洁英/僧侣|{1}{W}{W},{Q}:将目标总法术力费用等于或小于3的生物牌从你的坟墓场移回场上。 ({Q}是重置符号。) Order of the Golden Cricket|金蟋蟀骑士团|生物~洁英/骑士|每当金蟋蟀骑士团攻击时,你可以支付{W}。 若你如此作,则它获得飞行异能直到回合结束。 Order of the Sacred Bell|圣钟教士团|生物~人类/修行僧| @@ -8439,6 +8483,8 @@ Out of Bounds|越线出界|瞬间|助力(另一位牌手能够为此咒语的 Outflank|侧翼突破|瞬间|侧翼突破对目标进行攻击或阻挡的生物造成伤害,其数量等同于由你操控的生物数量。 Outland Boar|边境野猪|生物~野猪|边境野猪不能被力量等于或小于2的生物阻挡。 Outland Colossus|离乡巨汉|生物~巨人|铭勇6(当此生物对任一牌手造成战斗伤害时,若它未铭勇,则在其上放置六个+1/+1指示物且它已铭勇。)离乡巨汉不能被多于一个生物阻挡。 +Outlaws' Merriment|狂徒嬉戏|结界|在你的维持开始时,随机选择一项。派出一个具相应特征的红白双色衍生生物。\n•3/1的人类/战士,且具践踏与敏捷。\n•2/1的人类/僧侣,且具系命与敏捷。\n•1/2的人类/浪客,且具敏捷与「当此生物进战场时,它对任意一个目标造成1点伤害。」 +Outmuscle|膂力过人|法术|在目标由你操控的生物上放置一个+1/+1指示物,然后它与目标不由你操控的生物互斗。(它们各向对方造成等同于本身力量的伤害。)\n固色~如果施放此咒语时支付过至少三点绿色法术力,则该由你操控的生物获得不灭异能直到回合结束。 Outnumber|以量取胜|瞬间|以量取胜对目标生物造成伤害,其数量等同于由你操控的生物数量。 Outpost Siege|围攻哨站|结界|于围攻哨站进战场时,选择可汗或龙王。\n● 可汗~在你的维持开始时,放逐你的牌库顶牌。直到回合结束,你可以使用该牌。\n● 龙王~每当一个由你操控的生物离开战场时,围攻哨站对目标生物或牌手造成1点伤害。 Outrage Shaman|暴怒祭师|生物~精灵/祭师|渲色~当暴怒祭师进场时,它对目标生物造成伤害,其数量等同于由你操控的每个永久物之法术力费用中红色法术力符号之数量。 @@ -8952,6 +8998,7 @@ Prodigal Pyromancer|放荡烈焰术士|生物~人类/法术师|{T}:放荡 Prodigal Sorcerer|放荡的术士|生物~人类/法术师|{T}:放荡的术士对目标生物或牌手造成1点伤害。 Prodigious Growth|异常成长|结界 ~灵气|结附于生物\n所结附的生物得+7/+7且具有践踏异能。 Profane Command|渎神指命|法术|选择两项~\n• 目标牌手失去X点生命。\n• 将目标总法术力费用等于或小于X的生物牌从你的坟墓场移回战场。\n• 目标生物得-X/-X直到回合结束。\n• 至多X个目标生物获得恐惧异能直到回合结束。 +Profane Insight|渎神洞察|瞬间~历险|你抓一张牌且你失去1点生命。(然后放逐此牌。之后你还可以从放逐区中施放该生物。) Profane Memento|异端祷物|神器|每当任一生物牌从任何区域置入对手的坟墓场时,你获得1点生命。 Profane Procession|渎神行列|传奇结界|{3}{W}{B}:放逐目标生物。然后如果放逐区中有三张或更多以渎神行列放逐的牌,转化渎神行列。 Profaner of the Dead|扰亡师|生物~那伽/法术师|榨取(当此生物进战场时,你可以牺牲一个生物。)\n当扰亡师榨取生物时,将所有由对手操控且防御力小于所榨取之生物的生物移回其拥有者手上。 @@ -9122,6 +9169,7 @@ Quest for the Goblin Lord|探索鬼怪领主|结界|每当一个鬼怪在你的 Quest for the Gravelord|探索坟场王侯|结界|每当一个生物从战场进入坟墓场时,你可以在探索坟场王侯上放置一个探索指示物。\n从探索坟场王侯上移去三个探索指示物并牺牲它:将一个5/5黑色灵俑/巨人衍生物放进战场。 Quest for the Holy Relic|探索神圣遗宝|结界|每当你施放生物咒语时,你可以在探索神圣遗宝上放置一个探索指示物。\n从探索神圣遗宝上移去五个探索指示物并牺牲它:从你的牌库中搜寻一张武具牌,将它放进战场,并装备在由你操控的一个生物上。 然后将你的牌库洗牌。 Quest for the Nihil Stone|探索返虚石|结界|每当任一对手弃一张牌时,你可以在探索返虚石上放置一个探索指示物。\n在每位对手的维持开始时,若该牌手没有手牌、且探索返虚石上有两个或更多探索指示物,你可以令该牌手失去5点生命。 +Questing Beast|寻水兽|传奇生物 ~野兽|警戒,死触,敏捷\n寻水兽不能被力量等于或小于2的生物阻挡。\n由你操控之生物所造成的战斗伤害不能被防止。\n每当寻水兽向任一对手造成战斗伤害时,它对目标由该牌手操控的鹏洛客造成等量的伤害。 Quickchange|快速变装|瞬间|直到回合结束,目标生物的颜色成为由你选择的颜色或颜色组合。\n抓一张牌。 Quicken|加快|瞬间|你于本回合中下一次施放的法术牌能视同具有闪现异能地来施放。(该牌可以于你能够施放瞬间的时机下施放。)抓一张牌。 Quickling|迅敏仙灵|生物~仙灵/浪客|闪现(你可以于你能够施放瞬间的时机下施放此咒语。)\n飞行\n当迅敏仙灵进战场时,除非你将另一个由你操控的生物移回其拥有者手上,否则牺牲迅敏仙灵。 @@ -9552,6 +9600,7 @@ Retreat to Valakut|撤往瓦拉库|结界|地落~每当一个地在你的操 Retribution of the Ancients|先人报偿|结界|{B},从由你操控的生物上移去总共X个+1/+1指示物:目标生物得-X/-X直到回合结束。 Retributive Wand|报复法杖|神器|{3},{T}:报复法杖对任意一个目标造成1点伤害。\n当报复法杖从战场进入坟墓场时,它对任意一个目标造成5点伤害。 Return from Extinction|灭绝重生|法术|选择一项~\n•将目标生物牌从你的坟墓场移回你手上。\n•将两张目标具共通之生物类别的生物牌从你的坟墓场移回你手上。 +Return of the Wildspeaker|召兽使复归|瞬间|选择一项~\n•抓若干牌,其数量等同于由你操控的非人类生物中力量最大者的数值。\n•由你操控的非人类生物得+3/+3直到回合结束。 Return to Battle|Return to Battle|| Return to Dust|终归浮尘|瞬间|将目标神器或结界移出对战。 如果你在你的行动阶段使用此咒语,则你可以将至多另一个目标神器或结界移出对战。 Return to Nature|回返自然|瞬间|选择一项~\n•消灭目标神器。\n•消灭目标结界。\n•将目标牌从坟墓场放逐。 @@ -9785,6 +9834,8 @@ Rootwater Commando|根潭突击兵|生物~人鱼|海岛行者(只要防御 Rootwater Matriarch|根潭女族长|生物~人鱼|{T}:选择目标生物。只要该生物被结附,你便获得其操控权。 Rorix Bladewing|锋翼洛里兹|传奇生物~龙|飞行,敏捷 Rosemane Centaur|玫瑰鬃半人马|生物 ~半人马/士兵|召集(此咒语能用你的生物来协助施放。你于施放此咒语时每横置一个生物,就能为此咒语支付{1}或一点该生物颜色之法术力。)\n警戒 +Rosethorn Acolyte|玫茨侍僧|生物 ~妖精/德鲁伊|{T}:加一点任意颜色的法术力。 +Rosethorn Halberd|玫茨长戟|神器 ~武具|当玫茨长戟进战场时,将它装备在目标由你操控的非人类生物上。\n佩带此武具的生物得+2/+1。\n佩带{5}({5}:装备在由你操控的目标生物上。佩带的时机视同法术。) Rosheen Meanderer|漫步人罗欣|传奇生物~巨人/祭师|{T}:加{4}到你的法术力池中。 此法术力只能用来支付包含{X}的费用。 Rot Farm Skeleton|腐尸农场骷髅妖|生物~植物/骷髅妖|腐尸农场骷髅妖不能进行阻挡。\n{2}{B}{G},将你牌库顶的四张牌置入你的坟墓场:将腐尸农场骷髅妖从你的坟墓场移回战场。你只可以于你能施放法术的时机下起动此异能。 Rot Shambler|腐臭跛行兽|生物~真菌|每当另一个由你操控的生物死去时,在腐臭跛行兽上放置一个+1/+1指示物。 @@ -10250,6 +10301,7 @@ Searing Spear|炙热矛|瞬间|炙热矛对目标生物或牌手造成3点伤害 Seascape Aerialist|海景舞空师|生物~人鱼/法术师/伙伴|每当海景舞空师或另一个伙伴在你的操控下进战场时,你可以让由你操控的伙伴生物获得飞行异能直到回合结束。 Seaside Citadel|海滨殿堂|地|海滨殿堂须横置进场。\n{T}:加{G},{W},或{U}到你的法术力池中。 Season of Growth|成长季节|结界|每当一个生物在你的操控下进战场时,占卜1。(检视你牌库顶的牌。你可以将该牌置于你的牌库底。)\n每当你施放以由你操控之生物为目标的咒语时,抓一张牌。 +Seasonal Ritual|季节仪式|法术~历险|加一点任意颜色的法术力。(然后放逐此牌。之后你还可以从放逐区中施放该生物。) Seasoned Marshal|经验老到的元帅|生物~人类/士兵|每当经验老到的元帅攻击时,你可以横置目标生物。 Seasoned Pyromancer|干练烈焰术士|生物 ~人类/祭师|当干练烈焰术士进战场时,弃两张牌,然后抓两张牌。每以此法弃掉一张非地牌,便派出一个1/1红色元素衍生生物。\n{3}{R}{R},从你的坟墓场放逐干练烈焰术士:派出两个1/1红色元素衍生生物。 Seasons Past|时迁季移|法术|将任意数量的牌从你的坟墓场移回你手上,且这些牌的总法术力费用须各不相同。将时迁季移置于其拥有者的牌库底。 @@ -10520,6 +10572,7 @@ Shield of the Avatar|圣者之盾|神器~武具|如果某来源将对佩带此 Shield of the Oversoul|超灵之盾|结界~灵气|生物结界\n只要受此结界的生物是绿色,它便得+1/+1且不会毁坏。 (致命伤害以及注明「消灭」的效应都不会将它消灭。 如果其防御力降到0或更少,它仍会置入其拥有者的坟墓场。)\n只要受此结界的生物是白色,它便得+1/+1且具有飞行异能。 Shield of the Realm|圣域坚盾|神器 ~武具|如果某来源将对佩带此武具的生物造成伤害,则防止该伤害中的2点。\n佩带{1} Shield of the Righteous|义人之盾|神器~武具|佩带此武具的生物得+0/+2且具有警戒异能。\n每当佩带此武具的生物阻挡其他生物时,后者于其操控者的下一个重置步骤中不能重置。\n佩带{2} +Shield's Might|护盾之力|瞬间~历险|目标生物得+2/+2直到回合结束。(然后放逐此牌。之后你还可以从放逐区中施放该生物。) Shielded Aether Thief|佩盾乙太贼|生物~维多肯/浪客|闪现(你可以于你能够施放瞬间的时机下施放此咒语。)\n每当佩盾乙太贼阻挡时,你得到{E}(一个能量指示物)。\n{T},支付{E}{E}{E}:抓一张牌。 Shielded Passage|严护通道|瞬间|于本回合中,防止将对目标生物造成的所有伤害。 Shielded by Faith|信念卫护|结界~灵气|结附于生物所结附的生物具有不灭异能。每当一个生物进战场时,你可以将信念卫护结附在该生物上。 @@ -11320,7 +11373,7 @@ Spore Burst|孢子爆发|法术|领土~由你操控的地之中每有一种基 Spore Frog|芽胞蛙|生物 ~蛙|牺牲芽胞蛙:于本回合中,防止将造成的所有战斗伤害。 Spore Swarm|孢子大群|瞬间|派出三个1/1绿色腐生物衍生生物。 Sporeback Troll|孢背巨魔|生物~巨魔/突变体|接殖2(此生物进场时上面有两个+1/+1指示物。 每当另一个生物进场时,你可以将此生物上的一个+1/+1指示物移到前者上。)\n{1}{G}:重生目标具有+1/+1指示物的生物。 -Sporecap Spider|菇顶蜘蛛|生物~蜘蛛|延势 (此生物能阻挡具飞行异能的生物。) +Sporecap Spider|菇顶蜘蛛|生物 ~蜘蛛|延势 Sporecrown Thallid|孢冠散绿菌|生物 ~真菌|由你操控且为真菌或腐生物的其他生物各得+1/+1。 Sporemound|孢子堆|生物~真菌|每当一个地在你的操控下进战场时,将一个1/1绿色腐生物衍生生物放进战场。 Sporesower Thallid|孢舞散绿菌|生物~真菌|在你的维持开始时,在每个由你操控的真菌上放置一个芽孢指示物。\n从孢舞散绿菌上移去三个芽孢指示物:将一个1/1绿色腐生物衍生物放置进场。 @@ -11794,6 +11847,7 @@ Swell of Courage|壮大勇气|瞬间|由你操控的生物得+2/+2直到回合 Swell of Growth|壮大成长|瞬间|目标生物得+2/+2直到回合结束。你可以将一张地牌从你手上放进战场。 Sweltering Suns|灼热双日|法术|灼热双日对每个生物各造成3点伤害。\n循环{3}({3},弃掉此牌:抓一张牌。) Swerve|方向偏离|瞬间|为仅指定单一目标的目标咒语更改目标。 +Swift End|迅速终结|瞬间~历险|消灭目标生物或鹏洛客。你失去2点生命。(然后放逐此牌。之后你还可以从放逐区中施放该生物。) Swift Justice|正义迅彰|瞬间|直到回合结束,目标生物得+1/+0且获得先攻与系命异能。 Swift Kick|旋风腿|瞬间|目标由你操控的生物得+1/+0直到回合结束。它与目标不由你操控的生物互斗。 Swift Maneuver|迅速巧驭|瞬间|于本回合中,为目标生物或牌手防止接下来的2点伤害。\n在下回合维持开始时抓一张牌。 @@ -11866,6 +11920,7 @@ Syphon Soul|吸魂|法术|吸魂对每位其他牌手各造成2点伤害。你 Syr Alin, the Lion's Claw|狮爪艾林爵士|传奇生物 ~人类/骑士|先攻\n每当狮爪艾林爵士攻击时,由你操控的其他生物得+1/+1直到回合结束。 Syr Carah, the Bold|勇威凯拉爵士|传奇生物 ~人类/骑士|每当勇威凯拉爵士或由你操控的瞬间或法术咒语对任一牌手造成伤害时,放逐你的牌库顶牌。本回合中,你可以使用该牌。\n{T}:凯拉爵士对任意一个目标造成1点伤害。 Syr Elenora, the Discerning|慧眼伊诺拉爵士|传奇生物 ~人类/骑士|慧眼伊诺拉爵士的力量等同于你的手牌数量。\n当伊诺拉爵士进战场时,抓一张牌。\n对手施放之以伊诺拉爵士为目标的咒语增加{2}来施放。 +Syr Faren, the Hengehammer|阵锤芳纶爵士|传奇生物 ~人类/骑士|每当阵锤芳纶爵士攻击时,另一个目标进行攻击的生物得+X/+X直到回合结束,X为芳纶爵士的力量。 Syr Konrad, the Grim|冷酷孔纳德爵士|传奇生物 ~人类/骑士|每当另一个生物死去,或一张生物牌从战场以外的任何区域进入坟墓场,或一张生物牌离开你的坟墓场时,冷酷孔纳德爵士向每位对手各造成1点伤害。\n{1}{B}:每位牌手各将其牌库顶牌置入其坟墓场。 Szadek, Lord of Secrets|诡秘王者札戴克|传奇生物~吸血鬼|飞行\n若诡秘王者札戴克将对牌手造成战斗伤害,则改为在札戴克上放置等量的+1/+1指示物,且该牌手将其牌库顶等量的牌置入其坟墓场。 Séance|降灵|结界|在每个维持开始时,你可以从你的坟墓场放逐目标生物牌。若你如此作,将一个衍生物放进战场,且为该牌的复制品,并额外具有精怪此类别。在下一个结束步骤开始时,将它放逐。 @@ -11908,6 +11963,7 @@ Talisman of Creativity|创新饰符|神器|{T}:加{C}。\n{T}:加{U}或{R} Talisman of Curiosity|求知饰符|神器|{T}:加{C}。\n{T}:加{G}或{U}。求知饰符对你造成1点伤害。 Talisman of Hierarchy|阶层饰符|神器|{T}:加{C}。\n{T}:加{W}或{B}。阶层饰符对你造成1点伤害。 Talisman of Resilience|复生饰符|神器|{T}:加{C}。\n{T}:加{B}或{G}。复生饰符对你造成1点伤害。 +Tall as a Beanstalk|豆茎高耸|结界 ~灵气|结附于生物\n所结附的生物得+3/+3,具有延势异能,且额外具有巨人此类别。 Tallowisp|油蜡鬼火|生物~精怪|每当你使用精怪或古咒咒语时,你可以从你的牌库中搜寻一张生物结界牌,展示该牌,并置于你手上。 若你如此作,则将你的牌库洗牌。 Talon Trooper|利爪装甲兵|生物~鸟/斥候|飞行 Talon of Pain|苦楚秘爪|神器|每当由你操控的一个来源向对手造成伤害,且该来源并非苦楚秘爪时,在苦楚秘爪上放置一个充电指示物。\n{X},{T},从苦楚秘爪上移去X个充电指示物:苦楚秘爪对目标生物或牌手造成X点伤害。 @@ -12120,6 +12176,7 @@ The First Sliver|原初裂片妖|传奇生物 ~裂片妖|倾曳(当你施放 The Flame of Keld|凯尔顿源火|结界 ~传纪|(于此传纪进战场时及于你抓牌步骤后,加一个学问指示物。到III后牺牲之。)\nI — 弃掉你的手牌。\nII — 抓两张牌。\nIII — 本回合中,如果某个由你操控的红色来源将对任一永久物或牌手造成伤害,则改为它对该永久物或牌手造成原数量加2点伤害。 The Gitrog Monster|噬人蛙怪|传奇生物~蛙/惊惧兽|死触\n在你的维持开始时,除非你牺牲一个地,否则牺牲噬人蛙怪。\n你在自己的每个回合中可以额外使用一个地。\n每当一张或数张地牌从任何区域置入你的坟墓场时,抓一张牌。 The Great Aurora|伟大极光|法术|每位牌手将其所有手牌和由他拥有的所有永久物洗入其牌库,然后各抓等量的牌。每位牌手可以将任意数量的地牌从其手上放进战场。放逐伟大极光。 +The Great Henge|巨石圆阵|传奇神器|此咒语减少{X}来施放,X为由你操控的生物中力量最大者的数值。\n{T}:加{G}{G}。你获得2点生命。\n每当一个非衍生物的生物在你的操控下进战场时,在其上放置一个+1/+1指示物且抓一张牌。 The Haunt of Hightower|高塔祟影|传奇生物 ~吸血鬼|飞行,系命\n每当高塔祟影攻击时,防御牌手弃一张牌。\n每当一张牌从任何区域置入对手的坟墓场时,在高塔祟影上放置一个+1/+1指示物。 The Hive|蜂箱|神器|{5},{T}:将一个1/1,名称为黄蜂,具飞行异能的昆虫神器生物衍生物放置进场。 (只有具飞行或延势异能的生物才能阻挡它。) The Immortal Sun|永生圣阳|传奇神器|牌手不能起动鹏洛客的忠诚异能。\n在你的抓牌步骤开始时,额外抓一张牌。\n你施放的咒语减少{1}来施放。\n由你操控的生物得+1/+1。 @@ -12128,6 +12185,7 @@ The Magic Mirror|魔法明镜|传奇神器|你坟墓场中每有一张瞬间与 The Mending of Dominaria|多明纳里亚愈合|结界 ~传纪|(于此传纪进战场时及于你抓牌步骤后,加一个学问指示物。到III后牺牲之。)\nI, II — 将你牌库顶的两张牌置入你的坟墓场,然后你可以将一张生物牌从你的坟墓场移回你手上。\nIII — 将所有地牌从你的坟墓场移回战场,然后将你的坟墓场洗入你的牌库。 The Mirari Conjecture|映奇宝珠探究|结界 ~传纪|(于此传纪进战场时及于你抓牌步骤后,加一个学问指示物。到III后牺牲之。)\nI — 将目标瞬间牌从你的坟墓场移回你手上。\nII — 将目标法术牌从你的坟墓场移回你手上。\nIII — 直到回合结束,每当你施放瞬间或法术咒语时,将其复制。你可以为该复制品选择新的目标。 The Rack|拷问台|神器|于拷问台进场时,选择一位对手。\n在该牌手的维持开始时,拷问台对该牌手造成X点伤害,X为3减去其手牌数量。 +The Royal Scions|皇族双子|传奇鹏洛客 ~威尔/萝婉|+1:抓一张牌,然后弃一张牌。\n+1:直到回合结束,目标生物得+2/+0且获得先攻与践踏异能。\n−8:抓四张牌。当你如此作时,皇族双子对任意一个目标造成等同于你手牌数量的伤害。 The Scarab God|甲虫神|传奇生物~神|在你的维持开始时,每位对手各失去X点生命且你占卜X,X为由你操控的灵俑数量。\n{2}{U}{B}:将目标生物牌从坟墓场放逐。派出一个衍生物,该衍生物为所放逐之牌的复制品,但它是4/4黑色灵俑。\n当甲虫神死去,在下一个结束步骤开始时,将它移回其拥有者手上。 The Scorpion God|毒蝎神|传奇生物~神|每当一个其上有-1/-1指示物的生物死去时,抓一张牌。\n{1}{B}{R}:在另一个目标生物上放置一个-1/-1指示物。\n当毒蝎神死去,在下一个结束步骤开始时,将它移回其拥有者手上。 The Unspeakable|忌话图|传奇生物~精怪|飞行,践踏\n每当忌话图对牌手造成战斗伤害时,你可以将目标古咒牌从你的坟墓场移回你手上。 @@ -12450,6 +12508,7 @@ Tragic Arrogance|偏执致悲|法术|对每位牌手而言,你从由该牌手 Tragic Lesson|悲痛教训|瞬间|抓两张牌。然后除非你将一个由你操控的地移回其拥有者手上,否则弃一张牌。 Tragic Poet|悲剧诗人|生物 ~人类|{T},牺牲悲剧诗人:将目标结界牌从你的坟墓场移回你手上。 Tragic Slip|悲剧失足|瞬间|目标生物得-1/-1直到回合结束。\n丧心~如果本回合有生物死去,则改为该生物得-13/-13直到回合结束。 +Trail of Crumbs|碎屑路径|结界|当碎屑路径进战场时,派出一个食品衍生物。\n每当你牺牲一个食品时,你可以支付{1}。若你如此作,则检视你牌库顶的两张牌。你可以展示其中的一张永久物牌,并将它置于你手上。将其余的牌以任意顺序置于你牌库底。 Trail of Evidence|证据线索|结界|每当你施放瞬间或法术咒语时,探查。(将一个无色线索衍生神器放进战场,且其具有「{2},牺牲此神器:抓一张牌。」) Trail of Mystery|神秘踪迹|结界|每当一个牌面朝下的生物在你的操控下进战场时,你可以从你牌库中搜寻一张基本地牌,展示该牌,将它置于你手上,然后将你的牌库洗牌。\n每当一个由你操控的永久物翻回正面时,若其是生物,则它得+2/+2直到回合结束。 Trailblazer's Boots|开拓者旅靴|神器~武具|佩带此武具的生物具有非基本地行者异能。 (只要防御牌手操控非基本地,它便不能被阻挡。)\n佩带{2} @@ -12590,6 +12649,7 @@ Trusty Machete|可靠的砍刀|神器~武具|佩带此武具的生物得+2/+1 Trusty Packbeast|可靠驮兽|生物 ~野兽|当可靠驮兽进战场时,将目标神器牌从你的坟墓场移回你手上。 Truth or Tale|虚实难解|瞬间|展示你牌库顶的五张牌,并分成两堆。 由任一对手选择其中一堆。 将该堆中的一张牌置于你手上,然后将以此法展示的其它牌以任意顺序置于你的牌库底。 Trygon Predator|掠食飞鳐|生物~野兽|飞行\n每当掠食飞鳐对任一牌手造成战斗伤害时,你可以消灭目标由该牌手操控的神器或结界。 +Tuinvale Treefolk|图音谷树妖|生物 ~树妖/德鲁伊| Tukatongue Thallid|吐卡散绿菌|生物~真菌|当吐卡散绿菌从场上置入坟墓场时,将一个1/1绿色腐生物衍生物放置进场。 Tuktuk Grunts|图图大兵|生物~鬼怪/战士/伙伴|敏捷\n每当图图大兵或另一个伙伴在你的操控下进战场时,你可以在图图大兵上放置一个+1/+1指示物。 Tuktuk Scrapper|图图拆解手|生物~鬼怪/神器师/伙伴|每当图图拆解手或另一个伙伴在你的操控下进战场时,你可以消灭目标神器。 如果该神器依此法置入坟墓场,则图图拆解手对该神器的操控者造成伤害,其数量等同于由你操控的伙伴数量。 @@ -13440,6 +13500,7 @@ Weird Harvest|奇异收成|法术|每位牌手可以各从其牌库中搜寻至 Weirded Vampire|怪奇吸血鬼|生物~吸血鬼/惊惧兽|疯魔{2}{B}(如果你弃掉此牌,将之弃到放逐区。当你如此作时,支付其疯魔费用施放之,否则便将其置入你的坟墓场。) Weirding Shaman|奥秘祭师|生物~精灵/祭师|{3}{B},牺牲一个精灵:将两个1/1黑色的精灵/浪客衍生物放置进场。 Weirding Wood|怪诞树木|结界~灵气|结附于地\n当怪诞树木进战场时,探查。(将一个无色线索衍生神器放进战场,且其具有「{2},牺牲此神器:抓一张牌。」)\n所结附的地具有「{T}:加两点任意颜色的单色法术力到你的法术力池中。」 +Welcome Home|欢迎回家|法术~历险|派出三个2/2绿色的熊衍生生物。(然后放逐此牌。之后你还可以从放逐区中施放该生物。) Welcome to the Fold|受拥入教|法术|疯魔{X}{U}{U}(如果你弃掉此牌,将之弃到放逐区。当你如此作时,支付其疯魔费用施放之,否则便将其置入你的坟墓场。)\n如果目标生物的防御力等于或小于2,则获得该生物的操控权。如果曾支付受拥入教的疯魔费用,则改为如果该生物的防御力等于或小于X,则获得其操控权。 Welder Automaton|焊熔机械兽|神器生物~组构体|{3}{R}:焊熔机械兽向每位对手各造成1点伤害。 Weldfast Engineer|焊锢区工程师|生物~人类/神器师|在你回合的战斗开始时,目标由你操控的神器生物得+2/+0直到回合结束。 @@ -13500,6 +13561,7 @@ Whitesun's Passage|白阳仪式|瞬间|你获得5点生命。 Whitewater Naiads|湍流水灵|结界生物~宁芙|星彩~每当湍流水灵或另一个结界在你的操控下进战场时,目标生物本回合不能被阻挡。 Wicked Akuba|恶姥|生物~精怪|{B}:目标于本回合中曾受到恶姥伤害的牌手失去1点生命。 Wicked Guardian|邪恶守护者|生物 ~人类/贵族|当邪恶守护者进战场时,你可以令它对另一个由你操控的生物造成2点伤害。若你如此作,则抓一张牌。 +Wicked Wolf|恶狼|生物 ~狼|当恶狼进战场时,它与至多一个目标不由你操控的生物互斗。\n牺牲一个食品:在恶狼上放置一个+1/+1指示物。它获得不灭异能直到回合结束。将之横置。 Wicker Warcrawler|柳条战草人|神器生物~稻草人|每当柳条战草人攻击或阻挡,在战斗结束时于其上放置一个-1/-1指示物。 Wicker Witch|柳条巫婆|神器生物~稻草人| Wickerbough Elder|柳饰长老|生物~树妖/祭师|柳饰长老进场时上面有一个-1/-1指示物。\n{G},从柳饰长老上移去一个-1/-1指示物:消灭目标神器或结界。 @@ -13526,6 +13588,7 @@ Wild Swing|猛力挥击|法术|选择三个目标非结界的永久物。 随机 Wild Wanderer|荒野漫游人|生物~妖精/德鲁伊|当荒野漫游人进战场时,你可以从你的牌库中搜寻一张基本地牌,将之横置放进战场,然后将你的牌库洗牌。 Wild-Field Scarecrow|荒野稻草人|神器生物~稻草人|守军\n{2},牺牲荒野稻草人:从你的牌库中搜寻至多两张基本地牌,展示这些牌,并将它们置于你手上。然后将你的牌库洗牌。 Wildblood Pack|野血狼群|生物~ - 狼人|践踏\n由你操控且进行攻击的生物得+3/+0。\n在每个维持开始时,如果某牌手上回合施放了两个或更多咒语,转化野血狼群。 +Wildborn Preserver|幻境保卫者|生物 ~妖精/弓箭手|闪现\n延势\n每当另一个非人类生物在你的操控下进战场时,你可以支付{X}。当你如此作时,在幻境保卫者上放置X个+1/+1指示物。 Wildcall|荒野呼唤|法术|显化你的牌库顶牌,然后在其上放置X个+1/+1指示物。(显化某张牌的流程是,将该牌面朝下地放进战场,当成2/2生物。如果该牌是生物牌,则可随时支付其法术力费用使其翻回正面。) Wilderness Elemental|野性元素|生物~元素|践踏\n野性元素的力量等同于由所有对手操控的非基本地数量。 Wilderness Hypnotist|荒野催眠师|生物~人鱼/法术师|{T}:目标红色或绿色生物得-2/-0直到回合结束。 @@ -13543,6 +13606,7 @@ Wildsize|加大尺寸|瞬间|目标生物得+2/+2且获得践踏异能直到回 Wildslayer Elves|伏蛮地精|生物~地精/战士|干枯 (此来源会以-1/-1指示物的方式对生物造成伤害。) Wildwood Geist|野林游魂|生物~精怪|只要是在你的回合中,野林游魂便得+2/+2。 Wildwood Rebirth|野林再生|瞬间|将目标生物牌从你的坟墓场移回你手上。 +Wildwood Tracker|幻野林侦猎手|生物 ~妖精/战士|每当幻野林侦猎手进行攻击或阻挡时,若你操控另一个非人类生物,则幻野林侦猎手得+1/+1直到回合结束。 Will Kenrith|威尔肯理斯|传奇鹏洛客 ~威尔|+2:选择至多两个目标生物。直到你的下一个回合,这些生物的基础力量和防御力为0/3,且失去所有异能。\n−2:目标牌手抓两张牌。直到你的下一个回合,由该牌手施放的瞬间、法术和鹏洛客咒语减少{2}来施放。\n−8:目标牌手获得具有「每当你施放瞬间或法术咒语时,将其复制。你可以为该复制品选择新的目标」的徽记。\n与萝婉肯理斯拍档\n威尔肯理斯可用作指挥官。 Will of the Naga|那伽的意志|瞬间|掘穴(你于施放此咒语时每从你坟墓场中放逐一张牌,就能为此咒语支付{1}。)\n横置至多两个目标生物。这些生物于其操控者的下一个重置步骤中不能重置。 Will-Forged Golem|凝志魔像|神器生物~魔像|召集(此咒语能用你的生物来协助施放。你于施放此咒语时每横置一个生物,就能为此咒语支付{1}或一点该生物颜色之法术力。) @@ -13643,6 +13707,7 @@ Wojek Halberdiers|沃耶克戟队|生物~人类/士兵|协战~每当沃耶 Wojek Siren|沃耶克警笛|瞬间|辉耀~目标生物和每个与该生物有共通颜色的其它生物得+1/+1直到回合结束。 Wolf Pack|Wolf Pack|| Wolf of Devil's Breach|魔鬼裂口焰狼|生物~元素/狼|每当魔鬼裂口焰狼攻击时,你可以支付{1}{R}并弃一张牌。若你如此作,则魔鬼裂口焰狼对目标生物或鹏洛客造成伤害,其数量等同于所弃之牌的总法术力费用。 +Wolf's Quarry|野狼行猎|法术|派出三个1/1绿色野猪衍生生物,它们具有「当此生物死去时,派出一个食品衍生物。」(食品衍生物是具有「{2},{T},牺牲此神器:你获得3点生命」的神器。) Wolf-Skull Shaman|狼颅祭师|生物~地精/祭师|血族~在你的维持开始时,你可以检视你的牌库顶牌。 如果它与狼颅祭师有共通之生物类别,你可以展示该牌。 若你如此作,将一个2/2绿色狼衍生物放置进场。 Wolfbitten Captive|狼吻囚人|生物~人类/狼人|{1}{G}:狼吻囚人得+2/+2直到回合结束。此异能每回合中只能起动一次。在每个维持开始时,若上回合没有任一咒语施放过,转化狼吻囚人。 Wolfbriar Elemental|狼荆元素|生物~元素|多重增幅{G} (你施放此咒语时可以任意次数地额外支付{G}。)\n当狼荆元素进战场时,它每增幅过一次,就将一个2/2绿色的狼衍生物放置进场。 @@ -13782,6 +13847,7 @@ Yoked Ox|负轭牛|生物 ~牛| Yoked Plowbeast|负轭犁兽|生物~野兽|循环{2} ({2},弃掉此牌:抓一张牌。) Yomiji, Who Bars the Way|奈落无路黄泉示|传奇生物~精怪|每当一个不是奈落无路黄泉示的传奇永久物从场上进入坟墓场时,将该牌移回其拥有者手上。 Yore-Tiller Nephilim|唤往巨神灵|生物~巨神灵|每当唤往巨神灵进行攻击时,将目标生物牌从你的坟墓场横置进场,且正进行攻击。 +Yorvo, Lord of Garenbrig|盖伦碧王约沃|传奇生物 ~巨人/贵族|盖伦碧王约沃进战场时上面有四个+1/+1指示物。\n每当另一个绿色生物在你的操控下进战场时,在约沃上放置一个+1/+1指示物。然后如果前者的力量大于约沃的力量,则在约沃上放置另一个+1/+1指示物。 Yosei, the Morning Star|辉龙阳星|传奇生物~龙/精怪|飞行\n当辉龙阳星从场上进入坟墓场时,目标牌手略过他的下一个重置步骤。横置至多五个目标由该牌手操控的永久物。 Yotian Soldier|佑天神将|神器生物 ~士兵|警戒 Young Pyromancer|年轻烈焰术士|生物~人类/祭师|每当你施放瞬间或法术咒语时,将一个1/1红色元素衍生生物放进战场。 diff --git a/forge-gui/res/languages/de-DE.properties b/forge-gui/res/languages/de-DE.properties index 6efc55d23f1..a5a5fc38efd 100644 --- a/forge-gui/res/languages/de-DE.properties +++ b/forge-gui/res/languages/de-DE.properties @@ -41,7 +41,7 @@ txerrFailedtodeletelayoutfile=Fehler beim Löschen der Layout-Datei. #VSubmenuPreferences.java Preferences=Einstellungen btnReset=Alles zurücksetzen -btnDeleteMatchUI=SpielfeldLayout zurücksetzen +btnDeleteMatchUI=Spielfeld-Layout zurücksetzen btnDeleteEditorUI=Editor-Layout zurücksetzen btnDeleteWorkshopUI=Workshop-Layout zurücksetzen btnUserProfileUI=Öffne Benutzer-Verzeichnis @@ -179,8 +179,8 @@ KeyboardShortcuts=Tastenkombinationen lblAchievements=Errungenschaften # VSubmenuDownloaders.java btnDownloadSetPics=Bilder(LQ) Sets herunterladen -btnDownloadPics=Bilder(LQ) Karten herunterladen btnDownloadPicsHQ=Bilder(HQ) Karten herunterladen (Sehr langsam!) +btnDownloadPics=Bilder(LQ) Karten herunterladen btnDownloadQuestImages=Bilder für Quests herunterladen btnDownloadAchievementImages=Bilder für Erfolge herunterladen btnReportBug=Einen Fehler melden @@ -548,6 +548,7 @@ lblPreconstructedDecks=Vorkonstruiertes Deck lblQuestOpponentDecks=Quest-Gegner-Deck lblRandomColorDecks=Decks - zufällige Farben lblRandomStandardArchetypeDecks=Decks - zufälliger Standard-Archetyp +lblRandomPioneerArchetypeDecks=Decks - zufälliger Pioneer-Archetyp lblRandomModernArchetypeDecks=Decks - zufälliger Modern-Archetyp lblRandomLegacyArchetypeDecks=Decks - zufälliger Legacy-Archetyp lblRandomVintageArchetypeDecks=Decks - zufälliger Vintage-Archetyp @@ -628,7 +629,7 @@ titleUnlocked=%n freigeschaltet! lblStartADuel=Starte eine Duell. lblSelectAQuestDeck=Wähle ein Quest-Deck lblInvalidDeck=Unzulässiges Deck -lblInvalidDeckDesc=Dein Deck %n. Bitte ändern oder anderes Deck wählen. +lblInvalidDeckDesc=Dein Deck %n\nBitte ändern oder anderes Deck wählen. #VSubmenuQuestPrefs.java lblQuestPreferences=Quest-Einstellungen lblRewardsError=Fehler bei Belohnungen @@ -756,6 +757,7 @@ lblcopiesof=Kopien von #ItemListView.java lblUniqueCardsOnly=Nur eine Version ttUniqueCardsOnly=Schaltet zwischen der Anzeige der neuesten oder aller Versionen einer Karte um. +lblListView=Listanzeige #ACEditorBase.java lblAddcard=Karten hinzufügen ttAddcard=Fügt gewählte Karte dem Deck hinzu (oder Doppelklick oder Leertaste drücken) @@ -788,6 +790,9 @@ lblCollapseallgroups=Minimiere alle Gruppen lblGroupby=Gruppiere nach lblPileby=Stapel nach lblColumns=Spalten +lblPiles=Stapel +lblGroups=Gruppen: +lblImageView=Bildanzeige #CEditorVariant.java, CEditorConstructed.java lblCatalog=Katalog lblAdd=Hinzufügen @@ -950,6 +955,12 @@ nlShowMatchBackground=Zeige Bilder im Spielfeldhintergrund. nlTheme=Wähle ein Thema um die Bildschirmanzeigen anzupassen. nlVibrateAfterLongPress=Aktiviert Vibration bei langen Druck, z.B. beim Zoomen. nlVibrateWhenLosingLife=Aktiviert Vibration bei Lebenspunktverlust. +lblEnableRoundBorder=Aktiviere Maske mit runden Ränder +nlEnableRoundBorder=Wenn aktiviert, werden Kartenecken abgerundet. Vorzugsweise bei Karten mit vollem Rand. +lblPreloadExtendedArtCards=Erw. Kartenbilder bei Start laden +nlPreloadExtendedArtCards=Wenn aktiviert, werden erweiterte Kartenbilder bereits beim Start in den Speicher geladen. +lblShowFPSDisplay=FPS-Anzeige +nlShowFPSDisplay=Aktiviert die Frames-per-second-Anzeige (Experimentell). #MatchScreen.java lblPlayers=Spieler lblLog=Bericht @@ -980,12 +991,13 @@ lblToMainDeck=zum Haupt-Deck lblHowMany=wie viel? lblInventory=Inhaltsverzeichnis lblCollection=Sammlung -lblCommanders=Komandeure +lblCommanders=Generäle lblOathbreakers=Eidbrecher #Forge.java lblLoadingFonts=Lade Schriftarten... lblLoadingCardTranslations=Lade Karten-Übersetzungen... lblFinishingStartup=Letzte Vorbereitungen... +lblPreloadExtendedArt=Lade erweiterte Bilder... #LobbyScreen.java lblMore=Mehr... lblLoadingNewGame=Lade neues Spiel... @@ -1088,7 +1100,7 @@ lblStormCount=Sturmzähler #PlayerControllerHuman.java lblYouHaveWonTheCoinToss=%s, du hast den Münzwurf gewonnen. lblYouLostTheLastGame=%s, du hast das letzte Spiel verloren. -lblWouldYouLiketoPlayorDraw=Willst du lieber zuerst spielen oder ziehen. +lblWouldYouLiketoPlayorDraw=Willst du lieber zuerst spielen oder ziehen? lblWhoWouldYouLiketoStartthisGame=Wer soll das Spiel beginnen? (Klicke auf das Portrait.) lblPlay=Spielen lblDraw=Ziehen @@ -1140,6 +1152,28 @@ lblArrangeCardsToBePutOnTopOfYourLibrary=Ordne Karten, welche unter die Biblioth lblTopOfLibrary=Oben auf Bibliothek lblSelectCardsToBePutIntoTheGraveyard=Wähle Karten, welche auf den Friedhof gelegt werden sollen lblCardsToPutInTheGraveyard=Karten, welche auf den Friedhof gelegt werden sollen +lblDiscardUpToNCards=Werfe bis zu %d Karte(n) ab +lblDiscardNCards=Werfe %d Karte(n) ab +lblSelectNCardsToDiscardUnlessDiscarduType=Wähle bis zu %d Karte(n) zum abwerfen, außer du wirfst eine %s ab. +lblCleanupPhase=Aufräumphase +lblSelectCardsToDiscardHandDownMaximum=Werfe %d Karte(n) ab um dein Handmaximum von %max Karte(n) zu erfüllen. +lblChooseMinCardToDiscard=Wähle %d Karte(n) zm Abwerfen +lblDiscarded=Abgeworfen +lblChooseDamageOrderFor=Wähle Schadensreihenfolge für %s +lblDamagedFirst=Zuerst geschädigt +lblChooseBlockerAfterWhichToPlaceAttackert=Wähle Blocker für Platz %s in der Schadensreihenfolge; Abbrechen für ersten Platz +lblPutCardOnTopOrBottomLibrary=Lege %s auf oder unter deine Bibliothek? +lblChooseOrderCardsPutIntoLibrary=Wähle die Reihenfolge der Karten, in der sie in die Bibliothek gelegt werden +lblClosestToTop=Zuoberst +lblChooseOrderCardsPutOntoBattlefield=Wähle die Reihenfolge der Karten, in der sie auf das Spielfeld gebracht werden +lblPutFirst=Lege zuerst +lblChooseOrderCardsPutIntoGraveyard=Wähle die Reihenfolge der Karten, in der sie in den Friedhof gelegt werden +lblClosestToBottom=Zuunterst +lblChooseOrderCardsPutIntoPlanarDeck=Wähle die Reihenfolge der Karten, in der sie in das Weltendeck gelegt werden +lblChooseOrderCardsPutIntoSchemeDeck=Wähle die Reihenfolge der Karten, in der sie in den Verschwörungsdeck gelegt werden +lblChooseOrderCopiesCast=Wähle die Reihenfolge für die Kopien +lblDelveHowManyCards=Wühlen - Wie viele Karten? +lblExileWhichCard=Schicke welche Karte ins Exil? #AbstractGuiGame.java lblConcedeCurrentGame=Das Spiel wird als verloren gewertet.\n\nTrotzdem aufgeben? lblConcedeTitle=Spiel verloren geben? @@ -1171,4 +1205,182 @@ btnQuitMatch=Beende Partie lblItsADraw=Es ist ein Unentschieden! lblTeamWon=Team %s hat gewonnen! lblWinnerWon=%s hat gewonnen! -lblGameLog=Spiel-Aufzeichnung +lblGameLog=Spiel-Bericht +#NewDraftScreen.java +lblLoadingNewDraft=Lade neuen Draft... +#LoadDraftScreen.java +lblDoubleTapToEditDeck=Doppelklick zum Bearbeiten. Lange drücken für Anzeige. +lblMode=Modus: +lblYouMustSelectExistingDeck=Du mußt eine bestehendes Deck wählen oder ein neues Draft-Deck erstellen. +lblWhichOpponentWouldYouLikeToFace=Wähle deinen Gegner! +lblSingleMatch=Einzelnes Spiel +#NewGauntletScreen.java +lblGauntletText1=Beim Spießrutenlauf wählst du ein Deck und tritts gegen mehrer Gegner an. +lblGauntletText2=Wähle die Anzahl der Gegener und welche Art Deck sie spielen sollen. +lblGauntletText3=Dann versuche alle Gegner zu besiegen auche ein Spiel zu verlieren. +lblSelectGauntletType=Wähle die Art des Spießrutenlaufs +lblCustomGauntlet=angepaßter Spießrutenlauf +lblGauntletContest=Wettbewerb +lblSelectYourDeck=Wähle dein Deck +lblSelectDeckForOpponent=Wähle Deck für Gegner +lblSelectGauntletContest=Wähle Wettbewerb +#PuzzleScreen.java +lblPuzzleText1=Der puzzle-Modus lädt ein Puzzle, welches du auf eine bestimmte Art zu gewinnen hast. +lblPuzzleText2=Drücke Start und wähle ein Puzzle aus der Liste. +lblPuzzleText3=Zu Beginn wird dir in einem Fenster dein Ziel erklärt, und auch eventuelle spezielle Karten in deiner Kommandozone. +lblChooseAPuzzle=Wähle ein Puzzle +lblLoadingThePuzzle=Lade das Puzzle... +#InputPassPriority.java +lblCastSpell=Einen Zauberspruch sprechen +lblPlayLand=Spiele ein Land +lblActivateAbility=Aktiviere Fähigkeit +lblYouHaveManaFloatingInYourManaPoolCouldBeLostIfPassPriority=Du hast noch unverbrauchtes Mana, welches verloren geht, wenn du die Priorität abgibst. +lblYouWillTakeManaBurnDamageEqualAmountFloatingManaLostThisWay=Du wirst Manabrand erleiden, in Höhe des verlorenen Manas. +lblManaFloating=Unverbrauchtes Mana +#InputPayManaOfCostPayment.java +lblPayManaCost=Zahle die Spruchkosten: +lblLifePaidForPhyrexianMana=(%d Leben wurde bezahlt für phyrexianisches Mana) +lblClickOnYourLifeTotalToPayLifeForPhyrexianMana=Klicke auf deine Lebenspunkte um phyrexianisches Mana zu bezahlen. +lblClickOnYourLifeTotalToPayLifeForBlackMana=Klicke auf deine Lebenspunkte um schwarzes Mana zu bezahlen. +lblClickOnYourLifeTotalToPayLifeForPhyrexianOrBlackMana=Klicke auf deine Lebenspunkte um phyrexianisches oder schwarzes Mana zu bezahlen. +lblPuzzleText1=Der Puzzle-Modus lädt ein Puzzle, das du in einer vorgegebenen Zeit/Weise gewinnen musst. +lblPuzzleText2=Um zu beginnen, drücke zunächst die Start-Taste und wähle dann ein Puzzle aus einer Liste aus. +lblPuzzleText3=Dein Ziel wird beim Start des Puzzles in einem Popup-Fenster angezeigt und auf einer Spezialeffektkarte angegeben, die sich in deiner Befehlszone befindet. +lblChooseAPuzzle=Wähle ein Puzzle +lblLoadingThePuzzle=Lade das Puzzle... +#GameLogFormatter.java +lblLogScryTopBottomLibrary=Hellsicht: %s legte %top Karte(n) auf und %bottom Karte(n) unter die Bibliothek +lblLogScryTopLibrary=Hellsicht: %s legte %top Karte(n) auf die Bibliothek +lblLogScryBottomLibrary=Hellsicht: %s legte %bottom Karte(n) unter die Bibliothek +lblPlayerHasMulliganedDownToNCards=%s nutze Mulligan und hat nun %d Karten. +lblPlayerDidntAttackThisTurn=% griff diesen Zug nicht an. +#FormatFilter.java +lblAllSetsFormats=Alle Sets/Formate +lblOtherFormats=Andere Formate... +lblChooseSets=Wähle Sets... +#HistoricFormatSelect.java +lblChooseFormat=Wähle Format +#TriggerAdapt.java +lblAdapt=Adaptieren +#TriggerAttached.java +lblAttachee=Anhang +#TriggerAttackerBlocked.java +lblNumberBlockers=Anzahl Blocker +lblBlocker=Blocker +#TriggerAttackersDeclared.java +lblNumberAttackers=Anzahl Angreifer +#TriggerAttackerUnblockedOnce.java +lblAttackingPlayer=Angreifender Spieler +lblDefenders=Verteidiger +#TriggerBecomeMonarch.java +lblPlayer=Spieler +#TriggerBecomeMonstrous.java +lblMonstrous=Monströs +#TriggerBecomeRenowned.java +lblRenowned=Ruhm +#TriggerBecomesTarget.java +lblSource=Quelle +lblTarget=Ziel +#TriggerBecomesTargetOnce.java +lblTargets=Ziele +#TriggerBlockersDeclared.java +lblBlockers=Blocker +#TriggerChampioned.java +lblChampioned=Unterstützt +#TriggerChangesController.java +lblChangedController=Kontrolle geändert +#TriggerChangesZone.java +lblZoneChanger=Zone geändert +#TriggerChangesZoneAll.java +lblAmount=Anzahl +#TriggerCounterAdded.java +lblAddedOnce=Einmalig hinzugefügt +#TriggerCountered.java +lblCountered=Abgewehrt +lblCause=Grund +#TriggerCounteredRemoved.java +lblRemovedFrom=Entfernt von +#TriggerCrewed.java +lblVehicle=Fahrzeug +lblCrew=Besatzung +#TriggerCycled.java +lblCycled=Ausgetauscht +#TriggerDamageDealtOnce.java +lblDamageSource=Schadensquelle +lblDamaged=Geschädigt +#TriggerDamagePrevented.java +lblDamageTarget=Schadensziel +#TriggerDestroyed.java +lblDestroyed=Zerstört +lblDestroyer=Zerstörer +#TriggerDevoured.java +lblDevoured=Verschlungen +#TriggerDiscarded.java +lblDiscarded=Abgeworfen +#TriggerEvolved.java +lblEvolved=Weiterentwickelt +#TriggerExerted.java +lblExerted=Erschöpft +#TriggerExiled.java +lblExiled=im Exil +#TriggerExploited.java +lblExploited=Ausgeschlachtet +lblExploiter=Ausschlachtender +#TriggerExplores.java +lblExplorer=Erforscher +#TriggerFight.java +lblFighter=Kämpfer +#TriggerLandPlayed.java +lblLandPlayed=Land gespielt +#TriggerLifeGained.java +lblGainedAmount=Anzahl bekommen +#TriggerLifeLost.java +lblLostAmount=Anzahl verloren +#TriggerPayCumulativeUpkeep.java +lblMana=Mana +#TriggerPayLife.java +lblPaidAmount=Anzahl bezahlt +#TriggerPhaseIn.java +lblPhasedIn=Stabilisiert +#TriggerPhaseOut.java +lblPhasedOut=Destabilisiert +#TriggerRoller.java +lblRoller=Würfler +#TriggerPlaneswalkedFrom.java +lblPlaneswalkedFrom=Weltengewandert von +#TriggerPlaneswalkedTo.java +lblPlaneswalkedTo=Weltengewandert nach +#TriggerRegenerated.java +lblRegenerated=Regeneriert +#TriggerRevealed.java +lblRevealed=Enthüllt +#TriggerSacrificed.java +lblSacrificed=Geopfert +#TriggerScry.java +lblScryer=Hellsicht angewendet +#TriggerSearchLibrary.java +lblSearcher=hat gesucht +#TriggerShuffled.java +lblShuffler=hat gemischt +#TriggerSpellAbilityCast.java +lblActivator=hat aktiviert +#TriggerSpellAbilityCast.java +lblSpellAbility=Spruch-Fähigkeit +#TriggerTaps.java +lblTapped=Getappt +#TriggerTapsForMana.java +lblTappedForMana=für Mana getappt +lblProduced=Erzeugte +#TriggerTransformed.java +lblTransformed=Transformiert +#TriggerTurnFaceUp.java +lblTurnFaceUp=Aufgedeckt +#TriggerUnattach.java +lblObject=Objekt +lblAttachment=Anhang +#TriggerUntaps.java +lblUntapped=nicht getappt +#TriggerVote.java +lblVoters=Abstimmende +#PermanentCreatureEffect.java +lblCreature=Kreatur diff --git a/forge-gui/res/languages/en-US.properties b/forge-gui/res/languages/en-US.properties index f5754b44fed..d73de04d1ed 100644 --- a/forge-gui/res/languages/en-US.properties +++ b/forge-gui/res/languages/en-US.properties @@ -548,6 +548,7 @@ lblPreconstructedDecks=Preconstructed Decks lblQuestOpponentDecks=Quest Opponent Decks lblRandomColorDecks=Random Color Decks lblRandomStandardArchetypeDecks=Random Standard Archetype Decks +lblRandomPioneerArchetypeDecks=Random Pioneer Archetype Decks lblRandomModernArchetypeDecks=Random Modern Archetype Decks lblRandomLegacyArchetypeDecks=Random Legacy Archetype Decks lblRandomVintageArchetypeDecks=Random Vintage Archetype Decks @@ -628,7 +629,7 @@ titleUnlocked=%n unlocked! lblStartADuel=Start a duel. lblSelectAQuestDeck=Please select a Quest Deck. lblInvalidDeck=Invalid Deck -lblInvalidDeckDesc=Your deck %n Please edit or choose a different deck. +lblInvalidDeckDesc=Your deck %n\nPlease edit or choose a different deck. #VSubmenuQuestPrefs.java lblQuestPreferences=Quest Preferences lblRewardsError=Rewards Error @@ -756,6 +757,7 @@ lblcopiesof=copies of #ItemListView.java lblUniqueCardsOnly=Unique Cards Only ttUniqueCardsOnly=Toggle whether to show unique cards only +lblListView=List View #ACEditorBase.java lblAddcard=Add card ttAddcard=Add selected card to current deck (or double click the row or hit the spacebar) @@ -788,6 +790,9 @@ lblCollapseallgroups=Collapse all groups lblGroupby=group by lblPileby=pile by lblColumns=Columns +lblPiles=Piles: +lblGroups=Groups: +lblImageView=Image View #CEditorVariant.java, CEditorConstructed.java lblCatalog=Catalog lblAdd=Add @@ -950,6 +955,12 @@ nlShowMatchBackground=Show match background image on battlefield, otherwise back nlTheme=Sets the theme that determines how display components are skinned. nlVibrateAfterLongPress=Enable quick vibration to signify a long press, such as for card zooming. nlVibrateWhenLosingLife=Enable vibration when your player loses life or takes damage during a game. +lblEnableRoundBorder=Enable Round Border Mask +nlEnableRoundBorder=When enabled, the card corners are rounded (Preferably Card with Full Borders). +lblPreloadExtendedArtCards=Preload Extended Art Cards +nlPreloadExtendedArtCards=When enabled, Preloads Extended Art Cards to Cache on Startup. +lblShowFPSDisplay=Show FPS Display +nlShowFPSDisplay=When enabled, show the FPS Display (Experimental). #MatchScreen.java lblPlayers=Players lblLog=Log @@ -986,6 +997,7 @@ lblOathbreakers=Oathbreakers lblLoadingFonts=Loading fonts... lblLoadingCardTranslations=Loading card translations... lblFinishingStartup=Finishing startup... +lblPreloadExtendedArt=Preload Extended Art... #LobbyScreen.java lblMore=More... lblLoadingNewGame=Loading new game... @@ -1140,6 +1152,28 @@ lblArrangeCardsToBePutOnTopOfYourLibrary=Arrange cards to be put on top of your lblTopOfLibrary=Top of Library lblSelectCardsToBePutIntoTheGraveyard=Select cards to be put into the graveyard lblCardsToPutInTheGraveyard=Cards to put in the graveyard +lblDiscardUpToNCards=Discard up to %d card(s) +lblDiscardNCards=Discard %d card(s) +lblSelectNCardsToDiscardUnlessDiscarduType=Select %d card(s) to discard, unless you discard a %s. +lblCleanupPhase=Cleanup Phase +lblSelectCardsToDiscardHandDownMaximum=Select %d card(s) to discard to bring your hand down to the maximum of %max cards. +lblChooseMinCardToDiscard=Choose %d card(s) to discard +lblDiscarded=Discarded +lblChooseDamageOrderFor=Choose Damage Order for %s +lblDamagedFirst=Damaged First +lblChooseBlockerAfterWhichToPlaceAttackert=Choose blocker after which to place %s in damage order; cancel to place it first +lblPutCardOnTopOrBottomLibrary=Put %s on the top or bottom of your library? +lblChooseOrderCardsPutIntoLibrary=Choose order of cards to put into the library +lblClosestToTop=Closest to top +lblChooseOrderCardsPutOntoBattlefield=Choose order of cards to put onto the battlefield +lblPutFirst=Put first +lblChooseOrderCardsPutIntoGraveyard=Choose order of cards to put into the graveyard +lblClosestToBottom=Closest to bottom +lblChooseOrderCardsPutIntoPlanarDeck=Choose order of cards to put into the planar deck +lblChooseOrderCardsPutIntoSchemeDeck=Choose order of cards to put into the scheme deck +lblChooseOrderCopiesCast=Choose order of copies to cast +lblDelveHowManyCards=Delve how many cards? +lblExileWhichCard=Exile which card? #AbstractGuiGame.java lblConcedeCurrentGame=This will concede the current game and you will lose.\n\nConcede anyway? lblConcedeTitle=Concede Game? @@ -1171,4 +1205,177 @@ btnQuitMatch=Quit Match lblItsADraw=It's a draw! lblTeamWon=Team %s won! lblWinnerWon=%s won! -lblGameLog=Game Log \ No newline at end of file +lblGameLog=Game Log +#NewDraftScreen.java +lblLoadingNewDraft=Loading new draft... +#LoadDraftScreen.java +lblDoubleTapToEditDeck=Double-tap to edit deck (Long-press to view) +lblMode=Mode: +lblYouMustSelectExistingDeck=You must select an existing deck or build a deck from a new booster draft game. +lblWhichOpponentWouldYouLikeToFace=Which opponent would you like to face? +lblSingleMatch=Single Match +#NewGauntletScreen.java +lblGauntletText1=In Gauntlet mode, you select a deck and play against multiple opponents. +lblGauntletText2=Configure how many opponents you wish to face and what decks or types of decks they will play. +lblGauntletText3=Then, try to beat all AI opponents without losing a match. +lblSelectGauntletType=Select a Gauntlet Type +lblCustomGauntlet=Custom Gauntlet +lblGauntletContest=Gauntlet Contest +lblSelectYourDeck=Select Your Deck +lblSelectDeckForOpponent=Select Deck for Opponent +lblSelectGauntletContest=Select Gauntlet Contest +#PuzzleScreen.java +lblPuzzleText1=Puzzle Mode loads in a puzzle that you have to win in a predetermined time/way. +lblPuzzleText2=To begin, press the Start button below, then select a puzzle from a list. +lblPuzzleText3=Your objective will be displayed in a pop-up window when the puzzle starts and also specified on a special effect card which will be placed in your command zone. +lblChooseAPuzzle=Choose a puzzle +lblLoadingThePuzzle=Loading the puzzle... +#InputPassPriority.java +lblCastSpell=cast spell +lblPlayLand=play land +lblActivateAbility=activate ability +lblYouHaveManaFloatingInYourManaPoolCouldBeLostIfPassPriority=You have mana floating in your mana pool that could be lost if you pass priority now. +lblYouWillTakeManaBurnDamageEqualAmountFloatingManaLostThisWay=You will take mana burn damage equal to the amount of floating mana lost this way. +lblManaFloating=Mana Floating +#InputPayManaOfCostPayment.java +lblPayManaCost=Pay Mana Cost: +lblLifePaidForPhyrexianMana=(%d life paid for phyrexian mana) +lblClickOnYourLifeTotalToPayLifeForPhyrexianMana=Click on your life total to pay life for phyrexian mana. +lblClickOnYourLifeTotalToPayLifeForBlackMana=Click on your life total to pay life for black mana. +lblClickOnYourLifeTotalToPayLifeForPhyrexianOrBlackMana=Click on your life total to pay life for phyrexian mana or black mana. +#GameLogFormatter.java +lblLogScryTopBottomLibrary=%s scried %top card(s) to the top of the library and %bottom card(s) to the bottom of the library +lblLogScryTopLibrary=%s scried %top card(s) to the top of the library +lblLogScryBottomLibrary=%s scried %bottom card(s) to the bottom of the library +lblPlayerHasMulliganedDownToNCards=%s has mulliganed down to %d cards. +lblPlayerDidntAttackThisTurn=%s didn't attack this turn. +#FormatFilter.java +lblAllSetsFormats=All Sets/Formats +lblOtherFormats=Other Formats... +lblChooseSets=Choose Sets... +#HistoricFormatSelect.java +lblChooseFormat=Choose Format +#TriggerAdapt.java +lblAdapt=Adapt +#TriggerAttached.java +lblAttachee=Attachee +#TriggerAttackerBlocked.java +lblNumberBlockers=Number Blockers +lblBlocker=Blocker +#TriggerAttackersDeclared.java +lblNumberAttackers=Number Attackers +#TriggerAttackerUnblockedOnce.java +lblAttackingPlayer=AttackingPlayer +lblDefenders=Defenders +#TriggerBecomeMonarch.java +lblPlayer=Player +#TriggerBecomeMonstrous.java +lblMonstrous=Monstrous +#TriggerBecomeRenowned.java +lblRenowned=Renowned +#TriggerBecomesTarget.java +lblSource=Source +lblTarget=Target +#TriggerBecomesTargetOnce.java +lblTargets=Targets +#TriggerBlockersDeclared.java +lblBlockers=Blockers +#TriggerChampioned.java +lblChampioned=Championed +#TriggerChangesController.java +lblChangedController=Changed Controller +#TriggerChangesZone.java +lblZoneChanger=Zone Changer +#TriggerChangesZoneAll.java +lblAmount=Amount +#TriggerCounterAdded.java +lblAddedOnce=Added once +#TriggerCountered.java +lblCountered=Countered +lblCause=Cause +#TriggerCounteredRemoved.java +lblRemovedFrom=Removed from +#TriggerCrewed.java +lblVehicle=Vehicle +lblCrew=Crew +#TriggerCycled.java +lblCycled=Cycled +#TriggerDamageDealtOnce.java +lblDamageSource=Damage Source +lblDamaged=Damaged +#TriggerDamagePrevented.java +lblDamageTarget=Damage Target +#TriggerDestroyed.java +lblDestroyed=Destroyed +lblDestroyer=Destroyer +#TriggerDevoured.java +lblDevoured=Devoured +#TriggerDiscarded.java +lblDiscarded=Discarded +#TriggerEvolved.java +lblEvolved=Evolved +#TriggerExerted.java +lblExerted=Exerted +#TriggerExiled.java +lblExiled=Exiled +#TriggerExploited.java +lblExploited=Exploited +lblExploiter=Exploiter +#TriggerExplores.java +lblExplorer=Explorer +#TriggerFight.java +lblFighter=Fighter +#TriggerLandPlayed.java +lblLandPlayed=Land played +#TriggerLifeGained.java +lblGainedAmount=Gained Amount +#TriggerLifeLost.java +lblLostAmount=Lost Amount +#TriggerPayCumulativeUpkeep.java +lblMana=Mana +#TriggerPayLife.java +lblPaidAmount=Paid Amount +#TriggerPhaseIn.java +lblPhasedIn=Phased In +#TriggerPhaseOut.java +lblPhasedOut=Phased Out +#TriggerRoller.java +lblRoller=Roller +#TriggerPlaneswalkedFrom.java +lblPlaneswalkedFrom=Planeswalked From +#TriggerPlaneswalkedTo.java +lblPlaneswalkedTo=Planeswalked To +#TriggerRegenerated.java +lblRegenerated=Regenerated +#TriggerRevealed.java +lblRevealed=Revealed +#TriggerSacrificed.java +lblSacrificed=Sacrificed +#TriggerScry.java +lblScryer=Scryer +#TriggerSearchLibrary.java +lblSearcher=Searcher +#TriggerShuffled.java +lblShuffler=Shuffler +#TriggerSpellAbilityCast.java +lblActivator=Activator +#TriggerSpellAbilityCast.java +lblSpellAbility=SpellAbility +#TriggerTaps.java +lblTapped=Tapped +#TriggerTapsForMana.java +lblTappedForMana=Tapped for Mana +lblProduced=Produced +#TriggerTransformed.java +lblTransformed=Transformed +#TriggerTurnFaceUp.java +lblTurnFaceUp=Turn Face up +#TriggerUnattach.java +lblObject=Object +lblAttachment=Attachment +#TriggerUntaps.java +lblUntapped=Untapped +#TriggerVote.java +lblVoters=Voters +#PermanentCreatureEffect.java +lblCreature=Creature \ No newline at end of file diff --git a/forge-gui/res/languages/es-ES.properties b/forge-gui/res/languages/es-ES.properties index 468a4ac6480..adb4a51aa64 100644 --- a/forge-gui/res/languages/es-ES.properties +++ b/forge-gui/res/languages/es-ES.properties @@ -548,6 +548,7 @@ lblPreconstructedDecks=Mazos Preconstruidos lblQuestOpponentDecks=Mazos de los Oponentes de la Aventura lblRandomColorDecks=Mazos Aleatorios por Color lblRandomStandardArchetypeDecks=Mazos Standard por Arquetipo +lblRandomPioneerArchetypeDecks=Random Pioneer Archetype Decks lblRandomModernArchetypeDecks=Mazos Modern por Arquetipo lblRandomLegacyArchetypeDecks=Mazos Legacy por Arquetipo lblRandomVintageArchetypeDecks=Mazos Vintage por Arquetipo @@ -628,7 +629,7 @@ titleUnlocked=%n desbloqueado! lblStartADuel=Comienza un duelo. lblSelectAQuestDeck=Por favor, seleccione un mazo de aventura. lblInvalidDeck=Mazo no válido -lblInvalidDeckDesc=Su mazo %n Por favor, edite o elija un mazo diferente. +lblInvalidDeckDesc=Su mazo %n\nPor favor, edite o elija un mazo diferente. #VSubmenuQuestPrefs.java lblQuestPreferences=Preferencias de la Aventura lblRewardsError=Error de recompensas @@ -756,6 +757,7 @@ lblcopiesof=copias de #ItemListView.java lblUniqueCardsOnly=Solo Cartas Únicas ttUniqueCardsOnly=Alternar para mostrar solo cartas únicas +lblListView=Vista de Lista #ACEditorBase.java lblAddcard=Añadir carta ttAddcard=Añade la carta seleccionada al mazo actual (o haz doble clic en la fila o presiona la barra espaciadora) @@ -788,6 +790,9 @@ lblCollapseallgroups=Contraer todos los grupos lblGroupby=agrupar por lblPileby=apilar por lblColumns=Columnas +lblPiles=Apilar: +lblGroups=Agrupar: +lblImageView=Vista de Imágenes #CEditorVariant.java, CEditorConstructed.java lblCatalog=Catálogo lblAdd=Añadir @@ -950,6 +955,12 @@ nlShowMatchBackground=Muestra la imagen de fondo de la partida en el campo de ba nlTheme=Establece el tema que determina el aspecto global del juego. nlVibrateAfterLongPress=Habilita la vibración rápida cuando se realice una pulsación prolongada, como p.ej. al realizar zoom de la carta. nlVibrateWhenLosingLife=Habilita la vibración cuando tu jugador pierde vida o sufre daños durante un juego. +lblEnableRoundBorder=Habilitar máscara de bordes redondeados +nlEnableRoundBorder=Cuando está habilitado, las esquinas de las cartas se redondean (Preferiblemente Cartas con bordes completos). +lblPreloadExtendedArtCards=Precargar Cartas de Arte Extendido +nlPreloadExtendedArtCards=Cuando está habilitado, carga previamente las cartas de arte ampliadas en la caché al iniciar el programa. +lblShowFPSDisplay=Mostrar FPS +nlShowFPSDisplay=Cuando está habilitado, muestra los FPS (Experimental). #MatchScreen.java lblPlayers=Jugadores lblLog=Log @@ -986,6 +997,7 @@ lblOathbreakers=Oathbreakers lblLoadingFonts=Cargando fuentes... lblLoadingCardTranslations=Cargando traducciones de cartas... lblFinishingStartup=Finalizando el arranque... +lblPreloadExtendedArt=Precargando Arte Extendido... #LobbyScreen.java lblMore=Más... lblLoadingNewGame=Cargando nueva partida... @@ -1140,6 +1152,28 @@ lblArrangeCardsToBePutOnTopOfYourLibrary=Organizar las cartas para colocarlas en lblTopOfLibrary=Parte Superior de la Biblioteca lblSelectCardsToBePutIntoTheGraveyard=Selecciona las cartas para ponerlas en el Cementerio lblCardsToPutInTheGraveyard=Cartas para poner en el Cementerio +lblDiscardUpToNCards=Descarta hasta %d carta(s) +lblDiscardNCards=Descarta %d carta(s) +lblSelectNCardsToDiscardUnlessDiscarduType=Selecciona %d carta(s) para descartar, a menos que descartes un %s. +lblCleanupPhase=Fase de Limpieza +lblSelectCardsToDiscardHandDownMaximum=Selecciona %d carta(s) a descartar para reducir tu mano al máximo de %max cartas. +lblChooseMinCardToDiscard=Elige %d carta(s) para descartar +lblDiscarded=Descartado +lblChooseDamageOrderFor=Selecciona el Orden de Daños para %s +lblDamagedFirst=Dañado Primero +lblChooseBlockerAfterWhichToPlaceAttackert=Elige un bloqueador después del cual colocar %s en el orden de daño; cancela para colocarlo primero. +lblPutCardOnTopOrBottomLibrary=¿Poner %s en la parte superior o inferior de tu biblioteca? +lblChooseOrderCardsPutIntoLibrary=Elige el orden de las cartas para poner en la biblioteca +lblClosestToTop=Más cerca de la parte superior +lblChooseOrderCardsPutOntoBattlefield=Elige el orden de las cartas que quieres poner en el campo de batalla +lblPutFirst=Poner en primer lugar +lblChooseOrderCardsPutIntoGraveyard=Elige el orden de las cartas para poner en el cementerio +lblClosestToBottom=Más cerca de la parte inferior +lblChooseOrderCardsPutIntoPlanarDeck=Elige el orden de las cartas que quieres poner en el mazo planar +lblChooseOrderCardsPutIntoSchemeDeck=Elige el orden de las cartas que quieres poner en el mazo scheme +lblChooseOrderCopiesCast=Elige el orden de las copias que se van a invocar +lblDelveHowManyCards=¿Excavar cuántas cartas? +lblExileWhichCard=¿Exiliar qué carta? #AbstractGuiGame.java lblConcedeCurrentGame=Esto concederá la partida actual y perderás.\n\n¿Conceder de todos modos? lblConcedeTitle=¿Conceder Partida? @@ -1171,4 +1205,177 @@ btnQuitMatch=Salir de la Partida lblItsADraw=¡Es un empate! lblTeamWon=¡El equipo %s ha ganado! lblWinnerWon=¡%s ha ganado! -lblGameLog=Registro del Juego \ No newline at end of file +lblGameLog=Registro del Juego +#NewDraftScreen.java +lblLoadingNewDraft=Cargando nuevo Draft... +#LoadDraftScreen.java +lblDoubleTapToEditDeck=Pulsa 2 veces para editar el mazo (Pulsación prologanda para ver) +lblMode=Modo: +lblYouMustSelectExistingDeck=Debes seleccionar un mazo existente o construir un mazo a partir de un nuevo juego de booster draft. +lblWhichOpponentWouldYouLikeToFace=¿A qué oponente te gustaría enfrentarte? +lblSingleMatch=Partida individual +#NewGauntletScreen.java +lblGauntletText1=En el modo Desafío, selecciona un mazo y juega contra varios oponentes. +lblGauntletText2=Configura a cuántos oponentes deseas enfrentarte y qué mazos o tipos de mazos jugarán. +lblGauntletText3=Luego, intenta derrotar a todos los oponentes de la IA sin perder una partida. +lblSelectGauntletType=Seleccione el Tipo de Desafío +lblCustomGauntlet=Desafío Personalizado +lblGauntletContest=Concurso de Desafío +lblSelectYourDeck=Seleccciona Tu Mazo +lblSelectDeckForOpponent=Seleccionar Mazo para el Oponente +lblSelectGauntletContest=Seleccionar Concurso de Desafío +#PuzzleScreen.java +lblPuzzleText1=En el Modo Puzzle se carga un rompecabezas que tienes que ganar en un tiempo/forma predeterminados. +lblPuzzleText2=Para comenzar, pulsa el botón Inicio y selecciona un puzzle de una lista. +lblPuzzleText3=Tu objetivo se mostrará en una ventana emergente cuando se inicie el puzzle y también se especificará en una carta de efectos especiales que se colocará en tu zona de comandos. +lblChooseAPuzzle=Elige un puzzle +lblLoadingThePuzzle=Cargando el puzzle... +#InputPassPriority.java +lblCastSpell=lanzar hechizo +lblPlayLand=jugar tierra +lblActivateAbility=activar abilidad +lblYouHaveManaFloatingInYourManaPoolCouldBeLostIfPassPriority=Tienes maná flotando en tu pool de maná que podría perderse si pasas la prioridad ahora. +lblYouWillTakeManaBurnDamageEqualAmountFloatingManaLostThisWay=Recibirás un daño por quemadura de maná igual a la cantidad de maná flotante perdido de esta manera. +lblManaFloating=Maná Flotante +#InputPayManaOfCostPayment.java +lblPayManaCost=Paga el coste de maná: +lblLifePaidForPhyrexianMana=(%d de vida pagado por el maná filaxiano) +lblClickOnYourLifeTotalToPayLifeForPhyrexianMana=Haga clic en el total de su vida para pagar la vida por el maná filaxiano. +lblClickOnYourLifeTotalToPayLifeForBlackMana=Haga clic en el total de su vida para pagar la vida de maná negro. +lblClickOnYourLifeTotalToPayLifeForPhyrexianOrBlackMana=Haga clic en el total de su vida para pagar la vida por maná filoxiano o maná negro. +#GameLogFormatter.java +lblLogScryTopBottomLibrary=%s adivinó %top carta(s) de la parte superior de la biblioteca y %bottom carta(s) de la parte inferior de la biblioteca +lblLogScryTopLibrary=%s adivinó %top carta(s) de la parte superior de la biblioteca +lblLogScryBottomLibrary=%s adivinó %bottom carta(s) de la parte inferior de la biblioteca +lblPlayerHasMulliganedDownToNCards=%s ha hecho mulligan a %d cartas. +lblPlayerDidntAttackThisTurn=%s no atacó este turno. +#FormatFilter.java +lblAllSetsFormats=Todos los Sets/Formatos +lblOtherFormats=Otros Formatos... +lblChooseSets=Selecciona Sets... +#HistoricFormatSelect.java +lblChooseFormat=Selecciona Formato +#TriggerAdapt.java +lblAdapt=Adaptar +#TriggerAttached.java +lblAttachee=Acoplado +#TriggerAttackerBlocked.java +lblNumberBlockers=Número de Bloqueadores +lblBlocker=Bloqueador +#TriggerAttackersDeclared.java +lblNumberAttackers=Número de Atacantes +#TriggerAttackerUnblockedOnce.java +lblAttackingPlayer=Jugador Atacante +lblDefenders=Defensores +#TriggerBecomeMonarch.java +lblPlayer=Jugador +#TriggerBecomeMonstrous.java +lblMonstrous=Monstruoso +#TriggerBecomeRenowned.java +lblRenowned=Renombrado +#TriggerBecomesTarget.java +lblSource=Origen +lblTarget=Objetivo +#TriggerBecomesTargetOnce.java +lblTargets=Objetivos +#TriggerBlockersDeclared.java +lblBlockers=Bloqueadores +#TriggerChampioned.java +lblChampioned=Promovido +#TriggerChangesController.java +lblChangedController=Controlador Cambiado +#TriggerChangesZone.java +lblZoneChanger=Cambiador de Zona +#TriggerChangesZoneAll.java +lblAmount=Cantidad +#TriggerCounterAdded.java +lblAddedOnce=Añadido una vez +#TriggerCountered.java +lblCountered=Contrarrestado +lblCause=Motivo +#TriggerCounteredRemoved.java +lblRemovedFrom=Eliminado de +#TriggerCrewed.java +lblVehicle=Vehículo +lblCrew=Tripulación +#TriggerCycled.java +lblCycled=Ciclado +#TriggerDamageDealtOnce.java +lblDamageSource=Origen del Daño +lblDamaged=Dañado +#TriggerDamagePrevented.java +lblDamageTarget=Dañar Objetivo +#TriggerDestroyed.java +lblDestroyed=Destruido +lblDestroyer=Destructor +#TriggerDevoured.java +lblDevoured=Devorado +#TriggerDiscarded.java +lblDiscarded=Descartado +#TriggerEvolved.java +lblEvolved=Evolucionado +#TriggerExerted.java +lblExerted=Ejecutado +#TriggerExiled.java +lblExiled=Exiliado +#TriggerExploited.java +lblExploited=Explotado +lblExploiter=Explotador +#TriggerExplores.java +lblExplorer=Explorador +#TriggerFight.java +lblFighter=Luchador +#TriggerLandPlayed.java +lblLandPlayed=Tierra jugada +#TriggerLifeGained.java +lblGainedAmount=Cantidad Ganada +#TriggerLifeLost.java +lblLostAmount=Cantidad Perdida +#TriggerPayCumulativeUpkeep.java +lblMana=Maná +#TriggerPayLife.java +lblPaidAmount=Cantidad Pagada +#TriggerPhaseIn.java +lblPhasedIn=En Fase +#TriggerPhaseOut.java +lblPhasedOut=Fuera de Fase +#TriggerRoller.java +lblRoller=Tirador de dados +#TriggerPlaneswalkedFrom.java +lblPlaneswalkedFrom=Planeswalked Desde +#TriggerPlaneswalkedTo.java +lblPlaneswalkedTo=Planeswalked A +#TriggerRegenerated.java +lblRegenerated=Regenerado +#TriggerRevealed.java +lblRevealed=Revelado +#TriggerSacrificed.java +lblSacrificed=Sacrificado +#TriggerScry.java +lblScryer=Escrutador +#TriggerSearchLibrary.java +lblSearcher=Buscador +#TriggerShuffled.java +lblShuffler=Barajeador +#TriggerSpellAbilityCast.java +lblActivator=Activador +#TriggerSpellAbilityCast.java +lblSpellAbility=Habilidad de Hechizo +#TriggerTaps.java +lblTapped=Girado +#TriggerTapsForMana.java +lblTappedForMana=Girado para Maná +lblProduced=Producido +#TriggerTransformed.java +lblTransformed=Transformado +#TriggerTurnFaceUp.java +lblTurnFaceUp=Poner la cara hacia arriba +#TriggerUnattach.java +lblObject=Objeto +lblAttachment=Adjunto +#TriggerUntaps.java +lblUntapped=Desgirado +#TriggerVote.java +lblVoters=Votantes +#PermanentCreatureEffect.java +lblCreature=Criatura \ No newline at end of file diff --git a/forge-gui/res/languages/zh-CN.properties b/forge-gui/res/languages/zh-CN.properties index 012b5a945e8..1ed52d9e239 100644 --- a/forge-gui/res/languages/zh-CN.properties +++ b/forge-gui/res/languages/zh-CN.properties @@ -1,21 +1,21 @@ language.name=Chinese (CN) #SplashScreen.java -splash.loading.examining-cards=加载牌张,检查文件夹 -splash.loading.cards-folders=从文件夹加载牌张 -splash.loading.cards-archive=从存档中加载牌张 +splash.loading.examining-cards=加载卡牌,检查文件夹 +splash.loading.cards-folders=从文件夹加载卡牌 +splash.loading.cards-archive=从存档中加载卡牌 splash.loading.decks=加载套牌 splash.loading.processingimagesprites=处理精灵图 #FControl.java lblOpeningMainWindow=打开主窗口中 lblCloseScreen=关闭屏幕 -txCloseAction1=Forge现在支持选项卡导航,可以轻松关闭和切换不同屏幕。因此,您不再需要使用右上角X按钮关闭当前屏幕并返回 -txCloseAction2=请选择右上角的X按钮选择接下来将要进行的操作。此选项保留给未来使用,您将不会再看到此消息,您可以随时在“首选项”中更改此行为 -titCloseAction=选择您的关闭行动 +txCloseAction1=Forge现在支持选项卡导航,可以轻松关闭和切换不同屏幕。因此,你不再需要使用右上角X按钮关闭当前屏幕并返回 +txCloseAction2=请通过右上角的X按钮选择将要进行的动作。此选项保留给未来使用,你将不会再看到此消息,你可以随时在“首选项”中更改此行为 +titCloseAction=选择你的关闭动作 lblAreYouSureYouWishRestartForge=你确定要重启Forge吗? lblAreYouSureYouWishExitForge=你确定要退出Forge吗? lblOneOrMoreGamesActive=一个或多个游戏正处于活动状态 -lblerrLoadingLayoutFile=无法读取您的布局文件:%s。按OK然后删除。\n游戏将以默认布局进行。 -lblLoadingQuest=加载时空竞逐中... +lblerrLoadingLayoutFile=无法读取你的布局文件:%s。按OK然后删除。\n游戏将以默认布局进行。 +lblLoadingQuest=加载冒险之旅... #FScreen.java lblHome=主页 lblWorkshop=作坊页面 @@ -30,13 +30,13 @@ lblDraftDeckEditor=轮抓套牌编辑器 lblSealedDeckEditor=现开套牌编辑器 lblTokenViewer=衍生物查看器 lblCloseViewer=关闭查看器 -lblQuestDeckEditor=竞逐套牌编辑器 -lblQuestTournamentDeckEditor=竞逐比赛套牌编辑器 -lblSpellShop=轮替商店 +lblQuestDeckEditor=冒险套牌编辑器 +lblQuestTournamentDeckEditor=冒险比赛套牌编辑器 +lblSpellShop=卡牌商店 lblLeaveShop=离开商店 lblLeaveDraft=离开轮抓 lblBazaar=珍宝集市 -lblConcedeGame=让出这场游戏 +lblConcedeGame=这场游戏认输 txerrFailedtodeletelayoutfile=删除布局文件失败。 #VSubmenuPreferences.java Preferences=偏好 @@ -62,7 +62,7 @@ cbEnableAICheats=允许人工智能作弊 cbManaBurn=法术力灼烧 cbManaLostPrompt=提示法术力池将要清空 cbDevMode=开发人员模式 -cbLoadCardsLazily=惰性加载牌张脚本 +cbLoadCardsLazily=惰性加载卡牌脚本 cbLoadHistoricFormats=加载史记赛制 cbWorkshopSyntax=作坊语法检查 cbEnforceDeckLegality=套牌一致性 @@ -74,7 +74,7 @@ cbCloneImgSource=复制使用原始的图片 cbScaleLarger=将图像缩放的更大 cbRenderBlackCardBorders=渲染黑卡边框 cbLargeCardViewers=使用大图查看器 -cbSmallDeckViewer=使用小套牌查看器 +cbSmallDeckViewer=使用小图查看器 cbDisplayFoil=显示闪卡 cbRandomFoil=随机闪卡 cbRandomArtInPools=在生成的卡池中随机加入闪卡 @@ -102,7 +102,7 @@ cbpGameLogEntryType=游戏日志详细程度 cbpCloseAction=关闭动作 cbpDefaultFontSize=默认字体大小 cbpAiProfiles=人工智能强度 -cbpDisplayCurrentCardColors=显示牌张颜色详情 +cbpDisplayCurrentCardColors=显示卡牌颜色详情 cbpAutoYieldMode=自动让过 cbpCounterDisplayType=计数器显示类型 cbpCounterDisplayLocation=计数器显示区域 @@ -141,13 +141,13 @@ nlSingletons=禁止在生成的套牌中非地牌重复出现 nlRemoveArtifacts=在生成的套牌中禁用神器牌 nlCardBased=构建具有更多协同效应的套牌(需要重启) DeckEditorOptions=套牌编辑器选项 -nlFilterLandsByColorId=当使用牌张颜色筛选器时,过滤地可以更容易找到产数相关法术力的地 +nlFilterLandsByColorId=当使用卡牌颜色筛选器时,过滤地可以更容易找到产数相关法术力的地 AdvancedSettings=高级设置 nlDevMode=启用在开发期间进行测试的功能菜单 -nlWorkshopSyntax=在作坊中启用牌张脚本检查。注意:该功能任在测试阶段。 +nlWorkshopSyntax=在作坊中启用卡牌脚本检查。注意:该功能任在测试阶段。 nlGameLogEntryType=更改游戏中日志显示的信息量。排序为最少到最详细。 -nlCloseAction=更改单击右上角X按钮时的行为 -nlLoadCardsLazily=如果打开该选项Forge将在使用到牌张脚本时才加载(警告:实验状态)。 +nlCloseAction=更改单击右上角X按钮时的动作 +nlLoadCardsLazily=如果打开该选项Forge将在使用到卡牌脚本时才加载(警告:实验状态)。 nlLoadHistoricFormats=如果打开,Forge将加载史记赛制,这个能会导致游戏载入时间变长。 GraphicOptions=图形选项 nlDefaultFontSize=UI中字体的默认大小。所有字体元素都相对于此缩放。(需要重启) @@ -155,21 +155,21 @@ cbpMulliganRule = 调度规则 nlImageFetcher=允许从在线资源中实时获取缺失的图片 nlDisplayFoil=显示闪卡 nlRandomFoil=随机将牌设置为闪卡 -nlScaleLarger=允许牌张图片缩放为初始大小 +nlScaleLarger=允许卡牌图片缩放为初始大小 nlRenderBlackCardBorders=为牌周围渲染黑色边框 nlLargeCardViewers=是所有牌看起来更大以便高分辨率图片看起来更舒适,不适合低分辨率设备使用 nlSmallDeckViewer=将套牌查看器设置为800X600而不是按屏幕大小等比缩放 nlRandomArtInPools=限制赛生成的卡池中带有闪卡。 nlUiForTouchScreen=增加一些UI元素以提高触屏体验(需要重启)。 nlCompactPrompt=隐藏标题并在“提示”窗格中使用较小的字体使其更紧凑。 -nlHideReminderText=在“牌张详情“窗格中隐藏提醒文本 +nlHideReminderText=在“卡牌详情“窗格中隐藏提醒文本 nlOpenPacksIndiv=打开肥包或者补充盒的时候一包一包开。 nlTokensInSeparateRow=生物与衍生物分不同的行显示。 nlStackCreatures=在战场上如同地、神器、结界一般堆叠一样的生物。 nlTimedTargOverlay=启用基于限制目标的覆盖优化以减少CPU使用率(仅在旧设备上需要使用,需要重启游戏)。 nlCounterDisplayType=选择指示物的样式。基于文本还是基于图片还是二者混合。 -nlCounterDisplayLocation=确定牌张上指示物的位置:靠近底部还是顶部 -nlDisplayCurrentCardColors=在牌张详情窗格中显示当前牌的颜色 +nlCounterDisplayLocation=确定卡牌上指示物的位置:靠近底部还是顶部 +nlDisplayCurrentCardColors=在卡牌详情窗格中显示当前牌的颜色 SoundOptions=声音选项 nlEnableSounds=在游戏中启用声音效果 nlEnableMusic=在游戏中启用背景音乐 @@ -188,18 +188,18 @@ btnListImageData=统计牌和图片数据 lblListImageData=统计Forge实现且缺少的图片的牌 btnImportPictures=导入数据 btnHowToPlay=如何玩 -btnDownloadPrices=下载牌张价格 +btnDownloadPrices=下载卡牌价格 btnLicensing=许可证详情 lblDownloadPics=下载缺省牌的图片 lblDownloadPicsHQ=下载缺省牌的高清图片 lblDownloadSetPics=下载每张牌的图片(每张牌出现一次) lblDownloadQuestImages=下载冒险之旅里使用的衍生物与图标 lblDownloadAchievementImages=下载成就图片,让你的奖杯更引人注目。 -lblDownloadPrices=下载牌张商店最新的价格表 +lblDownloadPrices=下载卡牌商店最新的价格表 lblYourVersionOfJavaIsTooOld=你的Java版本太旧无法开始下载内容 lblPleaseUpdateToTheLatestVersionOfJava=请更新到最新版本的JRE lblYoureRunning=你在运行 -lblYouNeedAtLeastJavaVersion=您的JRE版本至少需要为1.8.0_101。 +lblYouNeedAtLeastJavaVersion=你的JRE版本至少需要为1.8.0_101。 lblImportPictures=从本地目录导入数据 lblReportBug=什么东西坏了? lblHowToPlay=游戏规则。 @@ -230,7 +230,7 @@ lblGameSettings=游戏设置 #VLobby.java lblHeaderConstructedMode=游戏模式:构筑 lblGetNewRandomName=获取一个随机名称 -lbltypeofName=您想要生成什么类型的名称? +lbltypeofName=你想要生成什么类型的名称? lblconfirmName=你想使用名称%s,还是想重试 lblUseThisName=使用这个名称 lblTryAgain=再试一次 @@ -299,7 +299,7 @@ lblAlphaStrike=先攻 lblEndTurn=结束回合 lblTargetingArcs=瞄准弧 lblOff=关闭 -lblCardMouseOver=牌张悬停 +lblCardMouseOver=卡牌悬停 lblAlwaysOn=总是打开 lblAutoYields=自动让过 lblDeckList=套牌列表 @@ -357,7 +357,7 @@ lblDraftText3=然后对抗一个或多个人工智能对手 lblNewBoosterDraftGame=新的补充包轮抓 lblDraftDecks=轮抓套牌 #CSubmenuDraft.java -lblNoDeckSelected=没有为人类选择套牌。\n(您可能要建立一个新的套牌) +lblNoDeckSelected=没有为人类选择套牌。\n(你可能要建立一个新的套牌) lblNoDeck=没有套牌 lblChooseDraftFormat=选择轮抓模式 #VSubmenuSealed.java @@ -365,7 +365,7 @@ lblSealedDeck=现开 lblSealedDecks=现开套牌 lblHeaderSealed=游戏模式:现开 lblSealedText1=构建或选择一个套牌 -lblSealedText2=在现开模式中,您可以从补充包里(最多10个)构建一套牌 +lblSealedText2=在现开模式中,你可以从补充包里(最多10个)构建一套牌 lblSealedText3=从你得到的牌中组一套牌。人工智能也会这样做 lblSealedText4=然后对抗一个或多个人工智能对手 btnBuildNewSealedDeck=构建新的现开套牌 @@ -392,7 +392,7 @@ lblGauntlet=决斗 lblTournament=锦标赛 lblQuest=冒险 lblQuestDraft=冒险轮抓 -lblPlanarConquest=时空竞逐征服 +lblPlanarConquest=时空征服 lblPuzzle=谜题 lblPuzzleDesc=从给定的游戏状态解谜 lblDeckManager=套牌管理 @@ -425,7 +425,7 @@ lblNextChallengeNotYet=没有确定下次胜利后的挑战 btnUnlockSets=解锁系列 btnTravel=时空旅行 btnBazaar=珍宝集市 -btnSpellShop=牌张商店 +btnSpellShop=卡牌商店 cbSummonPlant=召唤植物 cbLaunchZeppelin=启动飞艇 #VSubmenuQuest.java @@ -448,7 +448,7 @@ lblCustomdeck=自定义套牌 lblDefineCustomFormat=定义自定义赛制 lblSelectFormat=选择赛制 lblStartWithAllCards=从所选系列的所有牌开始 -lblAllowDuplicateCards=允许重复的牌张 +lblAllowDuplicateCards=允许重复的卡牌 lblStartingPoolDistribution=初始牌池分配 lblChooseDistribution=选择分配 lblPrizedCards=奖励卡 @@ -505,9 +505,9 @@ lblColors=颜色 lblnoSettings=没有可用于此选择的设置 lblDistribution=分配 lblHoverforDescription=将鼠标悬停在每个选项上以获得更详细的说明 -lblradBalanced=“均衡”将在每种选定的颜色中提供数量均衡的牌张。 -lblradRandom=“随机”将随机分配牌张和颜色。 -lblradSurpriseMe=随机挑选颜色并提供数量均衡的随机牌张。 +lblradBalanced=“均衡”将在每种选定的颜色中提供数量均衡的卡牌。 +lblradRandom=“随机”将随机分配卡牌和颜色。 +lblradSurpriseMe=随机挑选颜色并提供数量均衡的随机卡牌。 lblradBoosters=忽略所有颜色设置,从指定数量的补充包中生成牌池 lblcbxArtifacts=选择后无论选择的颜色如何,神器都包涵在牌池中,这模拟了旧牌池的行为。 #VSubmenuChallenges.java @@ -548,6 +548,7 @@ lblPreconstructedDecks=预组套牌 lblQuestOpponentDecks=冒险之旅套牌 lblRandomColorDecks=随机颜色套牌 lblRandomStandardArchetypeDecks=随机标准原型套牌 +lblRandomPioneerArchetypeDecks=随机先驱原型套牌 lblRandomModernArchetypeDecks=随机摩登原型套牌 lblRandomLegacyArchetypeDecks=随机薪传原型套牌 lblRandomVintageArchetypeDecks=随机特选原型套牌 @@ -620,7 +621,7 @@ lblBuildAndSelectaDeck=构建,然后在“冒险套牌”子菜单中选择一 lblCurrentDeck=你现在的套牌是%n PleaseCreateAQuestBefore=请在%n之前创建套牌。 lblNoQuest=没有探索 -lblVisitTheSpellShop=参观牌张商店 +lblVisitTheSpellShop=进入卡牌商店 lblVisitTheBazaar=参观珍宝集市 lblUnlockEditions=解锁新的时空 lblUnlocked=你已经成功解锁%n @@ -628,7 +629,7 @@ titleUnlocked=%n解锁! lblStartADuel=开始决斗! lblSelectAQuestDeck=请选择一个冒险套牌。 lblInvalidDeck=错误的套牌 -lblInvalidDeckDesc=您的套牌%n请编辑或者选择其他套牌 +lblInvalidDeckDesc=你的套牌%n请编辑或者选择其他套牌 #VSubmenuQuestPrefs.java lblQuestPreferences=冒险偏好 lblRewardsError=奖励错误 @@ -672,7 +673,7 @@ lblStartingCredits=初始积分 lblWinsforNewChallenge=新挑战所需的胜利 lblStartingSnowLands=初始雪境地 lblColorBias=颜色偏差(1-100%) -ttColorBias=初始卡池中您选择的颜色的百分比 +ttColorBias=初始卡池中的颜色百分比 lblPenaltyforLoss=失败补偿 lblMoreDuelChoices=更多决斗选择 lblCommon=铁 @@ -695,11 +696,11 @@ lblCardSalePercentageCap=出售牌的系数上限 lblCardSalePriceCap=出售牌的价格上限 lblWinstoUncapSalePrice=胜利解锁价格系数 lblPlaysetSize=玩家收藏大小 -ttPlaysetSize=在售卖牌张时要保留的牌张数量 +ttPlaysetSize=在售卖卡牌时要保留的卡牌数量 lblPlaysetSizeBasicLand=玩家收藏大小:基本地 -ttPlaysetSizeBasicLand=在售卖牌张时要保留的基本地数量 +ttPlaysetSizeBasicLand=在售卖卡牌时要保留的基本地数量 lblPlaysetSizeAnyNumber=玩家收藏大小:任意数量 -ttPlaysetSizeAnyNumber=售卖牌张时不保留牌张 +ttPlaysetSizeAnyNumber=售卖卡牌时不保留 lblItemLevelRestriction=物品等级限制 lblFoilfilterAlwaysOn=闪卡过滤器始终开启 lblRatingsfilterAlwaysOn=评级过滤器始终开启。 @@ -756,6 +757,7 @@ lblcopiesof=副本 #ItemListView.java lblUniqueCardsOnly=每张牌都只显示一个画 ttUniqueCardsOnly=切换是否每张牌都只显示一个画 +lblListView=列表视图 #ACEditorBase.java lblAddcard=添加牌 ttAddcard=将选定的牌添加到当前套牌(双击该行或者空格) @@ -767,7 +769,7 @@ lblRemove4ofcard=移除4张牌 ttRemove4ofcard=最多可以将4张所选牌从当前套牌移除 lblAddBasicLands=添加基本地 ttAddBasicLands=添加基本地到套牌 -lblCardCatalog=牌张目录 +lblCardCatalog=卡牌目录 lblJumptoprevioustable=跳转到上一个表格 lblJumptopnexttable=跳转到下一个表格 lblJumptotextfilter=跳转到文本筛选器 @@ -788,6 +790,9 @@ lblCollapseallgroups=折叠所有组 lblGroupby=分组 lblPileby=堆积 lblColumns=行 +lblPiles=柱状: +lblGroups=分组: +lblImageView=图片视图 #CEditorVariant.java, CEditorConstructed.java lblCatalog=目录 lblAdd=添加 @@ -807,7 +812,7 @@ lbltoplanardeck=到时空竞逐套牌 lbltoconspiracydeck=到诡局套牌 lblMove=移到 #VDock.java -lblDock=Dock +lblDock=停靠栏 lblViewDeckList=查看套牌列表 lblRevertLayout=还原布局 lblOpenLayout=打开布局 @@ -883,7 +888,7 @@ lblQty=数量 lblQuantity=数量 lblSide=备牌 lblSideboard=备牌 -lblNew=新建 +lblNew=新获得 lblOwned=拥有 lblPower=力量 ttPower=力量 @@ -904,8 +909,8 @@ lblAutomaticBugReports=自动报告BUG lblBattlefieldTextureFiltering=战场纹理过滤 lblCompactListItems=紧凑的项目列表 lblCompactTabs=紧凑标签 -lblCardOverlays=牌张叠加层 -lblDisableCardEffect=禁用牌张“效果”图 +lblCardOverlays=卡牌叠加层 +lblDisableCardEffect=禁用卡牌“效果”图 lblDynamicBackgroundPlanechase=动态时空背景 lblGameplayOptions=游戏选项 lblGeneralSettings=常规设置 @@ -915,14 +920,14 @@ lblLater=以后 lblMinimizeScreenLock=锁屏时最小化 lblOrderGraveyard=坟场顺序 lblRestartForge=重启Forge -lblRestartForgeDescription=您必须重启Forge才能使此更改生效 +lblRestartForgeDescription=你必须重启Forge才能使此更改生效 lblRotateZoomPlanesPhenomena=旋转缩放时空/异象图 lblRotateZoomSplit=旋转缩放连体牌 lblShowAbilityIconsOverlays=显示异能图标 -lblShowCardIDOverlays=显示牌张ID叠加层 -lblShowCardManaCostOverlays=显示牌张法术力费用叠加层 -lblShowCardNameOverlays=显示牌张名称叠加层 -lblShowCardOverlays=显示牌张叠加层 +lblShowCardIDOverlays=显示卡牌ID叠加层 +lblShowCardManaCostOverlays=显示卡牌法术力费用叠加层 +lblShowCardNameOverlays=显示卡牌名称叠加层 +lblShowCardOverlays=显示卡牌叠加层 lblShowCardPTOverlays=显示攻击/防御叠加层 lblShowMatchBackground=显示比赛背景 lblVibrateAfterLongPress=长按后震动 @@ -930,26 +935,32 @@ lblVibrateWhenLosingLife=失去生命时震动 lblVibrationOptions=振动选项 nlAutomaticBugReports=在没有提示的情况下自动向开发人员报告错误 nlBattlefieldTextureFiltering=在战场上过滤闪卡特效,使其在大屏幕上不像素化(需要重启,可能会降低性能)。 -nlCompactListItems=默认情况下,在所有视图列表中只显示牌张和套牌的单行文本。 +nlCompactListItems=默认情况下,在所有视图列表中只显示卡牌和套牌的单行文本。 nlCompactTabs=在标签页屏幕顶部显示较小的标签(例如此屏幕)。 nlDisableCardEffect=禁用“效果”卡的缩放图片。 nlDynamicBackgroundPlanechase=使用当前时空图片作为背景(时空图片必须位于cache/pics/planechase文件夹中)。 nlHotSeatMode=当用两个人类玩家开始游戏的时候,用单个提示控制两个玩家。 nlLandscapeMode=使用横向(水平)而不是纵向(垂直)。 nlMinimizeScreenLock=锁定屏幕时最小化Forge(锁屏以后出现图形故障使用)。 -nlOrderGraveyard=确定何时让玩家确定同时进入坟场的牌的顺序(绝不/总是/只对有关牌张)。 +nlOrderGraveyard=确定何时让玩家确定同时进入坟场的牌的顺序(绝不/总是/只对有关卡牌)。 nlRotateZoomPlanesPhenomena=旋转缩放时空或异象图片。 nlRotateZoomSplit=旋转缩放连体牌图片。 -nlShowAbilityIconsOverlays=在牌张上显示异能图标,否则他们被隐藏。 -nlShowCardIDOverlays=显示牌张的ID叠加层,否则他们被隐藏。 -nlShowCardManaCostOverlays=显示牌张的法术力费用叠加层,否则他们被隐藏。 -nlShowCardNameOverlays=显示牌张的名称费用叠加层,否则他们被隐藏。 -nlShowCardOverlays=显示牌张名称,法术力费用,力量/防御和ID叠加层,否则他们被隐藏。 +nlShowAbilityIconsOverlays=在卡牌上显示异能图标,否则他们被隐藏。 +nlShowCardIDOverlays=显示卡牌的ID叠加层,否则他们被隐藏。 +nlShowCardManaCostOverlays=显示卡牌的法术力费用叠加层,否则他们被隐藏。 +nlShowCardNameOverlays=显示卡牌的名称费用叠加层,否则他们被隐藏。 +nlShowCardOverlays=显示卡牌名称,法术力费用,力量/防御和ID叠加层,否则他们被隐藏。 nlShowCardPTOverlays=显示力量/防御/忠诚叠加层,否则他们被隐藏。 nlShowMatchBackground=在战场显示背景图片,否则显示背景纹理。 nlTheme=设置显示的组件使用的外观主题。 -nlVibrateAfterLongPress=启用长按触发震动,例如长按缩放牌张图片。 +nlVibrateAfterLongPress=启用长按触发震动,例如长按缩放卡牌图片。 nlVibrateWhenLosingLife=启用当玩家在游戏中失去生命或收到伤害时震动。 +lblEnableRoundBorder=启用圆角边框掩码 +nlEnableRoundBorder=启用后,卡牌边框会变成圆角(带有完整边框的卡牌图片效果最好)。 +lblPreloadExtendedArtCards=预加载拉伸卡图 +nlPreloadExtendedArtCards=启用后,拉伸卡图将在启动时加载到缓存。 +lblShowFPSDisplay=显示当前的FPS值 +nlShowFPSDisplay=启用后,将在画面左上角显示当前Forge的FPS(实验性特性)。 #MatchScreen.java lblPlayers=玩家列表 lblLog=日志 @@ -973,7 +984,7 @@ lblChangePreferredArt=改变首选卡图 lblSelectPreferredArt=选择首选的卡图版本 lblTo=到 lblAvatar=头像 -lblCards=牌张 +lblCards=卡牌 lblPlanes=时空 lblSchemes=阴谋 lblToMainDeck=到主牌 @@ -984,8 +995,9 @@ lblCommanders=指挥官 lblOathbreakers=破誓者 #Forge.java lblLoadingFonts=加载字体中 -lblLoadingCardTranslations=加载牌张翻译中 +lblLoadingCardTranslations=加载卡牌翻译中 lblFinishingStartup=完成启动 +lblPreloadExtendedArt=预加载拉伸卡图 #LobbyScreen.java lblMore=更多 lblLoadingNewGame=载入新游戏中 @@ -1038,11 +1050,11 @@ lblNoPlayerPriorityNoDeckListViewed=现在玩家没有优先权,因此无法 #FilesPage.java lblFiles=文件 lblStorageLocations=储存位置 -lblCardPicsLocation=牌张图片位置 +lblCardPicsLocation=卡牌图片位置 lblDecksLocation=套牌位置 lblDataLocation=数据位置(例如 设置和探索模式) lblImageCacheLocation=图片缓存位置 -lblRestartForgeMoveFilesNewLocation=您必须重启Forge才能使此更改生效。执行此操作之前,请确保将所有必要的文件移动到新的位置。 +lblRestartForgeMoveFilesNewLocation=你必须重启Forge才能使此更改生效。执行此操作之前,请确保将所有必要的文件移动到新的位置。 lblRestartRequired=需要重启 lblSelect=选择%s #AddBasicLandsDialog.java @@ -1050,17 +1062,17 @@ lblLandSet=地牌的系列 lblAddBasicLandsAutoSuggest=添加基本地到%s\n(双击自动添加) lblAssortedArt=各种画 lblCardArt=卡图%d -lblNonLandCount=%d张非地 -lblOldLandCount=%d张地 -lblNewLandCount=添加%d张地 +lblNonLandCount=%d张非地牌 +lblOldLandCount=%d张地牌 +lblNewLandCount=添加%d张地牌 lblNewTotalCount=%d张牌 #FDeckImportDialog.java -lblImportLatestVersionCard=导入牌张的最新版本 +lblImportLatestVersionCard=导入卡牌的最新版本 lblUseOnlySetsReleasedBefore=只用之前上市系列的版本: lblUseOnlyCoreAndExpansionSets=只使用核心系列和拓展系列 -lblFollowingCardsCannotBeImported=由于拼写错误,系列限制或forge尚未实现,以下牌张没有被导入: +lblFollowingCardsCannotBeImported=由于拼写错误,系列限制或forge尚未实现,以下卡牌没有被导入: lblImportRemainingCards=导入剩余的卡? -lblNoKnownCardsOnClipboard=在剪切板找不到已知的牌张。\n\n将套牌列表复制到剪切板,然后重新打开此对话框。 +lblNoKnownCardsOnClipboard=在剪切板找不到已知的卡牌。\n\n将套牌列表复制到剪切板,然后重新打开此对话框。 #FDeckViewer.java lblDeckListCopiedClipboard=套牌列表'%s'已经复制到剪切板 #FSideboardDialog.java @@ -1092,11 +1104,11 @@ lblWouldYouLiketoPlayorDraw=你想先手还是后手? lblWhoWouldYouLiketoStartthisGame=你想谁先开始游戏?(单击头像) lblPlay=先手 lblDraw=后手 -lblTooFewCardsMainDeck=主牌中牌张数过少(最少为%s),请重新修改套牌。 -lblTooManyCardsSideboard=备牌中牌张数过多(最多为%s),请重新修改套牌。 +lblTooFewCardsMainDeck=主牌中卡牌数过少(最少为%s),请重新修改套牌。 +lblTooManyCardsSideboard=备牌中卡牌数过多(最多为%s),请重新修改套牌。 lblAssignCombatDamageWerentBlocked=是否要像没有被阻挡一样分配战斗伤害? lblChosenCards=选择牌 -lblAttacker=攻击者 +lblAttacker=进攻者 lblTriggeredby=触发者 lblChooseWhichCardstoReveal=选择要展示的牌 lblChooseCardsActivateOpeningHandandOrder=选择要展示的手牌和顺序 @@ -1110,16 +1122,16 @@ lblPleaseDefineanActionSequenceFirst=请先定义一个动作序列。 lblRememberActionSequence=记住动作序列 lblYouMustHavePrioritytoUseThisFeature=你必须有使用此功能的优先权。 lblNameTheCard=命名牌 -lblWhichPlayerShouldRoll=那个玩家掷骰子? +lblWhichPlayerShouldRoll=哪位玩家掷骰子? lblChooseResult=选择结果 lblChosenCardNotPermanentorCantExistIndependentlyontheBattleground=选择的牌不是永久物,也不能在战场单独存在。\n如果你想释放费永久物咒语或者你想释放永久物咒语并将之放于堆叠上,请按"Cast Spell/Play Land"按钮。 lblError=错误 lblWinGame=赢得这局游戏 lblSetLifetoWhat=设定生命值为多少? -lblSetLifeforWhichPlayer=设定哪个牌手的生命值? +lblSetLifeforWhichPlayer=设定哪位牌手的生命值? lblChoosePermanentstoTap=选择要横置的永久物 lblChoosePermanentstoUntap=选择要重置的永久物 -lblWhichTypeofCounter=那种指示物? +lblWhichTypeofCounter=哪种指示物? lblHowManyCounters=多少指示物? lblRemoveCountersFromWhichCard=从哪张牌移除指示物? lblAddCountersToWhichCard=添加指示物到哪张牌? @@ -1127,23 +1139,45 @@ lblChooseaCard=选择一张牌 lblNoPlayerPriorityDeckCantBeTutoredFrom=目前没有玩家拥有优先权,因此无法从其套牌导师。 lblNoPlayerPriorityGameStateCannotBeSetup=目前没有玩家拥有优先权,因此无法设置游戏状态。 lblErrorLoadingBattleSetupFile=加载战场设置文件出错! -lblSelectCardstoAddtoYourDeck=选择要添加到套牌的牌张。 +lblSelectCardstoAddtoYourDeck=选择要添加到套牌的卡牌。 lblAddTheseToMyDeck=添加这些到我的套牌 lblChooseaPile=选择一堆 lblSelectOrderForSimultaneousAbilities=选择同时触发的异能的结算顺序 lblReorderSimultaneousAbilities=重新对同时触发异能的结算顺序进行排序 lblResolveFirst=先结算 -lblMoveCardstoToporBbottomofLibrary=将牌张移动到牌库顶或底 -lblSelectCardsToBeOutOnTheBottomOfYourLibrary=选择要放到牌库底的牌张 -lblCardsToPutOnTheBottom=放到底部的牌张 -lblArrangeCardsToBePutOnTopOfYourLibrary=为放于牌库顶的牌张排序 +lblMoveCardstoToporBbottomofLibrary=将卡牌移动到牌库顶或底 +lblSelectCardsToBeOutOnTheBottomOfYourLibrary=选择要放到牌库底的卡牌 +lblCardsToPutOnTheBottom=放到底部的卡牌 +lblArrangeCardsToBePutOnTopOfYourLibrary=为放于牌库顶的卡牌排序 lblTopOfLibrary=牌库顶 -lblSelectCardsToBePutIntoTheGraveyard=选择要放于坟场的牌张 -lblCardsToPutInTheGraveyard=放于坟场的牌张 +lblSelectCardsToBePutIntoTheGraveyard=选择要放于坟场的卡牌 +lblCardsToPutInTheGraveyard=放于坟场的卡牌 +lblDiscardUpToNCards=最多弃%d张牌 +lblDiscardNCards=弃%d张牌 +lblSelectNCardsToDiscardUnlessDiscarduType=选择要丢弃的%d张牌,除非你丢弃%s。 +lblCleanupPhase=清除步骤 +lblSelectCardsToDiscardHandDownMaximum=选择要丢弃的%d张牌,以使你的手牌数量减少到%max张。 +lblChooseMinCardToDiscard=选择%d张牌弃掉 +lblDiscarded=弃牌 +lblChooseDamageOrderFor=选择%s造成伤害的顺序 +lblDamagedFirst=先造成伤害 +lblChooseBlockerAfterWhichToPlaceAttackert=选择%s后造成伤害的阻挡者; cancel to place it first +lblPutCardOnTopOrBottomLibrary=将%s放到牌库顶还是底? +lblChooseOrderCardsPutIntoLibrary=选择要放入牌库中的牌的顺序 +lblClosestToTop=最接近顶部 +lblChooseOrderCardsPutOntoBattlefield=选择要放入战场中的牌的顺序 +lblPutFirst=放在最前 +lblChooseOrderCardsPutIntoGraveyard=选择要放入坟场中的牌的顺序 +lblClosestToBottom=最接近底部 +lblChooseOrderCardsPutIntoPlanarDeck=选择要放入时空竞逐套牌中的牌的顺序 +lblChooseOrderCardsPutIntoSchemeDeck=选择要放入魔王套牌中的牌的顺序 +lblChooseOrderCopiesCast=选择要复制品的释放顺序。 +lblDelveHowManyCards=掘穴多少张牌? +lblExileWhichCard=放逐哪张牌? #AbstractGuiGame.java -lblConcedeCurrentGame=这将让出这局游戏,而你将输掉。\n\n一定要让出吗? -lblConcedeTitle=让出这局游戏? -lblConcede=让出 +lblConcedeCurrentGame=这局游戏认输。\n\n确认吗? +lblConcedeTitle=这局游戏认输? +lblConcede=认输 lblCloseGameSpectator=这将关闭游戏,你将无法继续观看它。\n\n一定要关闭吗? lblCloseGame=关闭游戏? lblWaitingForOpponent=等待对手中 @@ -1153,16 +1187,16 @@ lblEnterNumberBetweenMinAndMax=输入介于%min到%max之间的数字: lblEnterNumberGreaterThanOrEqualsToMin=输入一个大于等于%min的数字: lblEnterNumberLessThanOrEqualsToMax=输入一个小于等于%max的数字: #PlayerOutcome.java -lblWonBecauseAllOpponentsHaveLost=由于所有对手都输了所以你赢了 -lblWonDueToEffectOf=受'%s'的影响而获胜了 -lblConceded=已经让出 +lblWonBecauseAllOpponentsHaveLost=因所有对手都输了而赢得胜利 +lblWonDueToEffectOf=受'%s'的影响赢得胜利 +lblConceded=已经认输 lblLostTryingToDrawCardsFromEmptyLibrary=尝试从为空的牌库中抓牌而输 lblLostBecauseLifeTotalReachedZero=生命值为0而输 lblLostBecauseOfObtainingTenPoisonCounters=中毒指示物达到10而输 lblLostBecauseAnOpponentHasWonBySpell=因对手用咒语'%s'获胜而输 lblLostDueToEffectOfSpell=受咒语'%s'的影响而输 lblLostDueToAccumulationOf21DamageFromGenerals=受到大于21点主将伤害而输 -lblAcceptedThatTheGameIsADraw=已经接受此局游戏平局 +lblAcceptedThatTheGameIsADraw=此局游戏平局 lblLostForUnknownReasonBug=由于未知错误而输(这是一个错误) #ViewWinLose.java btnNextGame=下一局游戏 @@ -1171,4 +1205,177 @@ btnQuitMatch=退出比赛 lblItsADraw=平局! lblTeamWon=队伍%s胜利了! lblWinnerWon=%s胜利了! -lblGameLog=游戏日志 \ No newline at end of file +lblGameLog=游戏日志 +#NewDraftScreen.java +lblLoadingNewDraft=加载新的轮抽中 +#LoadDraftScreen.java +lblDoubleTapToEditDeck=双击以编辑套牌(长按可以查看) +lblMode=模式: +lblYouMustSelectExistingDeck=你必须选择一个已有的卡组或者从新的补充包轮抽游戏中构筑一个卡组。 +lblWhichOpponentWouldYouLikeToFace=你想面对哪个对手? +lblSingleMatch=单场比赛 +#NewGauntletScreen.java +lblGauntletText1=在决斗模式下,你可以选择一套牌与多个对手进行对战。 +lblGauntletText2=设置你想面对的对手数量以及他们所使用的套牌类型或者套牌。 +lblGauntletText3=然后,尝试击败所有人工智能对手而不输掉一场比赛。 +lblSelectGauntletType=选择一个决斗类型 +lblCustomGauntlet=自定义决斗 +lblGauntletContest=决斗竞赛 +lblSelectYourDeck=选择你的套牌 +lblSelectDeckForOpponent=选择对手的套牌 +lblSelectGauntletContest=选择决斗竞赛 +#PuzzleScreen.java +lblPuzzleText1=解谜模式会加载一个谜题,你必须在预定的时间/方式中获胜。 +lblPuzzleText2=首先,按下面的开始按钮,然后从列表中选择一个谜题。 +lblPuzzleText3=当解谜开始的时候,该谜题的要求将会显示在弹窗中,并且还会在指挥官区域放置一张特殊效应卡指示这个谜题的要求。 +lblChooseAPuzzle=选择一个谜题 +lblLoadingThePuzzle=加载新的谜题中 +#InputPassPriority.java +lblCastSpell=释放咒语 +lblPlayLand=使用地 +lblActivateAbility=启动式异能 +lblYouHaveManaFloatingInYourManaPoolCouldBeLostIfPassPriority=你的法术力池中还有剩余的法术力,如果现在让过优先权,这些法术力可能会丢失。 +lblYouWillTakeManaBurnDamageEqualAmountFloatingManaLostThisWay=你将受到等同于通过这种方式失去的剩余法术力数量的法术力灼烧伤害。 +lblManaFloating=剩余法术力 +#InputPayManaOfCostPayment.java +lblPayManaCost=支付法术力: +lblLifePaidForPhyrexianMana=(以%d生命支付了非瑞克西亚法术力) +lblClickOnYourLifeTotalToPayLifeForPhyrexianMana=单击你的总生命,以生命值支付非瑞克西亚法术力。 +lblClickOnYourLifeTotalToPayLifeForBlackMana=单击你的总生命,以生命值支付黑色法术力。 +lblClickOnYourLifeTotalToPayLifeForPhyrexianOrBlackMana=单击你的总生命,以生命值支付黑色或非瑞克西亚法术力。 +#GameLogFormatter.java +lblLogScryTopBottomLibrary=%s将%top张牌放到牌库顶和%bottom张牌放到牌库底 +lblLogScryTopLibrary=%s将%top张牌放到牌库顶 +lblLogScryBottomLibrary=%s将%top张牌放到牌库底 +lblPlayerHasMulliganedDownToNCards=%s已经调度到%d张牌。 +lblPlayerDidntAttackThisTurn=%s本回合没有进攻。 +#FormatFilter.java +lblAllSetsFormats=所有系列/赛制 +lblOtherFormats=其他赛制 +lblChooseSets=选择系列 +#HistoricFormatSelect.java +lblChooseFormat=选择赛制 +#TriggerAdapt.java +lblAdapt=演化 +#TriggerAttached.java +lblAttachee=结附 +#TriggerAttackerBlocked.java +lblNumberBlockers=阻挡者数 +lblBlocker=阻挡者 +#TriggerAttackersDeclared.java +lblNumberAttackers=攻击者数 +#TriggerAttackerUnblockedOnce.java +lblAttackingPlayer=进攻牌手 +lblDefenders=阻挡者 +#TriggerBecomeMonarch.java +lblPlayer=牌手 +#TriggerBecomeMonstrous.java +lblMonstrous=已蛮化 +#TriggerBecomeRenowned.java +lblRenowned=已铭勇 +#TriggerBecomesTarget.java +lblSource=来源 +lblTarget=目标 +#TriggerBecomesTargetOnce.java +lblTargets=目标 +#TriggerBlockersDeclared.java +lblBlockers=阻挡者 +#TriggerChampioned.java +lblChampioned=夺冠 +#TriggerChangesController.java +lblChangedController=改变操控者 +#TriggerChangesZone.java +lblZoneChanger=改变区域 +#TriggerChangesZoneAll.java +lblAmount=共计 +#TriggerCounterAdded.java +lblAddedOnce=添加一次 +#TriggerCountered.java +lblCountered=反击 +lblCause=原因 +#TriggerCounteredRemoved.java +lblRemovedFrom=删除 +#TriggerCrewed.java +lblVehicle=载具 +lblCrew=搭载 +#TriggerCycled.java +lblCycled=已循环 +#TriggerDamageDealtOnce.java +lblDamageSource=伤害来源 +lblDamaged=造成伤害 +#TriggerDamagePrevented.java +lblDamageTarget=伤害目标 +#TriggerDestroyed.java +lblDestroyed=被消灭 +lblDestroyer=破坏者 +#TriggerDevoured.java +lblDevoured=已吞噬 +#TriggerDiscarded.java +lblDiscarded=丢弃 +#TriggerEvolved.java +lblEvolved=已进化 +#TriggerExerted.java +lblExerted=已耗竭 +#TriggerExiled.java +lblExiled=被放逐 +#TriggerExploited.java +lblExploited=被榨取 +lblExploiter=榨取者 +#TriggerExplores.java +lblExplorer=勘察者 +#TriggerFight.java +lblFighter=互斗者 +#TriggerLandPlayed.java +lblLandPlayed=已下地 +#TriggerLifeGained.java +lblGainedAmount=获得的数量 +#TriggerLifeLost.java +lblLostAmount=失去的数量 +#TriggerPayCumulativeUpkeep.java +lblMana=法术力 +#TriggerPayLife.java +lblPaidAmount=已支付的数量 +#TriggerPhaseIn.java +lblPhasedIn=已跃回 +#TriggerPhaseOut.java +lblPhasedOut=已跃离 +#TriggerRoller.java +lblRoller=回滚者 +#TriggerPlaneswalkedFrom.java +lblPlaneswalkedFrom=时空旅行自 +#TriggerPlaneswalkedTo.java +lblPlaneswalkedTo=时空旅行到 +#TriggerRegenerated.java +lblRegenerated=已重生 +#TriggerRevealed.java +lblRevealed=已展示 +#TriggerSacrificed.java +lblSacrificed=已牺牲 +#TriggerScry.java +lblScryer=占卜者 +#TriggerSearchLibrary.java +lblSearcher=搜寻者 +#TriggerShuffled.java +lblShuffler=洗牌者 +#TriggerSpellAbilityCast.java +lblActivator=启动自 +#TriggerSpellAbilityCast.java +lblSpellAbility=咒语异能 +#TriggerTaps.java +lblTapped=已横置 +#TriggerTapsForMana.java +lblTappedForMana=为法术力横置 +lblProduced=产生 +#TriggerTransformed.java +lblTransformed=已转化 +#TriggerTurnFaceUp.java +lblTurnFaceUp=面朝上 +#TriggerUnattach.java +lblObject=物件 +lblAttachment=装备 +#TriggerUntaps.java +lblUntapped=未横置 +#TriggerVote.java +lblVoters=投票 +#PermanentCreatureEffect.java +lblCreature=生物 \ No newline at end of file diff --git a/forge-gui/res/lists/net-decks.txt b/forge-gui/res/lists/net-decks.txt index 28a0252fff0..af6cf662f75 100644 --- a/forge-gui/res/lists/net-decks.txt +++ b/forge-gui/res/lists/net-decks.txt @@ -33,4 +33,5 @@ Genetic Algorithm AI Decks | https://downloads.cardforge.org/decks/geneticalgori Current Standard Metagame | https://downloads.cardforge.org/decks/currentstandardmetagame.zip Current Modern Metagame | https://downloads.cardforge.org/decks/currentmodernmetagame.zip Current Legacy Metagame | https://downloads.cardforge.org/decks/currentlegacymetagame.zip -Current Pauper Metagame | https://downloads.cardforge.org/decks/currentpaupermetagame.zip \ No newline at end of file +Current Pauper Metagame | https://downloads.cardforge.org/decks/currentpaupermetagame.zip +Current Pioneer Decks | https://downloads.cardforge.org/decks/currentpioneerdecks.zip \ No newline at end of file diff --git a/forge-gui/res/puzzle/PS_ELD1.pzl b/forge-gui/res/puzzle/PS_ELD1.pzl new file mode 100644 index 00000000000..caea4cc1864 --- /dev/null +++ b/forge-gui/res/puzzle/PS_ELD1.pzl @@ -0,0 +1,19 @@ +[metadata] +Name:Possibility Storm - Throne of Eldraine #01 +URL:http://www.possibilitystorm.com/wp-content/uploads/2019/10/132.-ELD1.jpg +Goal:Win +Turns:1 +Difficulty:Rare +Description:Win this turn. You have three cards in your graveyard. +[state] +humanlife=20 +ailife=8 +turn=1 +activeplayer=human +activephase=MAIN1 +humanhand=Irencrag Feat;Charnel Troll;Steelbane Hydra;Festive Funeral;Trollbred Guardian +humangraveyard=Molderhulk;Stomping Ground;Deathless Knight +humanbattlefield=Fires of Invention;Goblin Smuggler;Yorvo, Lord of Garenbrig|Counters:P1P1=8;Vraska, Golgari Queen|Counters:LOYALTY=9;Blood Crypt|NoETBTrigs;Blood Crypt|NoETBTrigs;Blood Crypt|NoETBTrigs;Forest|Set:ELD;Forest|Set:ELD +aibattlefield=Inspiring Veteran +aiprecast=The Circle of Loyalty:TrigToken;The Circle of Loyalty:TrigToken;The Circle of Loyalty:TrigToken;The Circle of Loyalty:TrigToken;The Circle of Loyalty:TrigToken;The Circle of Loyalty:TrigToken +removesummoningsickness=true diff --git a/forge-gui/res/puzzle/PS_ELD2.pzl b/forge-gui/res/puzzle/PS_ELD2.pzl new file mode 100644 index 00000000000..e8d7df4e530 --- /dev/null +++ b/forge-gui/res/puzzle/PS_ELD2.pzl @@ -0,0 +1,16 @@ +[metadata] +Name:Possibility Storm - Throne of Eldraine #02 +URL:http://www.possibilitystorm.com/wp-content/uploads/2019/10/133.-ELD2-1.jpg +Goal:Win +Turns:1 +Difficulty:Uncommon +Description:Win this turn. Your Sentinel's Mark is attached to your Tajic, Legion's Edge, and your opponent's Sentinel Mark is attached to their Harmonious Archon. Neither was cast this turn. Remember that your solution must satisfy all possible blocking scenarios! +[state] +humanlife=20 +ailife=8 +turn=1 +activeplayer=human +activephase=MAIN1 +humanhand=Silverflame Squire;Arrester's Zeal;Burn Bright;Torch Courier +humanbattlefield=Ferocity of the Wilds;Torbran, Thane of Red Fell;Tajic, Legion's Edge|Id:1;Sentinel's Mark|AttachedTo:1;Sacred Foundry|NoETBTrigs;Mountain;Mountain;Plains +aibattlefield=Harmonious Archon|Id:2;Sentinel's Mark|AttachedTo:2;t:Human,P:1,T:1,Cost:no cost,Color:W,Types:Creature-Human,Keywords:,Image:w_1_1_human_eld;t:Human,P:1,T:1,Cost:no cost,Color:W,Types:Creature-Human,Keywords:,Image:w_1_1_human_eld diff --git a/forge-gui/res/puzzle/PS_ELD3.pzl b/forge-gui/res/puzzle/PS_ELD3.pzl new file mode 100644 index 00000000000..9ca10e7e032 --- /dev/null +++ b/forge-gui/res/puzzle/PS_ELD3.pzl @@ -0,0 +1,18 @@ +[metadata] +Name:Possibility Storm - Throne of Eldraine #03 +URL:http://www.possibilitystorm.com/wp-content/uploads/2019/10/134.-ELD3.jpg +Goal:Win +Turns:1 +Difficulty:Mythic +Description:Win this turn. Your opponent owns a Beanstalk Giant in exile. You have a Cryptic Caves in your graveyard. +[state] +humanlife=1 +ailife=7 +turn=1 +activeplayer=human +activephase=MAIN1 +humanhand=Giant Opportunity;Overgrown Tomb;Shepherd of the Flock;Overcome;Outmuscle +humangraveyard=Cryptic Caves +humanbattlefield=Wandermare;Kaya, Orzhov Usurper|Counters:LOYALTY=5;Vengeful Warchief;Trollbred Guardian;Jiang Yanggu, Wildcrafter|Counters:LOYALTY=1;Overgrown Tomb|NoETBTrigs;Overgrown Tomb|NoETBTrigs;Godless Shrine|NoETBTrigs;Godless Shrine|NoETBTrigs +aibattlefield=End-Raze Forerunners;Wardscale Crocodile +aiexile=Beanstalk Giant diff --git a/forge-gui/res/puzzle/PS_ELD4.pzl b/forge-gui/res/puzzle/PS_ELD4.pzl new file mode 100644 index 00000000000..8c0588ab6ea --- /dev/null +++ b/forge-gui/res/puzzle/PS_ELD4.pzl @@ -0,0 +1,20 @@ +[metadata] +Name:Possibility Storm - Throne of Eldraine #04 +URL:http://www.possibilitystorm.com/wp-content/uploads/2019/10/135.-ELD4-1.jpg +Goal:Win +Turns:1 +Difficulty:Uncommon +Description:Win this turn. You have not played a land yet this turn. You own an Animating Faerie "on an adventure" in exile. Note that Bring to Life turned Enchanted Carriage into a 0/0 with four +1/+1 counters. +[state] +humanlife=20 +ailife=10 +humanlandsplayed=0 +turn=1 +activeplayer=human +activephase=MAIN1 +humanhand=Witch's Oven;Island;Taste of Death;Undercity Uprising +humanbattlefield=Wicked Wolf;Oko, Thief of Crowns|Counters:LOYALTY=1;Nullhide Ferox;Enchanted Carriage|Id:1;Breeding Pool|NoETBTrigs;Breeding Pool|NoETBTrigs;Breeding Pool|NoETBTrigs;Watery Grave|NoETBTrigs;Watery Grave|NoETBTrigs +humanexile=Animating Faerie|OnAdventure +aibattlefield=Loyal Pegasus;Gate Colossus;Dawning Angel +humanprecast=Enchanted Carriage:TrigToken;Bring To Life:1->1 +removesummoningsickness=true diff --git a/forge-gui/res/puzzle/PS_ELD5.pzl b/forge-gui/res/puzzle/PS_ELD5.pzl new file mode 100644 index 00000000000..493f35ef902 --- /dev/null +++ b/forge-gui/res/puzzle/PS_ELD5.pzl @@ -0,0 +1,17 @@ +[metadata] +Name:Possibility Storm - Throne of Eldraine #05 +URL:http://www.possibilitystorm.com/wp-content/uploads/2019/11/136.-ELD5.jpg +Goal:Win +Turns:1 +Difficulty:Rare +Description:Win this turn. You own a Smitten Swordmaster "on an adventure" in exile. You chose "Red" with Diamond Knight. Your solution must satisfy all possible opponent decisions/actions. Assume you have 10 life. +[state] +humanlife=10 +ailife=7 +turn=1 +activeplayer=human +activephase=MAIN1 +humanhand=Smitten Swordmaster;Bonecrusher Giant;The Circle of Loyalty;Cavalier of Night +humanbattlefield=Charity Extractor;Diamond Knight|NoETBTrigs|ChosenColor:red;Syr Konrad, the Grim;Jaya, Venerated Firemage|Counters:LOYALTY=1;Tournament Grounds;Tournament Grounds;Swamp;Sacred Foundry|NoETBTrigs;Sacred Foundry|NoETBTrigs +humanexile=Smitten Swordmaster|OnAdventure +aibattlefield=Windstorm Drake|Tapped;Teferi, Time Raveler|Counters:LOYALTY=1;Cerulean Drake;Cerulean Drake;Vindictive Vampire|Id:1;Mantle of Tides|AttachedTo:1 diff --git a/forge-gui/res/quest/world/worlds.txt b/forge-gui/res/quest/world/worlds.txt index 9a71672caec..243a2ff2d5e 100644 --- a/forge-gui/res/quest/world/worlds.txt +++ b/forge-gui/res/quest/world/worlds.txt @@ -1,5 +1,6 @@ Name:Main world Name:Random Standard +Name:Random Pioneer Name:Random Modern Name:Random Commander Name:Amonkhet|Dir:Amonkhet|Sets:AKH, HOU diff --git a/forge-gui/res/skins/darkred/bg_splash.png b/forge-gui/res/skins/darkred/bg_splash.png index 20bf087e1f2..880e3c2068d 100644 Binary files a/forge-gui/res/skins/darkred/bg_splash.png and b/forge-gui/res/skins/darkred/bg_splash.png differ diff --git a/forge-gui/res/skins/darkred/sprite_icons.png b/forge-gui/res/skins/darkred/sprite_icons.png index 2684a130faf..b1e19b256e3 100644 Binary files a/forge-gui/res/skins/darkred/sprite_icons.png and b/forge-gui/res/skins/darkred/sprite_icons.png differ diff --git a/forge-gui/res/skins/default/sprite_border.png b/forge-gui/res/skins/default/sprite_border.png new file mode 100644 index 00000000000..56b4276d8f4 Binary files /dev/null and b/forge-gui/res/skins/default/sprite_border.png differ diff --git a/forge-gui/res/skins/default/sprite_sleeves.png b/forge-gui/res/skins/default/sprite_sleeves.png new file mode 100644 index 00000000000..d6e97d099b8 Binary files /dev/null and b/forge-gui/res/skins/default/sprite_sleeves.png differ diff --git a/forge-gui/res/skins/default/sprite_sleeves2.png b/forge-gui/res/skins/default/sprite_sleeves2.png new file mode 100644 index 00000000000..4916506f01e Binary files /dev/null and b/forge-gui/res/skins/default/sprite_sleeves2.png differ diff --git a/forge-gui/src/main/java/forge/FThreads.java b/forge-gui/src/main/java/forge/FThreads.java index 95f3df74158..e065cf85079 100644 --- a/forge-gui/src/main/java/forge/FThreads.java +++ b/forge-gui/src/main/java/forge/FThreads.java @@ -13,6 +13,8 @@ public class FThreads { * @param mustBeEDT   boolean: true = exception if not EDT, false = exception if EDT */ public static void assertExecutedByEdt(final boolean mustBeEDT) { + if (GuiBase.isNetworkplay()) + return; //don't check for networkplay if (isGuiThread() != mustBeEDT) { final StackTraceElement[] trace = Thread.currentThread().getStackTrace(); final String methodName = trace[2].getClassName() + "." + trace[2].getMethodName(); diff --git a/forge-gui/src/main/java/forge/GuiBase.java b/forge-gui/src/main/java/forge/GuiBase.java index a675dfbdd73..aee6e20dd49 100644 --- a/forge-gui/src/main/java/forge/GuiBase.java +++ b/forge-gui/src/main/java/forge/GuiBase.java @@ -4,6 +4,8 @@ import forge.interfaces.IGuiBase; public class GuiBase { private static IGuiBase guiInterface; + private static boolean propertyConfig = true; + private static boolean networkplay = false; public static IGuiBase getInterface() { return guiInterface; @@ -11,4 +13,16 @@ public class GuiBase { public static void setInterface(IGuiBase i0) { guiInterface = i0; } + public static void enablePropertyConfig(boolean value) { + propertyConfig = value; + } + public static boolean isNetworkplay() { + return networkplay; + } + public static void setNetworkplay(boolean value) { + networkplay = value; + } + public static boolean hasPropertyConfig() { + return propertyConfig; + } } diff --git a/forge-gui/src/main/java/forge/assets/FSkinProp.java b/forge-gui/src/main/java/forge/assets/FSkinProp.java index 0de1c4bc7ac..a2074450960 100644 --- a/forge-gui/src/main/java/forge/assets/FSkinProp.java +++ b/forge-gui/src/main/java/forge/assets/FSkinProp.java @@ -322,6 +322,9 @@ public enum FSkinProp { IMG_ABILITY_HEXPROOF_UB (new int[] {166, 494, 80, 80}, PropType.ABILITY), //token icon IMG_ABILITY_TOKEN (new int[] {330, 494, 80, 80}, PropType.ABILITY), + //border + IMG_BORDER_BLACK (new int[] {2, 2, 672, 936}, PropType.BORDERS), + IMG_BORDER_WHITE (new int[] {676, 2, 672, 936}, PropType.BORDERS), //Protection From IMG_ABILITY_PROTECT_ALL (new int[] {248, 84, 80, 80}, PropType.ABILITY), IMG_ABILITY_PROTECT_B (new int[] {330, 84, 80, 80}, PropType.ABILITY), @@ -374,6 +377,7 @@ public enum FSkinProp { OLD_FOIL, TROPHY, ABILITY, + BORDERS, MANAICONS, PLANAR_CONQUEST, FAVICON diff --git a/forge-gui/src/main/java/forge/card/CardDetailUtil.java b/forge-gui/src/main/java/forge/card/CardDetailUtil.java index da99512137f..8694427ce53 100644 --- a/forge-gui/src/main/java/forge/card/CardDetailUtil.java +++ b/forge-gui/src/main/java/forge/card/CardDetailUtil.java @@ -14,6 +14,7 @@ import forge.item.SealedProduct; import forge.model.FModel; import forge.properties.ForgeConstants; import forge.properties.ForgePreferences; +import forge.util.CardTranslation; import forge.util.Lang; import org.apache.commons.lang3.StringUtils; diff --git a/forge-gui/src/main/java/forge/control/FControlGameEventHandler.java b/forge-gui/src/main/java/forge/control/FControlGameEventHandler.java index d3bdc446df1..6fcf716e1eb 100644 --- a/forge-gui/src/main/java/forge/control/FControlGameEventHandler.java +++ b/forge-gui/src/main/java/forge/control/FControlGameEventHandler.java @@ -38,7 +38,7 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base { private final Set manaPoolUpdate = new HashSet<>(); private final PlayerZoneUpdates zonesUpdate = new PlayerZoneUpdates(); - private boolean processEventsQueued, needPhaseUpdate, needCombatUpdate, needStackUpdate, needPlayerControlUpdate; + private boolean processEventsQueued, needPhaseUpdate, needCombatUpdate, needStackUpdate, needPlayerControlUpdate, refreshFieldUpdate; private boolean gameOver, gameFinished; private PlayerView turnUpdate; @@ -103,6 +103,10 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base { zonesUpdate.clear(); } } + if (refreshFieldUpdate) { + refreshFieldUpdate = false; + matchController.refreshField(); + } if (gameOver) { gameOver = false; humanController.getInputQueue().onGameOver(true); // this will unlock any game threads waiting for inputs to complete @@ -277,6 +281,7 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base { @Override public Void visit(final GameEventCardTapped event) { + refreshFieldUpdate = true; //update all players field when event un/tapped processCard(event.card, cardsUpdate); return processEvent(); } @@ -332,6 +337,8 @@ public class FControlGameEventHandler extends IGameEventVisitor.Base { @Override public Void visit(final GameEventCardChangeZone event) { + if(event.to.getZoneType() == ZoneType.Battlefield) + refreshFieldUpdate = true; //pfps the change to the zones have already been performed with add and remove calls // this is only for playing a sound // updateZone(event.from); diff --git a/forge-gui/src/main/java/forge/deck/CardArchetypeLDAGenerator.java b/forge-gui/src/main/java/forge/deck/CardArchetypeLDAGenerator.java index ddcc82a3e02..53c942a2adf 100644 --- a/forge-gui/src/main/java/forge/deck/CardArchetypeLDAGenerator.java +++ b/forge-gui/src/main/java/forge/deck/CardArchetypeLDAGenerator.java @@ -20,6 +20,7 @@ public final class CardArchetypeLDAGenerator { public static boolean initialize(){ List formatStrings = new ArrayList<>(); formatStrings.add(FModel.getFormats().getStandard().getName()); + formatStrings.add(FModel.getFormats().getPioneer().getName()); formatStrings.add(FModel.getFormats().getModern().getName()); formatStrings.add("Legacy"); formatStrings.add("Vintage"); diff --git a/forge-gui/src/main/java/forge/deck/DeckType.java b/forge-gui/src/main/java/forge/deck/DeckType.java index 83867dc6d50..ba1b8af9e72 100644 --- a/forge-gui/src/main/java/forge/deck/DeckType.java +++ b/forge-gui/src/main/java/forge/deck/DeckType.java @@ -20,6 +20,7 @@ public enum DeckType { QUEST_OPPONENT_DECK("lblQuestOpponentDecks"), COLOR_DECK("lblRandomColorDecks"), STANDARD_CARDGEN_DECK("lblRandomStandardArchetypeDecks"), + PIONEER_CARDGEN_DECK("lblRandomPioneerArchetypeDecks"), MODERN_CARDGEN_DECK("lblRandomModernArchetypeDecks"), LEGACY_CARDGEN_DECK("lblRandomLegacyArchetypeDecks"), VINTAGE_CARDGEN_DECK("lblRandomVintageArchetypeDecks"), @@ -41,6 +42,7 @@ public enum DeckType { DeckType.QUEST_OPPONENT_DECK, DeckType.COLOR_DECK, DeckType.STANDARD_CARDGEN_DECK, + DeckType.PIONEER_CARDGEN_DECK, DeckType.MODERN_CARDGEN_DECK, DeckType.LEGACY_CARDGEN_DECK, DeckType.VINTAGE_CARDGEN_DECK, diff --git a/forge-gui/src/main/java/forge/deck/RandomDeckGenerator.java b/forge-gui/src/main/java/forge/deck/RandomDeckGenerator.java index 8837c75ad1b..fe11a4cd0ea 100644 --- a/forge-gui/src/main/java/forge/deck/RandomDeckGenerator.java +++ b/forge-gui/src/main/java/forge/deck/RandomDeckGenerator.java @@ -104,6 +104,8 @@ public class RandomDeckGenerator extends DeckProxy implements Comparable list); PaperCard chooseCard(String title, String message, List list); int getAvatarCount(); + int getSleevesCount(); void copyToClipboard(String text); void browseToUrl(String url) throws IOException, URISyntaxException; IAudioClip createAudioClip(String filename); diff --git a/forge-gui/src/main/java/forge/interfaces/IGuiGame.java b/forge-gui/src/main/java/forge/interfaces/IGuiGame.java index 9b53c385e45..33c6999dab8 100644 --- a/forge-gui/src/main/java/forge/interfaces/IGuiGame.java +++ b/forge-gui/src/main/java/forge/interfaces/IGuiGame.java @@ -53,6 +53,7 @@ public interface IGuiGame { void updateSingleCard(CardView card); void updateCards(Iterable cards); void refreshCardDetails(Iterable cards); + void refreshField(); void updateManaPool(Iterable manaPoolUpdate); void updateLives(Iterable livesUpdate); void setPanelSelection(CardView hostCard); @@ -160,6 +161,8 @@ public interface IGuiGame { void setSelectables(final Iterable cards); void clearSelectables(); boolean isSelecting(); + boolean isGamePaused(); + public void setgamePause(boolean pause); void awaitNextInput(); void cancelAwaitNextInput(); diff --git a/forge-gui/src/main/java/forge/match/AbstractGuiGame.java b/forge-gui/src/main/java/forge/match/AbstractGuiGame.java index c906151501c..0e571e8c99a 100644 --- a/forge-gui/src/main/java/forge/match/AbstractGuiGame.java +++ b/forge-gui/src/main/java/forge/match/AbstractGuiGame.java @@ -9,6 +9,7 @@ import java.util.Set; import java.util.Timer; import java.util.TimerTask; +import forge.GuiBase; import forge.util.Localizer; import org.apache.commons.lang3.StringUtils; @@ -37,6 +38,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards { private IGameController spectator = null; private final Map gameControllers = Maps.newHashMap(); private final Map originalGameControllers = Maps.newHashMap(); + private boolean gamePause = false; public final boolean hasLocalPlayers() { return !gameControllers.isEmpty(); @@ -58,7 +60,16 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards { public final void setCurrentPlayer(PlayerView player) { player = TrackableTypes.PlayerViewType.lookup(player); //ensure we use the correct player - if (!gameControllers.containsKey(player)) { + if (hasLocalPlayers() && !isLocalPlayer(player)) { //add check if gameControllers is not empty + if(GuiBase.getInterface().isLibgdxPort()){//spectator is registered as localplayer bug on ai vs ai (after . + if (spectator != null){ //human vs ai game), then it loses "control" when you watch ai vs ai, + currentPlayer = null; //again, and vice versa, This is to prevent throwing error, lose control, + updateCurrentPlayer(null); //workaround fix on mayviewcards below is needed or it will bug the UI.. + gameControllers.clear(); + return; + } + } + throw new IllegalArgumentException(); } @@ -158,13 +169,32 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards { //not needed for base game implementation } + @Override + public void refreshField() { + //not needed for base game implementation + } + @Override public boolean mayView(final CardView c) { if (!hasLocalPlayers()) { return true; //if not in game, card can be shown } - if (getGameController().mayLookAtAllCards()) { - return true; + if(GuiBase.getInterface().isLibgdxPort()){ + if(spectator!=null) { //workaround fix!! this is needed on above code or it will + gameControllers.remove(spectator); //bug the UI! remove spectator here since its must not be here... + return true; + } + try{ + if (getGameController().mayLookAtAllCards()) { // when it bugged here, the game thinks the spectator (null) + return true; // is the humancontroller here (maybe because there is an existing game thread???) + } + } catch (NullPointerException e){ + return true; // return true so it will work as normal + } + } else { + if (getGameController().mayLookAtAllCards()) { + return true; + } } return c.canBeShownToAny(getLocalPlayers()); } @@ -232,6 +262,8 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards { public boolean isSelecting() { return !selectableCards.isEmpty(); } + public boolean isGamePaused() { return gamePause; } + public void setgamePause(boolean pause) { gamePause = pause; } /** Concede game, bring up WinLose UI. */ public boolean concede() { @@ -266,6 +298,8 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards { if (showConfirmDialog(Localizer.getInstance().getMessage("lblCloseGameSpectator"), Localizer.getInstance().getMessage("lblCloseGame"), Localizer.getInstance().getMessage("lblClose"), Localizer.getInstance().getMessage("lblCancel"))) { IGameController controller = spectator; spectator = null; //ensure we don't prompt again, including when calling nextGameDecision below + if (!isGamePaused()) + controller.selectButtonOk(); //pause controller.nextGameDecision(NextGameDecision.QUIT); } return false; //let logic above handle closing current screen diff --git a/forge-gui/src/main/java/forge/match/GameLobby.java b/forge-gui/src/main/java/forge/match/GameLobby.java index 6f9bfd78659..7e747c3e0e0 100644 --- a/forge-gui/src/main/java/forge/match/GameLobby.java +++ b/forge-gui/src/main/java/forge/match/GameLobby.java @@ -158,7 +158,7 @@ public abstract class GameLobby implements IHasGameType { public void addSlot() { final int newIndex = getNumberOfSlots(); final LobbySlotType type = allowNetworking ? LobbySlotType.OPEN : LobbySlotType.AI; - addSlot(new LobbySlot(type, null, newIndex, newIndex, false, !allowNetworking, Collections.emptySet())); + addSlot(new LobbySlot(type, null, newIndex, newIndex, newIndex, false, !allowNetworking, Collections.emptySet())); } protected final void addSlot(final LobbySlot slot) { if (slot == null) { @@ -198,6 +198,15 @@ public abstract class GameLobby implements IHasGameType { } return result; } + protected final static int[] localSleeveIndices() { + final String[] sSleeves = FModel.getPreferences().getPref(FPref.UI_SLEEVES).split(","); + final int[] result = new int[sSleeves.length]; + for (int i = 0; i < sSleeves.length; i++) { + final Integer val = Ints.tryParse(sSleeves[i]); + result[i] = val == null ? -1 : val.intValue(); + } + return result; + } public void removeSlot(final int index) { if (index < 0 || index >= data.slots.size()) { @@ -415,6 +424,7 @@ public abstract class GameLobby implements IHasGameType { final IGuiGame gui = getGui(data.slots.indexOf(slot)); final String name = slot.getName(); final int avatar = slot.getAvatarIndex(); + final int sleeve = slot.getSleeveIndex(); final boolean isArchenemy = slot.isArchenemy(); final int team = GameType.Archenemy.equals(currentGameType) && !isArchenemy ? 1 : slot.getTeam(); final Set aiOptions = slot.getAiOptions(); @@ -422,7 +432,7 @@ public abstract class GameLobby implements IHasGameType { final boolean isAI = slot.getType() == LobbySlotType.AI; final LobbyPlayer lobbyPlayer; if (isAI) { - lobbyPlayer = GamePlayerUtil.createAiPlayer(name, avatar, aiOptions); + lobbyPlayer = GamePlayerUtil.createAiPlayer(name, avatar, sleeve, aiOptions); } else { boolean setNameNow = false; @@ -430,7 +440,7 @@ public abstract class GameLobby implements IHasGameType { setNameNow = true; hasNameBeenSet = true; } - lobbyPlayer = GamePlayerUtil.getGuiPlayer(name, avatar, setNameNow); + lobbyPlayer = GamePlayerUtil.getGuiPlayer(name, avatar, sleeve, setNameNow); } Deck deck = slot.getDeck(); diff --git a/forge-gui/src/main/java/forge/match/HostedMatch.java b/forge-gui/src/main/java/forge/match/HostedMatch.java index 5d82270821c..4c71ebea9ce 100644 --- a/forge-gui/src/main/java/forge/match/HostedMatch.java +++ b/forge-gui/src/main/java/forge/match/HostedMatch.java @@ -158,6 +158,7 @@ public class HostedMatch { final FCollectionView players = game.getPlayers(); final String[] avatarIndices = FModel.getPreferences().getPref(FPref.UI_AVATARS).split(","); + final String[] sleeveIndices = FModel.getPreferences().getPref(FPref.UI_SLEEVES).split(","); final GameView gameView = getGameView(); humanCount = 0; @@ -175,6 +176,16 @@ public class HostedMatch { } } p.updateAvatar(); + //sleeve + p.getLobbyPlayer().setSleeveIndex(rp.getPlayer().getSleeveIndex()); + if (p.getLobbyPlayer().getSleeveIndex() == -1) { + if (iPlayer < sleeveIndices.length) { + p.getLobbyPlayer().setSleeveIndex(Integer.parseInt(sleeveIndices[iPlayer])); + } else { + p.getLobbyPlayer().setSleeveIndex(0); + } + } + p.updateSleeve(); if (p.getController() instanceof PlayerControllerHuman) { final PlayerControllerHuman humanController = (PlayerControllerHuman) p.getController(); @@ -205,13 +216,7 @@ public class HostedMatch { final IGuiGame gui = GuiBase.getInterface().getNewGuiGame(); gui.setGameView(null); //clear the view so when the game restarts again, it updates correctly gui.setGameView(gameView); - - final PlayerControllerHuman humanController = new WatchLocalGame(game, new LobbyPlayerHuman("Spectator"), gui); - game.subscribeToEvents(new FControlGameEventHandler(humanController)); - humanControllers.add(humanController); - gui.setSpectator(humanController); - - gui.openView(null); + registerSpectator(gui, new WatchLocalGame(game, new LobbyPlayerHuman("Spectator"), gui)); } //prompt user for player one name if needed @@ -265,9 +270,12 @@ public class HostedMatch { public void registerSpectator(final IGuiGame gui) { final PlayerControllerHuman humanController = new WatchLocalGame(game, null, gui); + registerSpectator(gui, humanController); + } + + public void registerSpectator(final IGuiGame gui, final PlayerControllerHuman humanController) { gui.setSpectator(humanController); gui.openView(null); - game.subscribeToEvents(new FControlGameEventHandler(humanController)); humanControllers.add(humanController); } diff --git a/forge-gui/src/main/java/forge/match/LobbySlot.java b/forge-gui/src/main/java/forge/match/LobbySlot.java index bd33cff83e9..e7c97666f53 100644 --- a/forge-gui/src/main/java/forge/match/LobbySlot.java +++ b/forge-gui/src/main/java/forge/match/LobbySlot.java @@ -15,6 +15,7 @@ public final class LobbySlot implements Serializable { private LobbySlotType type; private String name; private int avatarIndex; + private int sleeveIndex; private int team; private boolean isArchenemy; private boolean isReady; @@ -22,10 +23,11 @@ public final class LobbySlot implements Serializable { private Deck deck; private ImmutableSet aiOptions; - public LobbySlot(final LobbySlotType type, final String name, final int avatarIndex, final int team, final boolean isArchenemy, final boolean isReady, final Set aiOptions) { + public LobbySlot(final LobbySlotType type, final String name, final int avatarIndex, final int sleeveIndex, final int team, final boolean isArchenemy, final boolean isReady, final Set aiOptions) { this.type = type; this.name = name; this.avatarIndex = avatarIndex; + this.sleeveIndex = sleeveIndex; this.team = team; this.isArchenemy = isArchenemy; this.isReady = isReady; @@ -47,6 +49,10 @@ public final class LobbySlot implements Serializable { setAvatarIndex(data.getAvatarIndex()); changed = true; } + if (data.getSleeveIndex() != -1) { + setSleeveIndex(data.getSleeveIndex()); + changed = true; + } if (data.getTeam() != -1) { setTeam(data.getTeam()); changed = true; @@ -93,9 +99,15 @@ public final class LobbySlot implements Serializable { public int getAvatarIndex() { return avatarIndex; } + public int getSleeveIndex() { + return sleeveIndex; + } public void setAvatarIndex(final int avatarIndex) { this.avatarIndex = avatarIndex; } + public void setSleeveIndex(final int sleeveIndex) { + this.sleeveIndex = sleeveIndex; + } public int getTeam() { return team; diff --git a/forge-gui/src/main/java/forge/match/LocalLobby.java b/forge-gui/src/main/java/forge/match/LocalLobby.java index f8fa6f7a8e7..bb8c348f6a6 100644 --- a/forge-gui/src/main/java/forge/match/LocalLobby.java +++ b/forge-gui/src/main/java/forge/match/LocalLobby.java @@ -13,11 +13,12 @@ public final class LocalLobby extends GameLobby { final String humanName = localName(); final int[] avatarIndices = localAvatarIndices(); + final int[] sleeveIndices = localSleeveIndices(); - final LobbySlot slot0 = new LobbySlot(LobbySlotType.LOCAL, humanName, avatarIndices[0], 0, true, true, Collections.emptySet()); + final LobbySlot slot0 = new LobbySlot(LobbySlotType.LOCAL, humanName, avatarIndices[0], sleeveIndices[0],0, true, true, Collections.emptySet()); addSlot(slot0); - final LobbySlot slot1 = new LobbySlot(LobbySlotType.AI, null, avatarIndices[1], 1, false, true, Collections.emptySet()); + final LobbySlot slot1 = new LobbySlot(LobbySlotType.AI, null, avatarIndices[1], sleeveIndices[1],1, false, true, Collections.emptySet()); addSlot(slot1); } diff --git a/forge-gui/src/main/java/forge/match/input/InputPassPriority.java b/forge-gui/src/main/java/forge/match/input/InputPassPriority.java index adff270db60..8db90702482 100644 --- a/forge-gui/src/main/java/forge/match/input/InputPassPriority.java +++ b/forge-gui/src/main/java/forge/match/input/InputPassPriority.java @@ -30,6 +30,7 @@ import forge.player.GamePlayerUtil; import forge.player.PlayerControllerHuman; import forge.properties.ForgePreferences.FPref; import forge.util.ITriggerEvent; +import forge.util.Localizer; import forge.util.ThreadUtil; /** @@ -55,11 +56,12 @@ public class InputPassPriority extends InputSyncronizedBase { public final void showMessage() { showMessage(getTurnPhasePriorityMessage(getController().getGame())); chosenSa = null; + Localizer localizer = Localizer.getInstance(); if (getController().canUndoLastAction()) { //allow undoing with cancel button if can undo last action - getController().getGui().updateButtons(getOwner(), "OK", "Undo", true, true, true); + getController().getGui().updateButtons(getOwner(), localizer.getMessage("lblOK"), localizer.getMessage("lblUndo"), true, true, true); } else { //otherwise allow ending turn with cancel button - getController().getGui().updateButtons(getOwner(), "OK", "End Turn", true, true, true); + getController().getGui().updateButtons(getOwner(), localizer.getMessage("lblOK"), localizer.getMessage("lblEndTurn"), true, true, true); } getController().getGui().alertUser(); @@ -106,11 +108,12 @@ public class InputPassPriority extends InputSyncronizedBase { ThreadUtil.invokeInGameThread(new Runnable() { //must invoke in game thread so dialog can be shown on mobile game @Override public void run() { - String message = "You have mana floating in your mana pool that could be lost if you pass priority now."; + Localizer localizer = Localizer.getInstance(); + String message = localizer.getMessage("lblYouHaveManaFloatingInYourManaPoolCouldBeLostIfPassPriority"); if (FModel.getPreferences().getPrefBoolean(FPref.UI_MANABURN)) { - message += " You will take mana burn damage equal to the amount of floating mana lost this way."; + message += " " + localizer.getMessage("lblYouWillTakeManaBurnDamageEqualAmountFloatingManaLostThisWay"); } - if (getController().getGui().showConfirmDialog(message, "Mana Floating", "Ok", "Cancel")) { + if (getController().getGui().showConfirmDialog(message, localizer.getMessage("lblManaFloating"), localizer.getMessage("lblOk"), localizer.getMessage("lblCancel"))) { runnable.run(); } } @@ -161,12 +164,12 @@ public class InputPassPriority extends InputSyncronizedBase { } final SpellAbility sa = abilities.get(0); if (sa.isSpell()) { - return "cast spell"; + return Localizer.getInstance().getMessage("lblCastSpell"); } if (sa instanceof LandAbility) { - return "play land"; + return Localizer.getInstance().getMessage("lblPlayLand"); } - return "activate ability"; + return Localizer.getInstance().getMessage("lblActivateAbility"); } @Override diff --git a/forge-gui/src/main/java/forge/match/input/InputPayMana.java b/forge-gui/src/main/java/forge/match/input/InputPayMana.java index 21dfe05227d..de1da8bf5b6 100644 --- a/forge-gui/src/main/java/forge/match/input/InputPayMana.java +++ b/forge-gui/src/main/java/forge/match/input/InputPayMana.java @@ -1,13 +1,10 @@ package forge.match.input; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Queue; +import java.util.*; import forge.GuiBase; import forge.game.GameActionUtil; +import forge.game.ability.AbilityKey; import forge.game.spellability.SpellAbilityView; import forge.util.TextUtil; import org.apache.commons.lang3.StringUtils; @@ -363,11 +360,11 @@ public abstract class InputPayMana extends InputSyncronizedBase { final Card source = am.getHostCard(); final Player activator = am.getActivatingPlayer(); final Game g = source.getGame(); - final HashMap repParams = new HashMap<>(); - repParams.put("Mana", m.getOrigProduced()); - repParams.put("Affected", source); - repParams.put("Player", activator); - repParams.put("AbilityMana", am); + final Map repParams = AbilityKey.newMap(); + repParams.put(AbilityKey.Mana, m.getOrigProduced()); + repParams.put(AbilityKey.Affected, source); + repParams.put(AbilityKey.Player, activator); + repParams.put(AbilityKey.AbilityMana, am); for (final Player p : g.getPlayers()) { for (final Card crd : p.getAllCards()) { diff --git a/forge-gui/src/main/java/forge/match/input/InputPayManaOfCostPayment.java b/forge-gui/src/main/java/forge/match/input/InputPayManaOfCostPayment.java index bbdc363952c..a3828e5370d 100644 --- a/forge-gui/src/main/java/forge/match/input/InputPayManaOfCostPayment.java +++ b/forge-gui/src/main/java/forge/match/input/InputPayManaOfCostPayment.java @@ -1,9 +1,5 @@ package forge.match.input; -import java.util.List; - -import com.google.common.collect.Lists; - import forge.card.mana.ManaAtom; import forge.card.mana.ManaCostShard; import forge.game.card.Card; @@ -15,7 +11,7 @@ import forge.model.FModel; import forge.player.PlayerControllerHuman; import forge.properties.ForgePreferences; import forge.util.ITriggerEvent; -import forge.util.Lang; +import forge.util.Localizer; public class InputPayManaOfCostPayment extends InputPayMana { public InputPayManaOfCostPayment(final PlayerControllerHuman controller, ManaCostBeingPaid cost, SpellAbility spellAbility, Player payer, ManaConversionMatrix matrix) { @@ -64,6 +60,7 @@ public class InputPayManaOfCostPayment extends InputPayMana { protected String getMessage() { final String displayMana = manaCost.toString(false, player.getManaPool()); final StringBuilder msg = new StringBuilder(); + final Localizer localizer = Localizer.getInstance(); applyMatrix(); @@ -78,26 +75,22 @@ public class InputPayManaOfCostPayment extends InputPayMana { msg.append(saPaidFor.getHostCard()).append(" - ").append(saPaidFor.toString()).append("\n\n"); } } - msg.append("Pay Mana Cost: ").append(displayMana); + msg.append(localizer.getMessage("lblPayManaCost")).append(" ").append(displayMana); if (this.phyLifeToLose > 0) { - msg.append(" ("); - msg.append(this.phyLifeToLose); - msg.append(" life paid for phyrexian mana)"); + msg.append(" ").append(String.format(localizer.getMessage("lblLifePaidForPhyrexianMana"), this.phyLifeToLose)); } boolean isLifeInsteadBlack = player.hasKeyword("PayLifeInsteadOf:B") && manaCost.hasAnyKind(ManaAtom.BLACK); if (manaCost.containsPhyrexianMana() || isLifeInsteadBlack) { StringBuilder sb = new StringBuilder(); - sb.append("Click on your life total to pay life for "); - List list = Lists.newArrayList(); - if (manaCost.containsPhyrexianMana()) { - list.add("phyrexian mana"); + if (manaCost.containsPhyrexianMana() && !isLifeInsteadBlack) { + sb.append(localizer.getMessage("lblClickOnYourLifeTotalToPayLifeForPhyrexianMana")); + } else if (!manaCost.containsPhyrexianMana() && isLifeInsteadBlack) { + sb.append(localizer.getMessage("lblClickOnYourLifeTotalToPayLifeForBlackMana")); + } else if (manaCost.containsPhyrexianMana() && isLifeInsteadBlack) { + sb.append(localizer.getMessage("lblClickOnYourLifeTotalToPayLifeForPhyrexianOrBlackMana")); } - if (isLifeInsteadBlack) { - list.add("black mana"); - } - sb.append(Lang.joinHomogenous(list, null, "or")).append("."); msg.append("\n(").append(sb).append(")"); } diff --git a/forge-gui/src/main/java/forge/match/input/InputPayManaSimple.java b/forge-gui/src/main/java/forge/match/input/InputPayManaSimple.java index ea536eb9c1f..1f8be1adb47 100644 --- a/forge-gui/src/main/java/forge/match/input/InputPayManaSimple.java +++ b/forge-gui/src/main/java/forge/match/input/InputPayManaSimple.java @@ -17,10 +17,6 @@ */ package forge.match.input; -import java.util.List; - -import com.google.common.collect.Lists; - import forge.card.mana.ManaAtom; import forge.card.mana.ManaCost; import forge.card.mana.ManaCostShard; @@ -33,7 +29,7 @@ import forge.model.FModel; import forge.player.PlayerControllerHuman; import forge.properties.ForgePreferences; import forge.util.ITriggerEvent; -import forge.util.Lang; +import forge.util.Localizer; //pays the cost of a card played from the player's hand //the card is removed from the players hand if the cost is paid @@ -136,29 +132,26 @@ public class InputPayManaSimple extends InputPayMana { @Override protected String getMessage() { final StringBuilder msg = new StringBuilder(); + final Localizer localizer = Localizer.getInstance(); if (FModel.getPreferences().getPrefBoolean(ForgePreferences.FPref.UI_DETAILED_SPELLDESC_IN_PROMPT)) { msg.append(saPaidFor.getStackDescription().replace("(Targeting ERROR)", "")).append("\n\n"); } - msg.append("Pay Mana Cost: ").append(this.manaCost.toString(false, player.getManaPool())); + msg.append(localizer.getMessage("lblPayManaCost")).append(" ").append(this.manaCost.toString(false, player.getManaPool())); if (this.phyLifeToLose > 0) { - msg.append(" ("); - msg.append(this.phyLifeToLose); - msg.append(" life paid for phyrexian mana)"); + msg.append(" ").append(String.format(localizer.getMessage("lblLifePaidForPhyrexianMana"), this.phyLifeToLose)); } boolean isLifeInsteadBlack = player.hasKeyword("PayLifeInsteadOf:B") && manaCost.hasAnyKind(ManaAtom.BLACK); if (manaCost.containsPhyrexianMana() || isLifeInsteadBlack) { StringBuilder sb = new StringBuilder(); - sb.append("Click on your life total to pay life for "); - List list = Lists.newArrayList(); - if (manaCost.containsPhyrexianMana()) { - list.add("phyrexian mana"); + if (manaCost.containsPhyrexianMana() && !isLifeInsteadBlack) { + sb.append(localizer.getMessage("lblClickOnYourLifeTotalToPayLifeForPhyrexianMana")); + } else if (!manaCost.containsPhyrexianMana() && isLifeInsteadBlack) { + sb.append(localizer.getMessage("lblClickOnYourLifeTotalToPayLifeForBlackMana")); + } else if (manaCost.containsPhyrexianMana() && isLifeInsteadBlack) { + sb.append(localizer.getMessage("lblClickOnYourLifeTotalToPayLifeForPhyrexianOrBlackMana")); } - if (isLifeInsteadBlack) { - list.add("black mana"); - } - sb.append(Lang.joinHomogenous(list, null, "or")).append("."); msg.append("\n(").append(sb).append(")"); } diff --git a/forge-gui/src/main/java/forge/match/input/InputPlaybackControl.java b/forge-gui/src/main/java/forge/match/input/InputPlaybackControl.java index c7f6f763ab7..fd01edfe5bf 100644 --- a/forge-gui/src/main/java/forge/match/input/InputPlaybackControl.java +++ b/forge-gui/src/main/java/forge/match/input/InputPlaybackControl.java @@ -48,6 +48,7 @@ public class InputPlaybackControl extends InputSyncronizedBase { } else { getController().getGui().updateButtons(null, "Pause", isFast ? "1x Speed" : "10x Faster", true, true, true); } + getController().getGui().setgamePause(isPaused); } public void pause() { diff --git a/forge-gui/src/main/java/forge/model/FModel.java b/forge-gui/src/main/java/forge/model/FModel.java index d1732ab280b..27d0060413c 100644 --- a/forge-gui/src/main/java/forge/model/FModel.java +++ b/forge-gui/src/main/java/forge/model/FModel.java @@ -24,7 +24,6 @@ import forge.CardStorageReader.ProgressObserver; import forge.achievement.*; import forge.ai.AiProfileUtil; import forge.card.CardPreferences; -import forge.card.CardTranslation; import forge.card.CardType; import forge.deck.CardArchetypeLDAGenerator; import forge.deck.CardRelationMatrixGenerator; @@ -49,6 +48,7 @@ import forge.quest.QuestController; import forge.quest.QuestWorld; import forge.quest.data.QuestPreferences; import forge.tournament.TournamentData; +import forge.util.CardTranslation; import forge.util.FileUtil; import forge.util.Localizer; import forge.util.storage.IStorage; @@ -147,7 +147,7 @@ public final class FModel { final CardStorageReader tokenReader = new CardStorageReader(ForgeConstants.TOKEN_DATA_DIR, progressBarBridge, FModel.getPreferences().getPrefBoolean(FPref.LOAD_CARD_SCRIPTS_LAZILY)); magicDb = new StaticData(reader, tokenReader, ForgeConstants.EDITIONS_DIR, ForgeConstants.BLOCK_DATA_DIR); - CardTranslation.preloadTranslation(preferences.getPref(FPref.UI_LANGUAGE)); + CardTranslation.preloadTranslation(preferences.getPref(FPref.UI_LANGUAGE), ForgeConstants.LANG_DIR); //create profile dirs if they don't already exist for (final String dname : ForgeConstants.PROFILE_DIRS) { @@ -168,6 +168,7 @@ public final class FModel { new File(ForgeConstants.USER_FORMATS_DIR), preferences.getPrefBoolean(FPref.LOAD_HISTORIC_FORMATS))); magicDb.setStandardPredicate(formats.getStandard().getFilterRules()); + magicDb.setPioneerPredicate(formats.getPioneer().getFilterRules()); magicDb.setModernPredicate(formats.getModern().getFilterRules()); magicDb.setCommanderPredicate(formats.get("Commander").getFilterRules()); magicDb.setOathbreakerPredicate(formats.get("Oathbreaker").getFilterRules()); diff --git a/forge-gui/src/main/java/forge/net/CustomObjectDecoder.java b/forge-gui/src/main/java/forge/net/CustomObjectDecoder.java new file mode 100644 index 00000000000..47d898769d4 --- /dev/null +++ b/forge-gui/src/main/java/forge/net/CustomObjectDecoder.java @@ -0,0 +1,58 @@ +package forge.net; + +import forge.GuiBase; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.LengthFieldBasedFrameDecoder; +import io.netty.handler.codec.serialization.ClassResolver; +import org.mapdb.elsa.ElsaObjectInputStream; + +import java.io.ObjectInputStream; + +public class CustomObjectDecoder extends LengthFieldBasedFrameDecoder { + private final ClassResolver classResolver; + + public CustomObjectDecoder(ClassResolver classResolver) { + this(1048576, classResolver); + } + + public CustomObjectDecoder(int maxObjectSize, ClassResolver classResolver) { + super(maxObjectSize, 0, 4, 0, 4); + this.classResolver = classResolver; + } + + protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception { + ByteBuf frame = (ByteBuf) super.decode(ctx, in); + if (frame == null) { + return null; + } else { + if (GuiBase.hasPropertyConfig()){ + ElsaObjectInputStream ois = new ElsaObjectInputStream(new ByteBufInputStream(frame, true)); + + Object var5; + try { + var5 = ois.readObject(); + } finally { + ois.close(); + } + + return var5; + } + else { + ObjectInputStream ois = new ObjectInputStream(new ByteBufInputStream(frame, true)); + + Object var5; + try { + var5 = ois.readObject(); + } finally { + ois.close(); + } + + return var5; + } + } + } + + public static int maxObjectsize = 10000000; //10megabyte??? +} diff --git a/forge-gui/src/main/java/forge/net/CustomObjectEncoder.java b/forge-gui/src/main/java/forge/net/CustomObjectEncoder.java new file mode 100644 index 00000000000..58dc82a58fb --- /dev/null +++ b/forge-gui/src/main/java/forge/net/CustomObjectEncoder.java @@ -0,0 +1,56 @@ +package forge.net; + +import forge.GuiBase; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufOutputStream; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; +import org.mapdb.elsa.ElsaObjectOutputStream; + +import java.io.ObjectOutputStream; +import java.io.Serializable; + +public class CustomObjectEncoder extends MessageToByteEncoder { + private static final byte[] LENGTH_PLACEHOLDER = new byte[4]; + + public CustomObjectEncoder() { + } + + protected void encode(ChannelHandlerContext ctx, Serializable msg, ByteBuf out) throws Exception { + int startIdx = out.writerIndex(); + ByteBufOutputStream bout = new ByteBufOutputStream(out); + + if (GuiBase.hasPropertyConfig()){ + ElsaObjectOutputStream oout = null; + try { + bout.write(LENGTH_PLACEHOLDER); + oout = new ElsaObjectOutputStream(bout); + oout.writeObject(msg); + oout.flush(); + } finally { + if (oout != null) { + oout.close(); + } else { + bout.close(); + } + } + } else { + ObjectOutputStream oout = null; + try { + bout.write(LENGTH_PLACEHOLDER); + oout = new ObjectOutputStream(bout); + oout.writeObject(msg); + oout.flush(); + } finally { + if (oout != null) { + oout.close(); + } else { + bout.close(); + } + } + } + + int endIdx = out.writerIndex(); + out.setInt(startIdx, endIdx - startIdx - 4); + } +} diff --git a/forge-gui/src/main/java/forge/net/OfflineLobby.java b/forge-gui/src/main/java/forge/net/OfflineLobby.java index e8827558e1a..392c8a880ca 100644 --- a/forge-gui/src/main/java/forge/net/OfflineLobby.java +++ b/forge-gui/src/main/java/forge/net/OfflineLobby.java @@ -14,11 +14,12 @@ public final class OfflineLobby extends GameLobby { final String humanName = localName(); final int[] avatarIndices = localAvatarIndices(); + final int[] sleeveIndices = localSleeveIndices(); - final LobbySlot slot0 = new LobbySlot(LobbySlotType.LOCAL, humanName, avatarIndices[0], 0, true, false, Collections.emptySet()); + final LobbySlot slot0 = new LobbySlot(LobbySlotType.LOCAL, humanName, avatarIndices[0], sleeveIndices[0], 0, true, false, Collections.emptySet()); addSlot(slot0); - final LobbySlot slot1 = new LobbySlot(LobbySlotType.OPEN, null, -1, -1, false, false, Collections.emptySet()); + final LobbySlot slot1 = new LobbySlot(LobbySlotType.OPEN, null, -1, -1,-1, false, false, Collections.emptySet()); addSlot(slot1); } diff --git a/forge-gui/src/main/java/forge/net/ProtocolMethod.java b/forge-gui/src/main/java/forge/net/ProtocolMethod.java index e220668832f..254ac09a3c5 100644 --- a/forge-gui/src/main/java/forge/net/ProtocolMethod.java +++ b/forge-gui/src/main/java/forge/net/ProtocolMethod.java @@ -9,6 +9,7 @@ import java.util.Map; import com.google.common.base.Function; +import forge.GuiBase; import forge.assets.FSkinProp; import forge.deck.CardPool; import forge.game.GameEntityView; @@ -65,11 +66,14 @@ public enum ProtocolMethod { confirm (Mode.SERVER, Boolean.TYPE, CardView.class, String.class, Boolean.TYPE, List/*String*/.class), getChoices (Mode.SERVER, List.class, String.class, Integer.TYPE, Integer.TYPE, List.class, Object.class, Function.class), order (Mode.SERVER, List.class, String.class, String.class, Integer.TYPE, Integer.TYPE, List.class, List.class, CardView.class, Boolean.TYPE), - sideboard (Mode.SERVER, List.class, CardPool.class, CardPool.class), + sideboard (Mode.SERVER, List.class, CardPool.class, CardPool.class, String.class), chooseSingleEntityForEffect(Mode.SERVER, GameEntityView.class, String.class, List.class, DelayedReveal.class, Boolean.TYPE), chooseEntitiesForEffect(Mode.SERVER, GameEntityView.class, String.class, List.class, Integer.TYPE, Integer.TYPE, DelayedReveal.class), manipulateCardList (Mode.SERVER, List.class, String.class, Iterable.class, Iterable.class, Boolean.TYPE, Boolean.TYPE, Boolean.TYPE), setCard (Mode.SERVER, Void.TYPE, CardView.class), + setSelectables (Mode.SERVER, Void.TYPE, Iterable/*CardView*/.class), + clearSelectables (Mode.SERVER), + refreshField (Mode.SERVER), // TODO case "setPlayerAvatar": openZones (Mode.SERVER, Boolean.TYPE, Collection/*ZoneType*/.class, Map/*PlayerView,Object*/.class), restoreOldZones (Mode.SERVER, Void.TYPE, Map/*PlayerView,Object*/.class), @@ -155,11 +159,22 @@ public enum ProtocolMethod { } public void checkArgs(final Object[] args) { + if (GuiBase.hasPropertyConfig()) + return; //uses custom serializer for Android 8+.. for (int iArg = 0; iArg < args.length; iArg++) { - final Object arg = args[iArg]; - final Class type = this.args[iArg]; - if (!ReflectionUtil.isInstance(arg, type)) { - throw new InternalError(String.format("Protocol method %s: illegal argument (%d) of type %s, %s expected", name(), iArg, arg.getClass().getName(), type.getName())); + Object arg = null; + Class type = null; + try { + arg = args[iArg]; + if (this.args.length > iArg) + type = this.args[iArg]; + } + catch (ArrayIndexOutOfBoundsException ex){ ex.printStackTrace(); } + catch(ConcurrentModificationException ex) { ex.printStackTrace(); } + if (arg != null) + if (type != null) + if (!ReflectionUtil.isInstance(arg, type)) { + throw new InternalError(String.format("Protocol method %s: illegal argument (%d) of type %s, %s expected", name(), iArg, arg.getClass().getName(), type.getName())); } if (arg != null) { // attempt to Serialize each argument, this will throw an exception if it can't. diff --git a/forge-gui/src/main/java/forge/net/client/FGameClient.java b/forge-gui/src/main/java/forge/net/client/FGameClient.java index 7a0f563730d..148118df536 100644 --- a/forge-gui/src/main/java/forge/net/client/FGameClient.java +++ b/forge-gui/src/main/java/forge/net/client/FGameClient.java @@ -1,5 +1,7 @@ package forge.net.client; +import forge.net.CustomObjectDecoder; +import forge.net.CustomObjectEncoder; import io.netty.bootstrap.Bootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; @@ -12,8 +14,6 @@ import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.serialization.ClassResolvers; -import io.netty.handler.codec.serialization.ObjectDecoder; -import io.netty.handler.codec.serialization.ObjectEncoder; import java.util.List; import java.util.concurrent.TimeoutException; @@ -58,8 +58,8 @@ public class FGameClient implements IToServer { public void initChannel(final SocketChannel ch) throws Exception { final ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast( - new ObjectEncoder(), - new ObjectDecoder(ClassResolvers.cacheDisabled(null)), + new CustomObjectEncoder(), + new CustomObjectDecoder(CustomObjectDecoder.maxObjectsize, ClassResolvers.cacheDisabled(null)), new MessageHandler(), new LobbyUpdateHandler(), new GameClientHandler(FGameClient.this)); diff --git a/forge-gui/src/main/java/forge/net/client/GameClientHandler.java b/forge-gui/src/main/java/forge/net/client/GameClientHandler.java index 30d977378a1..094123fe56a 100644 --- a/forge-gui/src/main/java/forge/net/client/GameClientHandler.java +++ b/forge-gui/src/main/java/forge/net/client/GameClientHandler.java @@ -198,7 +198,8 @@ final class GameClientHandler extends GameProtocolHandler { ); LobbyPlayer lobbyPlayer = new LobbyPlayerHuman( playerSlot.getName(), - playerSlot.getAvatarIndex() + playerSlot.getAvatarIndex(), + playerSlot.getSleeveIndex() ); player.setPlayer(lobbyPlayer); player.setTeamNumber(playerSlot.getTeam()); @@ -287,7 +288,7 @@ final class GameClientHandler extends GameProtocolHandler { @Override public void channelActive(final ChannelHandlerContext ctx) { // Don't use send() here, as this.channel is not yet set! - ctx.channel().writeAndFlush(new LoginEvent(FModel.getPreferences().getPref(FPref.PLAYER_NAME), Integer.parseInt(FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",")[0]))); + ctx.channel().writeAndFlush(new LoginEvent(FModel.getPreferences().getPref(FPref.PLAYER_NAME), Integer.parseInt(FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",")[0]), Integer.parseInt(FModel.getPreferences().getPref(FPref.UI_SLEEVES).split(",")[0]))); } } \ No newline at end of file diff --git a/forge-gui/src/main/java/forge/net/event/LoginEvent.java b/forge-gui/src/main/java/forge/net/event/LoginEvent.java index 92d5b016b67..170750751a9 100644 --- a/forge-gui/src/main/java/forge/net/event/LoginEvent.java +++ b/forge-gui/src/main/java/forge/net/event/LoginEvent.java @@ -6,10 +6,11 @@ public class LoginEvent implements NetEvent { private static final long serialVersionUID = -8865183377417377938L; private final String username; - private final int avatarIndex; - public LoginEvent(final String username, final int avatarIndex) { + private final int avatarIndex, sleeveIndex; + public LoginEvent(final String username, final int avatarIndex, final int sleeveIndex) { this.username = username; this.avatarIndex = avatarIndex; + this.sleeveIndex = sleeveIndex; } @Override @@ -23,4 +24,8 @@ public class LoginEvent implements NetEvent { public int getAvatarIndex() { return avatarIndex; } + + public int getSleeveIndex() { + return sleeveIndex; + } } diff --git a/forge-gui/src/main/java/forge/net/event/UpdateLobbyPlayerEvent.java b/forge-gui/src/main/java/forge/net/event/UpdateLobbyPlayerEvent.java index 7640472ba6d..7fae4077b10 100644 --- a/forge-gui/src/main/java/forge/net/event/UpdateLobbyPlayerEvent.java +++ b/forge-gui/src/main/java/forge/net/event/UpdateLobbyPlayerEvent.java @@ -16,6 +16,7 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { private LobbySlotType type = null; private String name = null; private int avatarIndex = -1; + private int sleeveIndex = -1; private int team = -1; private Boolean isArchenemy = null; private Boolean isReady = null; @@ -26,11 +27,11 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { private Set aiOptions = null; - public static UpdateLobbyPlayerEvent create(final LobbySlotType type, final String name, final int avatarIndex, final int team, final boolean isArchenemy, final boolean isReady, final Set aiOptions) { - return new UpdateLobbyPlayerEvent(type, name, avatarIndex, team, isArchenemy, isReady, aiOptions); + public static UpdateLobbyPlayerEvent create(final LobbySlotType type, final String name, final int avatarIndex, final int sleeveIndex, final int team, final boolean isArchenemy, final boolean isReady, final Set aiOptions) { + return new UpdateLobbyPlayerEvent(type, name, avatarIndex, sleeveIndex, team, isArchenemy, isReady, aiOptions); } - public static UpdateLobbyPlayerEvent create(final LobbySlotType type, final String name, final int avatarIndex, final int team, final boolean isArchenemy, final boolean isReady, final boolean isDevMode, final Set aiOptions) { - return new UpdateLobbyPlayerEvent(type, name, avatarIndex, team, isArchenemy, isReady, isDevMode, aiOptions); + public static UpdateLobbyPlayerEvent create(final LobbySlotType type, final String name, final int avatarIndex, final int sleeveIndex, final int team, final boolean isArchenemy, final boolean isReady, final boolean isDevMode, final Set aiOptions) { + return new UpdateLobbyPlayerEvent(type, name, avatarIndex, sleeveIndex, team, isArchenemy, isReady, isDevMode, aiOptions); } public static UpdateLobbyPlayerEvent deckUpdate(final Deck deck) { return new UpdateLobbyPlayerEvent(deck); @@ -46,6 +47,19 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { this.name = name; } + public static UpdateLobbyPlayerEvent avatarUpdate(final int index) { + return new UpdateLobbyPlayerEvent(index, true); + } + public static UpdateLobbyPlayerEvent sleeveUpdate(final int index) { + return new UpdateLobbyPlayerEvent(index, false); + } + private UpdateLobbyPlayerEvent(int index, boolean avatar) { + if (avatar) + this.avatarIndex = index; + else + this.sleeveIndex = index; + } + private UpdateLobbyPlayerEvent(final Deck deck) { this.deck = deck; } @@ -59,6 +73,7 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { final LobbySlotType type, final String name, final int avatarIndex, + final int sleeveIndex, final int team, final boolean isArchenemy, final boolean isReady, @@ -66,6 +81,7 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { this.type = type; this.name = name; this.avatarIndex = avatarIndex; + this.sleeveIndex = sleeveIndex; this.team = team; this.isArchenemy = isArchenemy; this.isReady = isReady; @@ -76,6 +92,7 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { final LobbySlotType type, final String name, final int avatarIndex, + final int sleeveIndex, final int team, final boolean isArchenemy, final boolean isReady, @@ -84,6 +101,7 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { this.type = type; this.name = name; this.avatarIndex = avatarIndex; + this.sleeveIndex = sleeveIndex; this.team = team; this.isArchenemy = isArchenemy; this.isReady = isReady; @@ -104,6 +122,9 @@ public final class UpdateLobbyPlayerEvent implements NetEvent { public int getAvatarIndex() { return avatarIndex; } + public int getSleeveIndex() { + return sleeveIndex; + } public int getTeam() { return team; } diff --git a/forge-gui/src/main/java/forge/net/server/FServerManager.java b/forge-gui/src/main/java/forge/net/server/FServerManager.java index 4a17201fd69..beb3887d4c2 100644 --- a/forge-gui/src/main/java/forge/net/server/FServerManager.java +++ b/forge-gui/src/main/java/forge/net/server/FServerManager.java @@ -6,13 +6,14 @@ import forge.interfaces.IGuiGame; import forge.interfaces.ILobbyListener; import forge.match.LobbySlot; import forge.match.LobbySlotType; +import forge.net.CustomObjectDecoder; +import forge.net.CustomObjectEncoder; import forge.net.event.LobbyUpdateEvent; import forge.net.event.LoginEvent; import forge.net.event.LogoutEvent; import forge.net.event.MessageEvent; import forge.net.event.NetEvent; import forge.net.event.UpdateLobbyPlayerEvent; -import forge.properties.ForgeConstants; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; @@ -25,8 +26,6 @@ import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.serialization.ClassResolvers; -import io.netty.handler.codec.serialization.ObjectDecoder; -import io.netty.handler.codec.serialization.ObjectEncoder; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; @@ -39,7 +38,6 @@ import java.util.Collections; import java.util.Enumeration; import java.util.Map; -import org.apache.log4j.PropertyConfigurator; import org.fourthline.cling.UpnpService; import org.fourthline.cling.UpnpServiceImpl; import org.fourthline.cling.support.igd.PortMappingListener; @@ -85,7 +83,6 @@ public final class FServerManager { */ public static FServerManager getInstance() { if (instance == null) { - PropertyConfigurator.configure(ForgeConstants.ASSETS_DIR + "/src/main/resources/log4jConfig.config"); instance = new FServerManager(); } return instance; @@ -98,11 +95,12 @@ public final class FServerManager { .channel(NioServerSocketChannel.class) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer() { - @Override public final void initChannel(final SocketChannel ch) { + @Override + public final void initChannel(final SocketChannel ch) throws Exception { final ChannelPipeline p = ch.pipeline(); p.addLast( - new ObjectEncoder(), - new ObjectDecoder(ClassResolvers.cacheDisabled(null)), + new CustomObjectEncoder(), + new CustomObjectDecoder(CustomObjectDecoder.maxObjectsize, ClassResolvers.cacheDisabled(null)), new MessageHandler(), new RegisterClientHandler(), new LobbyInputHandler(), @@ -329,7 +327,7 @@ public final class FServerManager { final RemoteClient client = clients.get(ctx.channel()); if (msg instanceof LoginEvent) { final LoginEvent event = (LoginEvent) msg; - final int index = localLobby.connectPlayer(event.getUsername(), event.getAvatarIndex()); + final int index = localLobby.connectPlayer(event.getUsername(), event.getAvatarIndex(), event.getSleeveIndex()); if (index == -1) { ctx.close(); } else { diff --git a/forge-gui/src/main/java/forge/net/server/NetGuiGame.java b/forge-gui/src/main/java/forge/net/server/NetGuiGame.java index 73fe66fc626..7601297f2e6 100644 --- a/forge-gui/src/main/java/forge/net/server/NetGuiGame.java +++ b/forge-gui/src/main/java/forge/net/server/NetGuiGame.java @@ -183,6 +183,12 @@ public class NetGuiGame extends AbstractGuiGame { send(ProtocolMethod.setPanelSelection, hostCard); } + @Override + public void refreshField() { + updateGameView(); + send(ProtocolMethod.refreshField); + } + @Override public SpellAbilityView getAbilityToPlay(final CardView hostCard, final List abilities, final ITriggerEvent triggerEvent) { return sendAndWait(ProtocolMethod.getAbilityToPlay, hostCard, abilities, triggerEvent); @@ -259,6 +265,18 @@ public class NetGuiGame extends AbstractGuiGame { send(ProtocolMethod.setCard, card); } + @Override + public void setSelectables(final Iterable cards) { + updateGameView(); + send(ProtocolMethod.setSelectables, cards); + } + + @Override + public void clearSelectables() { + updateGameView(); + send(ProtocolMethod.clearSelectables); + } + @Override public void setPlayerAvatar(final LobbyPlayer player, final IHasIcon ihi) { // TODO Auto-generated method stub diff --git a/forge-gui/src/main/java/forge/net/server/ServerGameLobby.java b/forge-gui/src/main/java/forge/net/server/ServerGameLobby.java index 9fd87b8b132..255ad807c63 100644 --- a/forge-gui/src/main/java/forge/net/server/ServerGameLobby.java +++ b/forge-gui/src/main/java/forge/net/server/ServerGameLobby.java @@ -13,25 +13,26 @@ public final class ServerGameLobby extends GameLobby { public ServerGameLobby() { super(true); - addSlot(new LobbySlot(LobbySlotType.LOCAL, localName(), localAvatarIndices()[0], 0, true, false, Collections.emptySet())); - addSlot(new LobbySlot(LobbySlotType.OPEN, null, -1, 1, false, false, Collections.emptySet())); + addSlot(new LobbySlot(LobbySlotType.LOCAL, localName(), localAvatarIndices()[0], localSleeveIndices()[0],0, true, false, Collections.emptySet())); + addSlot(new LobbySlot(LobbySlotType.OPEN, null, -1, -1, 1, false, false, Collections.emptySet())); } - public int connectPlayer(final String name, final int avatarIndex) { + public int connectPlayer(final String name, final int avatarIndex, final int sleeveIndex) { final int nSlots = getNumberOfSlots(); for (int index = 0; index < nSlots; index++) { final LobbySlot slot = getSlot(index); if (slot.getType() == LobbySlotType.OPEN) { - connectPlayer(name, avatarIndex, slot); + connectPlayer(name, avatarIndex, sleeveIndex, slot); return index; } } return -1; } - private void connectPlayer(final String name, final int avatarIndex, final LobbySlot slot) { + private void connectPlayer(final String name, final int avatarIndex, final int sleeveIndex, final LobbySlot slot) { slot.setType(LobbySlotType.REMOTE); slot.setName(name); slot.setAvatarIndex(avatarIndex); + slot.setSleeveIndex(sleeveIndex); updateView(false); } public void disconnectPlayer(final int index) { diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestController.java b/forge-gui/src/main/java/forge/planarconquest/ConquestController.java index 41dba7860ac..19d10ebd25c 100644 --- a/forge-gui/src/main/java/forge/planarconquest/ConquestController.java +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestController.java @@ -127,7 +127,7 @@ public class ConquestController { starter.add(humanStart.setPlayer(humanPlayer)); final IGuiGame gui = GuiBase.getInterface().getNewGuiGame(); - final LobbyPlayer aiPlayer = GamePlayerUtil.createAiPlayer(aiPlayerName, -1); + final LobbyPlayer aiPlayer = GamePlayerUtil.createAiPlayer(aiPlayerName, -1, -1); battle.setOpponentAvatar(aiPlayer, gui); starter.add(aiStart.setPlayer(aiPlayer)); diff --git a/forge-gui/src/main/java/forge/player/GamePlayerUtil.java b/forge-gui/src/main/java/forge/player/GamePlayerUtil.java index a7a93d85006..ee63047e9bd 100644 --- a/forge-gui/src/main/java/forge/player/GamePlayerUtil.java +++ b/forge-gui/src/main/java/forge/player/GamePlayerUtil.java @@ -23,7 +23,7 @@ public final class GamePlayerUtil { public static final LobbyPlayer getGuiPlayer() { return guiPlayer; } - public static final LobbyPlayer getGuiPlayer(final String name, final int avatarIndex, final boolean writePref) { + public static final LobbyPlayer getGuiPlayer(final String name, final int avatarIndex, final int sleeveIndex, final boolean writePref) { if (writePref) { if (!name.equals(guiPlayer.getName())) { guiPlayer.setName(name); @@ -33,7 +33,7 @@ public final class GamePlayerUtil { return guiPlayer; } //use separate LobbyPlayerHuman instance for human players beyond first - return new LobbyPlayerHuman(name, avatarIndex); + return new LobbyPlayerHuman(name, avatarIndex, sleeveIndex); } public static final LobbyPlayer getQuestPlayer() { @@ -45,19 +45,25 @@ public final class GamePlayerUtil { } public final static LobbyPlayer createAiPlayer(final String name) { final int avatarCount = GuiBase.getInterface().getAvatarCount(); - return createAiPlayer(name, avatarCount == 0 ? 0 : MyRandom.getRandom().nextInt(avatarCount)); + final int sleeveCount = GuiBase.getInterface().getSleevesCount(); + return createAiPlayer(name, avatarCount == 0 ? 0 : MyRandom.getRandom().nextInt(avatarCount), sleeveCount == 0 ? 0 : MyRandom.getRandom().nextInt(sleeveCount)); } public final static LobbyPlayer createAiPlayer(final String name, final String profileOverride) { final int avatarCount = GuiBase.getInterface().getAvatarCount(); - return createAiPlayer(name, avatarCount == 0 ? 0 : MyRandom.getRandom().nextInt(avatarCount), null, profileOverride); + final int sleeveCount = GuiBase.getInterface().getSleevesCount(); + return createAiPlayer(name, avatarCount == 0 ? 0 : MyRandom.getRandom().nextInt(avatarCount), sleeveCount == 0 ? 0 : MyRandom.getRandom().nextInt(sleeveCount), null, profileOverride); } public final static LobbyPlayer createAiPlayer(final String name, final int avatarIndex) { - return createAiPlayer(name, avatarIndex, null, ""); + final int sleeveCount = GuiBase.getInterface().getSleevesCount(); + return createAiPlayer(name, avatarIndex, sleeveCount == 0 ? 0 : MyRandom.getRandom().nextInt(sleeveCount), null, ""); } - public final static LobbyPlayer createAiPlayer(final String name, final int avatarIndex, final Set options) { - return createAiPlayer(name, avatarIndex, options, ""); + public final static LobbyPlayer createAiPlayer(final String name, final int avatarIndex, final int sleeveIndex) { + return createAiPlayer(name, avatarIndex, sleeveIndex, null, ""); } - public final static LobbyPlayer createAiPlayer(final String name, final int avatarIndex, final Set options, final String profileOverride) { + public final static LobbyPlayer createAiPlayer(final String name, final int avatarIndex, final int sleeveIndex, final Set options) { + return createAiPlayer(name, avatarIndex, sleeveIndex, options, ""); + } + public final static LobbyPlayer createAiPlayer(final String name, final int avatarIndex, final int sleeveIndex, final Set options, final String profileOverride) { final LobbyPlayerAi player = new LobbyPlayerAi(name, options); // TODO: implement specific AI profiles for quest mode. @@ -87,6 +93,7 @@ public final class GamePlayerUtil { player.setAiProfile(profile); player.setAvatarIndex(avatarIndex); + player.setSleeveIndex(sleeveIndex); return player; } diff --git a/forge-gui/src/main/java/forge/player/LobbyPlayerHuman.java b/forge-gui/src/main/java/forge/player/LobbyPlayerHuman.java index 04d8a75a5c8..e5882646851 100644 --- a/forge-gui/src/main/java/forge/player/LobbyPlayerHuman.java +++ b/forge-gui/src/main/java/forge/player/LobbyPlayerHuman.java @@ -9,11 +9,12 @@ import forge.util.GuiDisplayUtil; public class LobbyPlayerHuman extends LobbyPlayer implements IGameEntitiesFactory { public LobbyPlayerHuman(final String name) { - this(name, -1); + this(name, -1, -1); } - public LobbyPlayerHuman(final String name, final int avatarIndex) { + public LobbyPlayerHuman(final String name, final int avatarIndex, final int sleeveIndex) { super(name); setAvatarIndex(avatarIndex); + setSleeveIndex(sleeveIndex); } @Override diff --git a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java index 267eae1e1a9..37bcafa370d 100644 --- a/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java +++ b/forge-gui/src/main/java/forge/player/PlayerControllerHuman.java @@ -678,7 +678,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont public CardCollection orderBlockers(final Card attacker, final CardCollection blockers) { final CardView vAttacker = CardView.get(attacker); getGui().setPanelSelection(vAttacker); - return game.getCardList(getGui().order("Choose Damage Order for " + vAttacker, "Damaged First", + return game.getCardList(getGui().order(localizer.getMessage("lblChooseDamageOrderFor").replace("%s", vAttacker.toString()), localizer.getMessage("lblDamagedFirst"), CardView.getCollection(blockers), vAttacker)); } @@ -703,7 +703,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont final CardView vAttacker = CardView.get(attacker); getGui().setPanelSelection(vAttacker); return game.getCardList(getGui().insertInList( - "Choose blocker after which to place " + vAttacker + " in damage order; cancel to place it first", + localizer.getMessage("lblChooseBlockerAfterWhichToPlaceAttackert").replace("%s", vAttacker.toString()), CardView.get(blocker), CardView.getCollection(oldBlockers))); } @@ -711,7 +711,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont public CardCollection orderAttackers(final Card blocker, final CardCollection attackers) { final CardView vBlocker = CardView.get(blocker); getGui().setPanelSelection(vBlocker); - return game.getCardList(getGui().order("Choose Damage Order for " + vBlocker, "Damaged First", + return game.getCardList(getGui().order(localizer.getMessage("lblChooseDamageOrderFor").replace("%s", vBlocker.toString()), localizer.getMessage("lblDamagedFirst"), CardView.getCollection(attackers), vBlocker)); } @@ -841,7 +841,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont getGui().setCard(c.getView()); boolean result = false; - result = InputConfirm.confirm(this, view, TextUtil.concatNoSpace("Put ", view.toString(), " on the top or bottom of your library?"), + result = InputConfirm.confirm(this, view, localizer.getMessage("lblPutCardOnTopOrBottomLibrary").replace("%s", view.toString()), true, ImmutableList.of("Top", "Bottom")); endTempShowCards(); @@ -876,27 +876,27 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont tempShowCards(cards); switch (destinationZone) { case Library: - choices = getGui().order("Choose order of cards to put into the library", "Closest to top", + choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoLibrary"), localizer.getMessage("lblClosestToTop"), CardView.getCollection(cards), null); break; case Battlefield: - choices = getGui().order("Choose order of cards to put onto the battlefield", "Put first", + choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutOntoBattlefield"), localizer.getMessage("lblPutFirst"), CardView.getCollection(cards), null); break; case Graveyard: - choices = getGui().order("Choose order of cards to put into the graveyard", "Closest to bottom", + choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoGraveyard"), localizer.getMessage("lblClosestToBottom"), CardView.getCollection(cards), null); break; case PlanarDeck: - choices = getGui().order("Choose order of cards to put into the planar deck", "Closest to top", + choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoPlanarDeck"), localizer.getMessage("lblClosestToTop"), CardView.getCollection(cards), null); break; case SchemeDeck: - choices = getGui().order("Choose order of cards to put into the scheme deck", "Closest to top", + choices = getGui().order(localizer.getMessage("lblChooseOrderCardsPutIntoSchemeDeck"), localizer.getMessage("lblClosestToTop"), CardView.getCollection(cards), null); break; case Stack: - choices = getGui().order("Choose order of copies to cast", "Put first", CardView.getCollection(cards), + choices = getGui().order(localizer.getMessage("lblChooseOrderCopiesCast"), localizer.getMessage("lblPutFirst"), CardView.getCollection(cards), null); break; default: @@ -914,14 +914,14 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont if (p != player) { tempShowCards(valid); final CardCollection choices = game - .getCardList(getGui().many("Choose " + min + " card" + (min != 1 ? "s" : "") + " to discard", - "Discarded", min, min, CardView.getCollection(valid), null)); + .getCardList(getGui().many(String.format(localizer.getMessage("lblChooseMinCardToDiscard"), min), + localizer.getMessage("lblDiscarded"), min, min, CardView.getCollection(valid), null)); endTempShowCards(); return choices; } final InputSelectCardsFromList inp = new InputSelectCardsFromList(this, min, max, valid, sa); - inp.setMessage(sa.hasParam("AnyNumber") ? "Discard up to %d card(s)" : "Discard %d card(s)"); + inp.setMessage(sa.hasParam("AnyNumber") ? localizer.getMessage("lblDiscardUpToNCards") : localizer.getMessage("lblDiscardNCards")); inp.showAndWait(); return new CardCollection(inp.getSelected()); } @@ -938,9 +938,9 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont for (int i = 0; i <= cardsInGrave; i++) { cntChoice.add(Integer.valueOf(i)); } - final int chosenAmount = getGui().one("Delve how many cards?", cntChoice.build()).intValue(); + final int chosenAmount = getGui().one(localizer.getMessage("lblDelveHowManyCards"), cntChoice.build()).intValue(); for (int i = 0; i < chosenAmount; i++) { - final CardView nowChosen = getGui().oneOrNone("Exile which card?", CardView.getCollection(grave)); + final CardView nowChosen = getGui().oneOrNone(localizer.getMessage("lblExileWhichCard"), CardView.getCollection(grave)); if (nowChosen == null) { // User canceled,abort delving. @@ -1003,7 +1003,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont return super.hasAllTargets(); } }; - target.setMessage("Select %d card(s) to discard, unless you discard a " + uType + "."); + target.setMessage(localizer.getMessage("lblSelectNCardsToDiscardUnlessDiscarduType").replace("%s", uType)); target.showAndWait(); return new CardCollection(target.getSelected()); } @@ -1316,8 +1316,8 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont // opponent's next turn } }; - final String message = "Cleanup Phase\nSelect " + nDiscard + " card" + (nDiscard > 1 ? "s" : "") - + " to discard to bring your hand down to the maximum of " + max + " cards."; + final String message = localizer.getMessage("lblCleanupPhase") + "\n" + + localizer.getMessage("lblSelectCardsToDiscardHandDownMaximum").replace("%d", String.valueOf(nDiscard)).replace("%max", String.valueOf(max)); inp.setMessage(message); inp.setCancelAllowed(false); inp.showAndWait(); @@ -1587,7 +1587,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont @Override public ReplacementEffect chooseSingleReplacementEffect(final String prompt, - final List possibleReplacers, final Map runParams) { + final List possibleReplacers) { final ReplacementEffect first = possibleReplacers.get(0); if (possibleReplacers.size() == 1) { return first; diff --git a/forge-gui/src/main/java/forge/properties/ForgeConstants.java b/forge-gui/src/main/java/forge/properties/ForgeConstants.java index 11c582e9de1..42d07add4e3 100644 --- a/forge-gui/src/main/java/forge/properties/ForgeConstants.java +++ b/forge-gui/src/main/java/forge/properties/ForgeConstants.java @@ -94,8 +94,11 @@ public final class ForgeConstants { public static final String SPRITE_OLD_FOILS_FILE = "sprite_old_foils.png"; public static final String SPRITE_TROPHIES_FILE = "sprite_trophies.png"; public static final String SPRITE_ABILITY_FILE = "sprite_ability.png"; + public static final String SPRITE_BORDER_FILE = "sprite_border.png"; public static final String SPRITE_MANAICONS_FILE = "sprite_manaicons.png"; public static final String SPRITE_AVATARS_FILE = "sprite_avatars.png"; + public static final String SPRITE_SLEEVES_FILE = "sprite_sleeves.png"; + public static final String SPRITE_SLEEVES2_FILE = "sprite_sleeves2.png"; public static final String SPRITE_FAVICONS_FILE = "sprite_favicons.png"; public static final String SPRITE_PLANAR_CONQUEST_FILE = "sprite_planar_conquest.png"; public static final String FONT_FILE = "font1.ttf"; diff --git a/forge-gui/src/main/java/forge/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/properties/ForgePreferences.java index b6dcf1be167..941ac2a1ed0 100644 --- a/forge-gui/src/main/java/forge/properties/ForgePreferences.java +++ b/forge-gui/src/main/java/forge/properties/ForgePreferences.java @@ -73,6 +73,7 @@ public class ForgePreferences extends PreferencesStore { UI_RANDOM_FOIL ("false"), UI_ENABLE_AI_CHEATS ("false"), UI_AVATARS ("0,1"), + UI_SLEEVES ("0,1"), UI_SHOW_CARD_OVERLAYS ("true"), UI_OVERLAY_CARD_NAME ("true"), UI_OVERLAY_CARD_POWER ("true"), @@ -134,6 +135,9 @@ public class ForgePreferences extends PreferencesStore { UI_ROTATE_SPLIT_CARDS("true"), UI_DYNAMIC_PLANECHASE_BG("false"), UI_DISABLE_IMAGES_EFFECT_CARDS("false"), + UI_ENABLE_PRELOAD_EXTENDED_ART("false"), + UI_ENABLE_BORDER_MASKING("false"), + UI_SHOW_FPS("false"), UI_ALLOW_ORDER_GRAVEYARD_WHEN_NEEDED ("Never"), UI_DEFAULT_FONT_SIZE("12"), UI_SELECT_FROM_CARD_DISPLAYS("true"), diff --git a/forge-gui/src/main/java/forge/quest/QuestController.java b/forge-gui/src/main/java/forge/quest/QuestController.java index 86fc937f89a..57ed852e5c8 100644 --- a/forge-gui/src/main/java/forge/quest/QuestController.java +++ b/forge-gui/src/main/java/forge/quest/QuestController.java @@ -448,7 +448,10 @@ public class QuestController { if (world.getName().equals(QuestWorld.STANDARDWORLDNAME)) { this.duelManager = new QuestEventLDADuelManager(FModel.getFormats().getStandard()); return; - } else if (world.getName().equals(QuestWorld.MODERNWORLDNAME)) { + } else if (world.getName().equals(QuestWorld.PIONEERWORLDNAME)) { + this.duelManager = new QuestEventLDADuelManager(FModel.getFormats().getPioneer()); + return; + }else if (world.getName().equals(QuestWorld.MODERNWORLDNAME)) { this.duelManager = new QuestEventLDADuelManager(FModel.getFormats().getModern()); return; }else if (world.isCustom()) { diff --git a/forge-gui/src/main/java/forge/quest/QuestSpellShop.java b/forge-gui/src/main/java/forge/quest/QuestSpellShop.java index 5924404f35f..e3f49e70786 100644 --- a/forge-gui/src/main/java/forge/quest/QuestSpellShop.java +++ b/forge-gui/src/main/java/forge/quest/QuestSpellShop.java @@ -360,6 +360,11 @@ public class QuestSpellShop { //If this card has an exception to the card limit, e.g.: Relentless Rats, get the quest preference if (DeckFormat.canHaveAnyNumberOf(card)) { numToKeep = FModel.getQuestPreferences().getPrefInt(QPref.PLAYSET_ANY_NUMBER_SIZE); + } else { + Integer cardCopies = DeckFormat.canHaveSpecificNumberInDeck(card); + if (cardCopies != null) { + numToKeep = cardCopies; + } } if (numToKeep < item.getValue()) { diff --git a/forge-gui/src/main/java/forge/quest/QuestWorld.java b/forge-gui/src/main/java/forge/quest/QuestWorld.java index b5a27b5b04c..52ad44988f0 100644 --- a/forge-gui/src/main/java/forge/quest/QuestWorld.java +++ b/forge-gui/src/main/java/forge/quest/QuestWorld.java @@ -40,6 +40,7 @@ public class QuestWorld implements Comparable{ private final String dir; private final GameFormatQuest format; public static final String STANDARDWORLDNAME = "Random Standard"; + public static final String PIONEERWORLDNAME = "Random Pioneer"; public static final String MODERNWORLDNAME = "Random Modern"; public static final String RANDOMCOMMANDERWORLDNAME = "Random Commander"; @@ -195,6 +196,12 @@ public class QuestWorld implements Comparable{ FModel.getFormats().getStandard().getBannedCardNames(),false); } + if (useName.equalsIgnoreCase(QuestWorld.PIONEERWORLDNAME)){ + useFormat = new GameFormatQuest(QuestWorld.PIONEERWORLDNAME, + FModel.getFormats().getPioneer().getAllowedSetCodes(), + FModel.getFormats().getPioneer().getBannedCardNames(),false); + } + if (useName.equalsIgnoreCase(QuestWorld.MODERNWORLDNAME)){ useFormat = new GameFormatQuest(QuestWorld.MODERNWORLDNAME, FModel.getFormats().getModern().getAllowedSetCodes(), diff --git a/forge-gui/src/main/java/forge/tournament/TournamentUtil.java b/forge-gui/src/main/java/forge/tournament/TournamentUtil.java index ebf1c426e60..08f99eed11b 100644 --- a/forge-gui/src/main/java/forge/tournament/TournamentUtil.java +++ b/forge-gui/src/main/java/forge/tournament/TournamentUtil.java @@ -36,6 +36,9 @@ public class TournamentUtil { case STANDARD_CARDGEN_DECK: deck = DeckgenUtil.buildCardGenDeck(FModel.getFormats().getStandard(),true); break; + case PIONEER_CARDGEN_DECK: + deck = DeckgenUtil.buildCardGenDeck(FModel.getFormats().getPioneer(),true); + break; case MODERN_CARDGEN_DECK: deck = DeckgenUtil.buildCardGenDeck(FModel.getFormats().getModern(),true); break; diff --git a/forge-gui/src/main/resources/log4j2.xml b/forge-gui/src/main/resources/log4j2.xml new file mode 100644 index 00000000000..c378e95d10f --- /dev/null +++ b/forge-gui/src/main/resources/log4j2.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/forge-gui/tools/cardnames-es-ES-patch.txt b/forge-gui/tools/cardnames-es-ES-patch.txt index 57969f05a8a..44cf166e58e 100644 --- a/forge-gui/tools/cardnames-es-ES-patch.txt +++ b/forge-gui/tools/cardnames-es-ES-patch.txt @@ -1,6 +1,155 @@ +Abandon Hope|Perder la esperanza|Conjuro|Como coste adicional para lanzar este hechizo, descarta X cartas.\nMira la mano del oponente objetivo y elige X cartas de este. Ese jugador descarta esas cartas. +Abbey Gargoyles|Gárgolas de la Abadía|Criatura - Gárgola|Vuela, protección contra el rojo +Abbey Matron|Abadesa|Criatura - Clérigo Humano|{W}, {T}: La Abadesa recibe +0/+3 hasta el final del turno. +Abduction|Secuestro|Encantamiento - Aura|Encantar criatura\nCuando el Secuestro entre en juego, endereza a la criatura encantada.\nTú controlas a la criatura encantada.\nCuando la criatura encantada muera, devuelve esa carta al juego bajo el control de su dueño. +Abeyance|Supresión|Instantáneo|Hasta el final del turno, el jugador objetivo no puede lanzar hechizos instantáneos o de brujería, y ese jugador no puede activar habilidades que no sean habilidades de maná.\nRoba una carta. +Abjure|Abjurar|Instantáneo|Como coste adicional para lanzar este hechizo, sacrifica un permanente azul.\nContrarresta el hechizo objetivo. +Abomination|Abominación|Criatura - Horror|Siempre que la Abominación bloquee o sea bloqueada por una criatura verde o blanca, destruye a esa criatura al final del combate. +Aboroth|Aboroth|Criatura — Elemental|Mantenimiento acumulativo - Pon un contador de -1/-1 en Aboroth. (Al principio de tu mantenimiento, pon un contador de edad en este permanente, luego sacrifícalo a menos que pagues su coste de mantenimiento por cada contador de edad en él). +About Face|Media vuelta|Instantáneo|Intercambia la fuerza y resistencia de la criatura objetivo hasta el final del turno. +Absolute Grace|Gracia absoluta|Encantamiento|Todas las criaturas tienen protección contra el negro. +Absolute Law|Ley absoluta|Encantamiento|Todas las criaturas tienen protección contra el rojo. +Abundance|Abundancia|Encantamiento|Si fueras a robar una carta, en vez de eso, puedes elegir tierra o no tierra y mostrar cartas de la parte superior de tu biblioteca hasta que muestres una carta del tipo elegido. Pon esa carta en tu mano y pon todas las otras cartas mostradas de esta manera en el fondo de tu biblioteca en cualquier orden. +Abyssal Gatekeeper|Portero abismal|Criatura — Horror|Cuando el Portero abismal muera, cada jugador sacrifica a una criatura. +Abyssal Horror|Horror abismal|Criatura — Horror|Vuela\nCuando el Horror abismal entre en juego, el jugador objetivo descarta dos cartas. +Abyssal Hunter|Cazador abismal|Criatura - Asesino Humano|{B}, {T}: Gira la criatura objetivo. El Cazador abismal inflige un daño igual a la fuerza del Cazador abismal sobre esa criatura. +Abyssal Nightstalker|Cazador nocturno abismal|Criatura — Cazador nocturno|Siempre que el Cazador nocturno abismal ataque y no sea bloqueado, el jugador defensor descarta una carta. +Academy Rector|Rector de la Academia|Criatura - Clérigo Humano|Cuando el Rector de la Academia muera, puedes exiliarlo. Si lo haces, busca en tu biblioteca una carta de encantamiento, pon esa carta en juego y luego baraja tu biblioteca. +Accumulated Knowledge|Conocimiento acumulado|Instantáneo|Roba una carta, luego roba tantas cartas como el número de cartas llamadas Conocimiento Acumulado en todos los cementerios. +Acidic Dagger|Daga corrosiva|Artefacto|{4}, {T}: Siempre que una criatura objetivo inflija daño de combate a una criatura no muralla en este turno, destruye a esa criatura no muralla. Cuando la criatura objetivo abandone el juego este turno, sacrifica la Daga corrosiva. Activa esta habilidad sólo antes de que se declaren los bloqueadores. +Acidic Sliver|Fragmentado corrosivo|Criatura - Fragmentado|Todos los fragmentados tienen "{2}, Sacrifica este permanente: Este permanente causa 2 de daño a cualquier objetivo." +Acidic Soil|Suelo ácido|Sorcery|Conjuro|Suelo ácido inflige daño a cada jugador igual al número de tierras que controlan. +Acridian|Acrídido|Criatura - Insecto|Eco {1}{G} (Al principio de su mantenimiento, si esto ha estado bajo tu control desde el principio de tu último mantenimiento, sacrifícalo a menos que pagues el coste del eco). +Adarkar Sentinel|Centinela de Adarkar|Criatura Artefacto - Soldado|{1}: El Centinela de Adarkar recibe +0/+1 hasta el final del turno. +Adarkar Unicorn|Unicornio de Adarkar|Criatura - Unicornio|{T}: Agrega {U} o {C}{U}. Gasta este maná sólo para pagar los costes acumulativos de mantenimiento. +Addle|Turbar|Conjuro|Elige un color. El jugador objetivo revela su mano y tú eliges una carta de ese color. Ese jugador descarta esa carta. +Advance Scout|Explorador avanzado|Criatura - Soldado Explorador Humano|Daña primero\n{W}: La criatura objetivo recibe el primer golpe hasta el final del turno. +Aegis of the Meek|Égida de los mansos|Artefacto|{1}, {T}: La criatura objetivo 1/1 recibe +1/+2 hasta el final del turno. +Aerial Caravan|Caravana aérea|Criatura - Soldado Humano|Vuela\n{1}{U}{U}: Exilia la carta superior de tu biblioteca. Hasta el final del turno, puedes jugar esa carta. (Revela la carta cuando la exilies.) +Aether Barrier|Barrera de éter|Encantamiento|Cuando un jugador lance un hechizo de criatura, ese jugador sacrifica un permanente a menos que pague {1}. +Aether Flash|Destello del Éter|Cada vez que una criatura entre en juego, el Destello del Éter le inflige 2 puntos de daño. +Aether Mutation|Mutación del éter|Conjuro|Devuelve la criatura objetivo a la mano de su dueño. Crea X fichas de criaturas verdes Saprolín 1/1, donde X es el coste de maná convertido de esa criatura. +Aether Rift|Grieta de éter|Encantamiento|Al principio de tu mantenimiento, descarta una carta al azar. Si descartas una carta de criatura de esta manera, devuélvela de tu cementerio al juego a menos que algún jugador pague 5 vidas. +Aether Sting|Piquete de Éter|Encantamiento|Siempre que un oponente lance un hechizo de criatura, el Piquete de Éter inflige 1 de daño a ese jugador. +Aether Storm|Tormenta del éter|Encantamiento|No se pueden lanzar hechizos de criaturas.\nPaga 4 vidas: Destruir la Tormenta del éter. No se puede regenerar. Cualquier jugador puede activar esta habilidad. +Aether Tide|Corriente de éter|Conjuro|Como coste adicional para lanzar este hechizo, descarta X cartas de criatura. Devuelve las X criaturas objetivo a las manos de sus dueños. +Afiya Grove|Arboleda de Afiya|Encantamiento|La Arboleda de Afiya entra en juego con tres contadores +1/+1.\nAl principio de tu mantenimiento, mueve un contador +1/+1 de la Arboleda de Afiya a la criatura objetivo.\nCuando la Arboleda de Afiya Grove no tenga contadores +1/+1, sacrifícala. +Aftershock|Conmoción posterior|Conjuro|Destruye el artefacto, la criatura o la tierra objetivo. La Conmoción posterior te inflinge 3 de daño. +Agent of Shauku|Agente de Shauku|Criatura - Mercenario Humano|{1}{B}, Sacrifica una tierra: La criatura objetivo recibe +2/+0 hasta el final del turno. +Agent of Stromgald|Agente de Stromgald|Criatura — Caballero Humano|{R}: Agrega {B}. +Aggression|Agresión|Encantamiento - Aura|Encantar criatura no muralla\nLa criatura encantada tiene la habilidad daña primero y arrollar.\nAl principio del paso final del controlador de la criatura encantada, destruye esa criatura si no atacó este turno. +Aggressive Urge|Impulso Agresivo|Instantáneo|La criatura objetivo recibe +1/+1 hasta el final del turno.\nRoba una carta. +Agility|Agilidad|Encantamiento - Aura|Encantar criatura.\nLa criatura encantada obtiene +1/+1 y tiene la habilidad de flanquear. (Siempre que una criatura sin la habilidad de flanquear bloquee a esta criatura, la criatura bloqueadora obtiene -1/-1 hasta el final del turno.) +Agonizing Demise|Fallecimiento Agónico|Instantáneo|Estímulo {1}{R} (Puedes pagar {1}{R} adicionales al lanzar este hechizo.)\nDestruye la criatura objetivo que no sea negra. No puede ser regenerada. Si el Fallecimiento Agónico fue estimulado, le hace daño al controlador de esa criatura igual a la fuerza de esa criatura. +Agonizing Memories|Recuerdos agónicos|Conjuro|Mira la mano del jugador objetivo y elige dos cartas de ahí. Pon esas cartas en la parte superior de la biblioteca de ese jugador en cualquier orden. +Air Bladder|Vejiga de aire|Encantamiento — Aura|Encantar criatura\nLa criatura encantada tiene la habilidad de volar.\nLa criatura encantada sólo puede bloquear a las criaturas con la habilidad de volar. +Air Elemental|Elemental de aire|Criatura — Elemental|Vuela. +Akron Legionnaire|Legionario de Akron|Criatura - Soldado Gigante|Excepto las criaturas llamadas Legionario de Akron y las criaturas artefacto, las criaturas que controlas no pueden atacar. +Aku Djinn|Djinn de Aku|Criatura — Djinn|Arrolla\nAl principio de tu mantenimiento, pon un contador +1/+1 en cada criatura que cada oponente controle. +Alabaster Dragon|Dragón alabastro|Criatura - Dragón Volador|Cuando el Dragón alabastro muera, mételo en la biblioteca de su dueño. +Alabaster Leech|Sanguijuela de Alabastro|Criatura - Sanguijuela|Los hechizos blancos que lanzas cuestan {W} más de lo que cuestan. +Alabaster Potion|Poción de alabastro|Instántaneo|Elige uno —\n• El jugador objetivo gana X de vida.\n• Evita el siguiente daño X que se infligiría a cualquier objetivo en este turno. +Alabaster Wall|Muro de alabastro|Criatura - Muro|Defensor (Esta criatura no puede atacar.)\n{T}: Evita el siguiente daño de 1 que sería infligido a cualquier objetivo en este turno. +Alaborn Cavalier|Caballero de Alaborn|Criatura — Caballero humano|Siempre que el Caballero de Alaborn ataque, puedes girar la criatura objetivo. +Alaborn Grenadier|Granadero de Alaborn|Criatura — Soldado humano|Vigilancia +Alaborn Musketeer|Mosquetero de Alaborn|Criatura — Soldado humano|Alcance (Esta criatura puede bloquear a las criaturas con la habilidad de volar.) +Alaborn Trooper|Soldado de caballeria de Alaborn|Criatura — Soldado humano| +Alaborn Veteran|Veterano alaborn|Criatura — Caballero humano|{T}: La criatura objetivo recibe +2/+2 hasta el final del turno. Activa esta habilidad sólo durante tu turno, antes de que los atacantes sean declarados. +Alaborn Zealot|Defensor alaborn|Criatura — Soldado humano|Cuando el Defensor alaborn bloquee a una criatura, destruye a esa criatura y al Defensor alaborn. +Aladdin's Lamp|Lámpara de Aladino|Artefacto|{X}, {T}: La próxima vez que robes una carta en este turno, mira las X cartas de la parte superior de tu biblioteca, pon todas menos una en la parte inferior de tu biblioteca en un orden aleatorio, y luego roba una carta. X no puede ser 0. +Alarum|Voz de alarma|Instantáneo|Endereza la criatura objetivo que no atacante. Obtiene +1/+3 hasta el final del turno. +Albino Troll|Troll albino|Criatura — Troll|Eco {1}{G} (Al principio de tu mantenimiento, si esto ha estado bajo tu control desde el principio de tu último mantenimiento, sacrifícalo a menos que pagues su coste de eco.)\n{1}{G}: Regenera el Troll albino. +Aleatory|Azar|Instantáneo|Lanza este hechizo sólo durante el combate después de que los bloqueadores sean declarados.\nLanza una moneda al aire. Si ganas la tirada, la criatura objetivo obtiene +1/+1 hasta el final del turno.\nRoba una carta al comienzo del mantenimiento del turno siguiente. +Alexi's Cloak|Capa de Alexi|Encantamiento — Aura|Destello\nEncantar criatura\nLa criatura encantada tiene la habilidad de velo. (No puede ser objetivo de hechizos o habilidades.) +Alexi, Zephyr Mage|Alexi, Maga Céfira|Criatura Legendaria - Hechicero Humano|{X}{U}, {T}, Descarta dos cartas: Devuelve X criaturas objetivo a las manos de sus dueños. +Ali Baba|Ali Baba|Criatura — Pícaro humano|{R}: Gira el Muro objetivo. +Aliban's Tower|Torre de Alibán|Instantáneo|La criatura objetivo que bloquea obtiene +3/+1 hasta el final del turno. +Allay|Mitigar|Instantáneo|Recuperar {3} (Puedes pagar {3} adicionales al lanzar este hechizo. Si lo haces, pon esta carta en tu mano en cuanto se resuelva.)\nDestruye el encantamiento objetivo. +Alley Grifters|Embaucadores callejeros|Criatura — Mercenario humano|Siempre que los Embaucadores callejeros sean bloqueados, el jugador defensor descarta una carta. +Allied Strategies|Estrategias Aliadas|Conjuro|Dominio - El jugador objetivo roba una carta por cada tipo de tierra básica entre las tierras que controle. +Alloy Golem|Gólem de Aleación|Criatura artefacto — Golem|Cuando el Gólem de Aleación entre en juego, elige un color.\nEl Gólem de Aleación es el color elegido. (Sigue siendo un artefacto.) +Alluring Scent|Aroma seductor|Conjuro|Todas las criaturas capaces de bloquear a la criatura objetivo en este turno lo hacen. +Alms|Limosna|Encantamiento|{1}, Exilia la carta superior de tu cementerio: Evita el siguiente daño de 1 que sería infligido a la criatura objetivo en este turno. +Alpha Kavu|Kavu alfa|Criatura — Kavu|{1}{G}: La criatura Kavu objetivo recibe -1/+1 hasta el final del turno. +Alpha Myr|Myr alfa|Criatura artefacto — Myr| +Alpha Tyrranax|Tyrranax alfa|Criatura — Bestia| +Alpine Grizzly|Parda alpina|Criatura — Oso| +Altar of Bone|Altar de hueso|Conjuro|Como coste adicional para lanzar este hechizo, sacrifica a una criatura.\nBusca en tu biblioteca una carta de criatura, revela esa carta y ponla en tu mano. Luego baraja tu biblioteca. +Altar of Dementia|Altar de la demencia|Artefacto|Sacrifica una criatura: El jugador objetivo pone un número de cartas igual a la fuerza de la criatura sacrificada desde la parte superior de su biblioteca a su cementerio. +Aluren|Pasajes encantados|Encantamiento|Cualquier jugador puede lanzar hechizos de criaturas con coste de maná convertido 3 o menos sin pagar su coste de maná y como si tuvieran la habilidad de destello. +Amber Prison|Prisión de ámbar|Artefacto|Puedes elegir no enderezar a la Prisión de ámbar durante su paso de enderezar.\n{4}, {T}:Gira el artefacto, criatura o tierra objetivo. Ese permanente no se enderezará durante el paso de enderezar del jugador que lo controla mientras la Prisión de ámbar permanezca girado. +Ambush Commander|Comandante de Emboscada|Criatura — Elfo|Los bosques que controlas son criaturas Elfo verde 1/1 que siguen siendo tierras.\n{1}{G}, sacrificar un Elfo: La criatura objetivo obtiene +3/+3 hasta el final del turno. +Ambush Party|Banda emboscada|Criatura - Pícaro humano|Daña primero, prisa +Ambush|Emboscada|Instantáneo|Las criaturas que bloquean reciben la habilidad daña primero hasta el final del turno. +Amok|Locura temporal|Encantamiento|{1}, Descarta una carta al azar: Pon un contador +1/+1 en la criatura objetivo. +Amphibious Kavu|Kavu anfibio|Criatura — Kavu|Siempre que el Kavu anfibio bloquee o sea bloqueado por una o más criaturas azules y/o negras, el Kavu anfibio obtiene +3/+3 hasta el final del turno. +Amrou Kithkin|Kitkin Amrou|Criatura — Kithkin|Amrou Kithkin no puede ser bloqueado por criaturas con fuerza de 3 o superior. +Amulet of Kroog|Amuleto de Kroog|Artefacto|{2}, {T}: Evita el siguiente daño de 1 que sería infligido a cualquier objetivo en este turno. +Amulet of Unmaking|Amuleto de disgregación|Artefacto|{5}, {T}, Exilia el Amuleto de disgregación: Exilia el artefacto, criatura o tierra objetivo. Activa esta habilidad sólo cuando puedas lanzar un conjuro. +An-Havva Constable|Alguacil de An-Havva|Criatura — Humano|La resistencia del Alguacil de An-Havva es igual a 1 más el número de criaturas verdes en juego. +An-Havva Inn|Posada de An-Havva|Conjuro|Ganas X más 1 vida, donde X es el número de criaturas verdes en juego. +An-Havva Township|Municipio de An-Havva|Tierra|{T}: Agrega {C}.\n{1}, {T}: Agrega {G}.\n{2}, {T}: Agrega {R} o {W}. +An-Zerrin Ruins|Ruinas de An-Zerrin|Encantamiento|Cuando las Ruinas de An-Zerrin entren en juego, elige un tipo de criatura.\nLas criaturas del tipo elegido no se enderezan durante los pasos de enderezar de sus controladores. +Ana Disciple|Discípulo Ana|Criatura — Mago humano|{U}, {T}: La criatura objetivo gana la habilidad de volar hasta el final del turno.\n{B}, {T}: La criatura objetivo obtiene -2/-0 hasta el final del turno. +Ana Sanctuary|Santuario Ana|Encantamiento|Al comienzo de tu mantenimiento, si controlas un permanente azul o negro, la criatura objetivo obtiene +1/+1 hasta el final del turno. Si controlas un permanente azul y un permanente negro, esa criatura obtiene +5/+5 hasta el final del turno. +Anaba Spirit Crafter|Animista de Anaba|Criatura — Minotauro chamán|Las criaturas Minotauro obtienen +1/+0. +Anarchy|Anarquía|Conjuro|Destruye todos los permanentes blancos. +Anavolver|Anavolver|Criatura — Volver|Estímulo {1}{U} y/o {B} (Puedes pagar {1}{U} y/o {B} adicionales al lanzar este hechizo.)\nSi Anavolver fue estimulado con el estímulo {1}{U}, entra en juego con dos contadores +1/+1 y con la habilidad de volar.\nSi Anavolver fue estimulado con el estímulo {B}, entra en juego con un contador +1/+1 sobre él y con "Pagar 3 vidas: Regenerar Anavolver". +Ancestral Knowledge|Conocimiento ancestral|Encantamiento|Mantenimiento acumulativo {1} (Al comienzo de tu mantenimiento, pon un contador de edad en este permanente, luego sacrifícalo a menos que pagues su coste de mantenimiento por cada contador de edad en él.)\nCuando el Conocimiento ancestral entre en juego, mira las diez cartas superiores de tu biblioteca, luego exilia a cualquier número de ellas y vuelve a poner el resto encima de tu biblioteca en cualquier orden.\nCuando el Conocimiento ancestral abandone el juego, baraja tu biblioteca. +Ancestral Mask|Máscara ancestral|Encantamiento — Aura|Encantar criatura\nLa criatura encantada recibe +2/+2 por cada uno de los otros encantamientos en juego. +Ancestral Memories|Bendición angélica|Conjuro|Mira las siete cartas superiores de tu biblioteca. Pon dos de ellas en tu mano y el resto en tu cementerio. +Ancient Den|Guarida antigua|Tierra artefacto|(La Guarida antigua no es un hechizo.)\n{T}: Agrega {W} a tu reserva de maná. +Ancient Hydra|Hidra antigua|Criatura — Hidra|Desaparecer 5 (Esta criatura entra en juego con cinco contadores de desaparecer. Al comienzo de tu mantenimiento, elimina un contador de desaparecer de ella. Si no puedes, sacrifícala.)\n{1}, Elimina un contador de desaparecer de la Hidra Antigua: inflige 1 de daño a cualquier objetivo. +Ancient Kavu|Kavu Antiguo|Criatura — Kavu|{2}: El Kabu Antiguo se vuelve incoloro hasta el final del turno. +Ancient Runes|Runas antiguas|Encantamiento|Al comienzo del mantenimiento de cada jugador, las Runas antiguas infligen daño a ese jugador igual al número de artefactos que controlan. +Ancient Spider|Araña antigua|Criatura — Araña|Daña primero; alcance (Esta criatura puede bloquear a criaturas con la habilidad de volar.) +Ancient Spring|Manantial Antiguo|Tierra|El Manantial Antiguo entra en juego girado.\n{T}: Agrega {U}.\n{T}, Sacrifica el Manantial Antiguo: Agrega {W}{B}. +Ancient Tomb|Tumba antigua|Tierra|{T}: Agrega {C}{C}. La Tumba antigua te inflinge 2 de daño. +Andradite Leech|Sanguijuela Andradita|Criatura — Sanguijuela|Los hechizos negros que lances cuestan {B} más.\n{B}: La Sanguijuela Andradita recibe +1/+1 hasta el final del turno. +Angel of Fury|Ángel de furia|Criature — Ángel|Vuela\nCuando el Ángel de furia muera, puedes mezclarlo en la biblioteca de su dueño. +Angel of Mercy|Angel de Piedad|Criatura — Ángel|Vuela\nCuando el Ángel de Piedad entra en juego, ganas 3 vidas. +Angel of Retribution|Ángel de Castigo|Criatura — Ángel|Vuela, daña primero +Angel's Trumpet|Trompeta de ángeles|Artefacto|Todas las criaturas tienen vigilancia.\nAl principio del paso final de cada jugador, gira todas las criaturas enderezadas que el jugador controle y que no hayan atacado este turno. La Trompeta de Ángeles inflige un daño al jugador igual al número de criaturas giradas de esta manera. +Angelfire Crusader|Cruzado fuegoangélico|Criatura — Caballero humano|{R}: El Cruzado fuegoangélico obtiene +1/+0 hasta el final del turno. +Angelic Blessing|Bendición angélica|Conjuro|La criatura objetivo obtiene +3/+3 y gana la habilidad de volar hasta el final del turno. (No puede ser bloqueado excepto por criaturas que tengan la habilidad de volar o alcance.) +Angelic Curator|Conservador angélico|Criatura - Ángel Espíritu|Vuela, protección de artefactos +Angelic Favor|Servicio angelical|Instantáneo|Si controlas una Llanura, puedes girar una criatura enderezada que controlas en lugar de pagar el coste de maná de este hechizo.\nLanza este hechizo sólo durante el combate.\nCrea una ficha criatura Ángel blanco 4/4 con la habilidad de vuelo. Exílialo al principio del siguiente paso final. +Angelic Protector|Protector angelical|Criatura — Ángel|Vuela\nSiempre que el Protector angelical se convierta en el objetivo de un hechizo o habilidad, el Protector angelical obtiene +0/+3 hasta el final del turno. +Angelic Renewal|Renovación angélica|Encantamiento|Cada vez que una criatura es puesta en tu cementerio desde el juego, puedes sacrificar la Renovación angélica. Si lo haces, devuelve esa carta al juego. +Angelic Shield|Escudo Angélico|Encantamiento|Las criaturas que controlas obtienen +0/+1.\nSacrifica al Escudo Angélico: Devuelve la criatura objetivo a la mano de su dueño. +Angry Mob|Turba|Criatura — Humano|Arrolla\nMientras sea tu turno, tanto la fuerza como la resistencia de la Turba son iguales a 2 más el número de Pantanos que controlan tus oponentes. Mientras no sea tu turno, tanto la fuerza como la resistencia de la Turba es igual a 2. +Animate Artifact|Animar artefacto|Encantamiento — Aura|Encantar artefacto\nMientras que el artefacto encantado no sea una criatura, es una criatura con poder y resistencia cada uno igual a su coste de maná convertido. +Animate Dead|Animar a los muertos|Encantamiento — Aura|Encantar la carta de criatura encantadora en un cementerio\nCuando Animar a los muertos entra en juego, si está en juego, pierde "encantar carta de criatura en un cementerio" y gana "encantar criatura puesta en juego con Animar a los muertos." Devuelve la carta de criatura encantada al juego bajo tu control y adjúntale Animar a los muertos. Cuando Animar a los muertos abandona el juego, el controlador de esa criatura lo sacrifica.\nLa criatura encantada obtiene -1/-0. +Animate Land|Animar la tierra|Instantáneo|Hasta el final del turno, la tierra objetivo se convierte en una criatura 3/3 que sigue siendo una tierra. +Animate Wall|Animar muro|Encantamiento — Aura|Encantar Muro\nEl Muro encantado puede atacar como si no tuviera defensor. +Ankh of Mishra|Ankh de Mishra|Artefacto|Cada vez que una tierra entra en juego, Ankh de Mishra inflige 2 puntos de daño al controlador de esa tierra. +Anoint|Untar|Instantáneo|Recuperar {3} (Puedes pagar {3} adicionales al lanzar este hechizo. Si lo haces, pon esta carta en tu mano en cuanto se resuelva.)\nEvita los siguientes 3 puntos de daños que se infligirían a la criatura objetivo en este turno. +Antagonism|Antagonismo|Encantamiento|Al comienzo del paso final de cada jugador, el Antagonismo inflige 2 puntos de daño a ese jugador a menos que uno de sus oponentes haya recibido daño en ese turno. +Anthroplasm|Antroplasma|Criatura — Metamorfo|El Antroplasma entra en juego con dos contadores +1/+1.\n{X}, {T}: Elimina todos los contadores +1/+1 del Antroplasma y ponle X contadores +1/+1 +Anti-Magic Aura|Aura antimagia|Encantamiento — Aura|Encantar criatura\nLa criatura encantada no puede ser el blanco de hechizos y no puede ser encantada por otras Auras. +Anvil of Bogardan|Yunque de Bogardan|Artefacto|Los jugadores no tienen un tamaño máximo de mano.\nAl principio del paso de cada jugador, ese jugador roba una carta adicional, y luego descarta una carta. +Anya, Merciless Angel|Anya, ángel despiadado|Criatura legendaria — Ángel|Vuela. Anya, ángel despiadado obtiene +3/+3 por cada oponente cuyo total de vidas sea menos que la mitad de su total de vidas inicial.Mientras el total de vidas de un oponente sea menos que la mitad de su total de vidas inicial, Anya tiene la habilidad de indestructible. +Apathy|Apatía|Encantamiento — Aura|Encantar criatura\nLa criatura encantada no se endereza durante el paso de enderezar de su controlador.\nAl comienzo del mantenimiento del controlador de la criatura encantada, ese jugador puede descartar una carta al azar. Si lo hace, endereza esa criatura. +Apes of Rath|Simios de Rath|Criatura — Simio|Siempre que los Simios de Rath ataquen, no se enderezan durante el siguiente paso de enderezar de su controlador. +Apocalypse Chime|Campana del Apocalipsis|Artefacto|{2}, {T}, Sacrificar Campana del Apocalipsis: Destruye todos los permanentes que no sean fichas con un nombre originalmente impreso en la expansión Homeland. No pueden ser regenerados. +Apocalypse|Apocalipsis|Conjuro|Exilia todos los permanentes. Descarta tu mano. +Apprentice Sorcerer|Hechicero aprendiz|Criatura — Hechicero humano|{T}: El Hechicero aprendiz inflige 1 de daño a cualquier objetivo. Activa esta habilidad sólo durante tu turno, antes de que los atacantes sean declarados. +Apprentice Wizard|Aprendiz de brujo|Criatura — Hechicero humano|{U}, {T}: Agrega {C}{C}{C}. +Arc Mage|Mago arco|Criatura — Hechicero humano|{2}{R}, {T}, Descarta una carta: el Mago arco inflige 2 puntos de daño divididos a tu elección entre uno o dos objetivos. +Arcane Laboratory|Laboratorio arcano|Encantamiento|Cada jugador no puede lanzar más de un hechizo por turno. +Archaeological Dig|Excavación Arqueológica|Tierra|{T}: Agrega {C}.\n{T}, Sacrifica Excavación Arqueológica: Agrega una maná de cualquier color. +Archangel|Arcángel|Criatura — Ángel|Vuela, vigilancia +Archery Training|Entrenamiento de arquería|Encantamiento — Aura|Encantar criatura\nAl comienzo de tu mantenimiento, puedes poner un contador de flechas en el Entrenamiento de arquería.\nLa criatura encantada tiene "{T}: Esta criatura inflige X de daño a la criatura que ataca o bloquea, donde X es el número de contadores de flecha en el Entrenamiento de arquería." +Arctic Foxes|Zorros árticos|Criatura — Zorro|Los Zorros árticos no pueden ser bloqueados por criaturas con fuerza 2 o superior mientras el jugador defensor controle una tierra nevada. +Arctic Merfolk|Tritón ártica|Criatura — Tritón|Estímulo — Devuelve una criatura que controlas a la mano de su dueño. (Puedes devolver una criatura que controlas a la mano de su dueño además de cualquier otro coste mientras lanzas este hechizo.)\nSi la Tritón ártica fue estimulada, entra en juego con una contador +1/+1. +Arctic Wolves|Lobos árticos|Criatura — Lobo|Mantenimiento acumulativo {2} (Al comienzo de tu mantenimiento, pon un contador de edad sobre este permanente, luego sacrifícalo a menos que pagues su coste de mantenimiento por cada contador de edad sobre él.)\nCuando los Lobos árticos entren en juego, roba una carta. +Arcum's Sleigh|Trineo de Arcum|Artefacto|{2}, {T}: La criatura objetivo gana vigilancia hasta el final del turno. Activa esta habilidad sólo durante el combate y sólo si el jugador defensor controla una tierra nevado. +Arcum's Weathervane|Veleta de Arcum|Artefacto|{2}, {T}: La tierra de nieve objetivo ya no es nieve.\n{2}, {T}:La tierra básica objetivo que no es nieve se convierte en nieve. +Arcum's Whistle|Silbato de Arcum|Artefacto|{3}, {T}: Elige una criatura objetivo que no sea Muro que el jugador activo haya controlado continuamente desde el comienzo del turno. Ese jugador puede pagar {X}, donde X es el coste de maná convertido de esa criatura. Si no pagan, la criatura ataca este turno si puede, y al comienzo del siguiente paso final, destrúyelo si no atacó este turno. Activa esta habilidad sólo antes de que los atacantes sean declarados. +Ardent Militia|Milicia enfervorecida|Criatura — Soldado humano|Vigilancia +Ardent Soldier|Soldado Ardoroso|Criatura — Soldado humano|Estímulo {2} (Puedes pagar {2} adicionales al lanzar este hechizo.)\nVigilancia\nSi el Soldado Ardoroso fue estimulado, entra en juego con una contador +1/+1. Forest|Bosque|Tierra básica - Bosque|({T}: Agrega {G}.) Island|Isla|Tierra básica - Isla|({T}: Agrega {U}.) Mountain|Montaña|Tierra básica - Montaña|({T}: Agrega {R}.) Plains|Llanura|Tierra básica - Llanura|({T}: Agrega {W}.) Swamp|Pantano|Tierra básica - Pantano|({T}: Agrega {B}.) - diff --git a/pom.xml b/pom.xml index 69db0d4163a..847f427aabf 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ forge pom Forge Parent - 1.6.30-SNAPSHOT + 1.6.31-SNAPSHOT Forge lets you play the card game Magic: The Gathering against a computer opponent using all of the rules.