* Name card abilities - fixed that it can't find split cards or fused spells with entered name (part of #6603, #6549);

This commit is contained in:
Oleg Agafonov 2020-06-05 00:06:57 +04:00
parent e95ae2675b
commit 4b77cb0fa8
30 changed files with 257 additions and 53 deletions

View file

@ -61,7 +61,7 @@ class BileBlightEffect extends BoostAllEffect {
} else {
String name = target.getName();
for (Permanent perm : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) {
if (CardUtil.haveSameNames(perm.getName(), name)) {
if (CardUtil.haveSameNames(perm, name, game)) {
affectedObjectList.add(new MageObjectReference(perm, game));
}
}

View file

@ -60,7 +60,7 @@ class BrainPryEffect extends OneShotEffect {
if (targetPlayer != null && controller != null && sourceObject != null && cardName != null) {
boolean hasDiscarded = false;
for (Card card : targetPlayer.getHand().getCards(game)) {
if (CardUtil.haveSameNames(card.getName(), cardName)) {
if (CardUtil.haveSameNames(card, cardName, game)) {
targetPlayer.discard(card, source, game);
hasDiscarded = true;
break;

View file

@ -90,18 +90,7 @@ class CabalTherapistDiscardEffect extends OneShotEffect {
if (card == null) {
return true;
}
if (card.isSplitCard()) {
SplitCard splitCard = (SplitCard) card;
if (CardUtil.haveSameNames(splitCard.getLeftHalfCard().getName(), cardName)) {
return false;
} else if (CardUtil.haveSameNames(splitCard.getRightHalfCard().getName(), cardName)) {
return false;
}
}
if (CardUtil.haveSameNames(card.getName(), cardName)) {
return false;
}
return true;
return !CardUtil.haveSameNames(card, cardName, game);
});
targetPlayer.discard(hand, source, game);
return true;

View file

@ -75,18 +75,7 @@ class CabalTherapyEffect extends OneShotEffect {
if (card == null) {
return true;
}
if (card.isSplitCard()) {
SplitCard splitCard = (SplitCard) card;
if (CardUtil.haveSameNames(splitCard.getLeftHalfCard().getName(), cardName)) {
return false;
} else if (CardUtil.haveSameNames(splitCard.getRightHalfCard().getName(), cardName)) {
return false;
}
}
if (CardUtil.haveSameNames(card.getName(), cardName)) {
return false;
}
return true;
return !CardUtil.haveSameNames(card, cardName, game);
});
targetPlayer.discard(hand, source, game);
return true;

View file

@ -85,7 +85,7 @@ class ConundrumSphinxEffect extends OneShotEffect {
if (card != null) {
Cards cards = new CardsImpl(card);
player.revealCards(source, player.getName(), cards, game);
if (CardUtil.haveSameNames(card.getName(), cardName)) {
if (CardUtil.haveSameNames(card, cardName, game)) {
player.moveCards(cards, Zone.HAND, source, game);
} else {
player.putCardsOnBottomOfLibrary(cards, game, source, false);

View file

@ -133,7 +133,7 @@ class CorrosiveOozeCombatWatcher extends Watcher {
if (event.getType() == GameEvent.EventType.BLOCKER_DECLARED) {
Permanent attacker = game.getPermanent(event.getTargetId());
Permanent blocker = game.getPermanent(event.getSourceId());
if (attacker != null && CardUtil.haveSameNames(attacker.getName(), "Corrosive Ooze")) { // To check for name is not working if Ooze is copied but name changed
if (attacker != null && CardUtil.haveSameNames(attacker, "Corrosive Ooze", game)) { // To check for name is not working if Ooze is copied but name changed
if (blocker != null && hasAttachedEquipment(game, blocker)) {
MageObjectReference oozeMor = new MageObjectReference(attacker, game);
Set<MageObjectReference> relatedCreatures = oozeBlocksOrBlocked.getOrDefault(oozeMor, new HashSet<>());
@ -141,7 +141,7 @@ class CorrosiveOozeCombatWatcher extends Watcher {
oozeBlocksOrBlocked.put(oozeMor, relatedCreatures);
}
}
if (blocker != null && CardUtil.haveSameNames(blocker.getName(), "Corrosive Ooze")) {
if (blocker != null && CardUtil.haveSameNames(blocker, "Corrosive Ooze", game)) {
if (attacker != null && hasAttachedEquipment(game, attacker)) {
MageObjectReference oozeMor = new MageObjectReference(blocker, game);
Set<MageObjectReference> relatedCreatures = oozeBlocksOrBlocked.getOrDefault(oozeMor, new HashSet<>());

View file

@ -93,7 +93,7 @@ class CouncilOfTheAbsoluteReplacementEffect extends ContinuousRuleModifyingEffec
if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) {
MageObject object = game.getObject(event.getSourceId());
String needName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY);
return object != null && CardUtil.haveSameNames(object.getName(), needName);
return object != null && CardUtil.haveSameNames(object, needName, game);
}
return false;
}
@ -123,7 +123,7 @@ class CouncilOfTheAbsoluteCostReductionEffect extends CostModificationEffectImpl
Card card = game.getCard(abilityToModify.getSourceId());
if (card != null) {
String needName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY);
return CardUtil.haveSameNames(card.getName(), needName);
return CardUtil.haveSameNames(card, needName, game);
}
}
return false;

View file

@ -61,9 +61,9 @@ class CrownOfEmpiresEffect extends OneShotEffect {
boolean scepter = false;
boolean throne = false;
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) {
if (CardUtil.haveSameNames(permanent.getName(), "Scepter of Empires")) {
if (CardUtil.haveSameNames(permanent, "Scepter of Empires", game)) {
scepter = true;
} else if (CardUtil.haveSameNames(permanent.getName(), "Throne of Empires")) {
} else if (CardUtil.haveSameNames(permanent, "Throne of Empires", game)) {
throne = true;
}
if (scepter && throne) break;

View file

@ -70,7 +70,7 @@ class CursedScrollEffect extends OneShotEffect {
}
revealed.add(card);
controller.revealCards(sourceObject.getIdName(), revealed, game);
if (CardUtil.haveSameNames(card.getName(), cardName)) {
if (CardUtil.haveSameNames(card, cardName, game)) {
Permanent creature = game.getPermanent(targetPointer.getFirst(game, source));
if (creature != null) {
creature.damage(2, source.getSourceId(), game, false, true);

View file

@ -72,6 +72,6 @@ class DeathbellowWarCryTarget extends TargetCardInLibrary {
.map(game::getCard)
.filter(Objects::nonNull)
.map(Card::getName)
.noneMatch(n -> CardUtil.haveSameNames(n, card.getName()));
.noneMatch(n -> CardUtil.haveSameNames(card, n, game));
}
}

View file

@ -86,7 +86,7 @@ class DementiaSliverEffect extends OneShotEffect {
if (card != null) {
revealed.add(card);
opponent.revealCards(sourceObject.getName(), revealed, game);
if (CardUtil.haveSameNames(card.getName(), cardName)) {
if (CardUtil.haveSameNames(card, cardName, game)) {
opponent.discard(card, source, game);
}
}

View file

@ -63,7 +63,7 @@ class DeniedEffect extends OneShotEffect {
player.revealCards("Denied!", player.getHand(), game, true);
String namedCard = (String) object;
for (Card card : player.getHand().getCards(game)) {
if (card != null && CardUtil.haveSameNames(card.getName(), namedCard)) {
if (card != null && CardUtil.haveSameNames(card, namedCard, game)) {
game.getStack().counter(targetSpell.getId(), source.getSourceId(), game);
break;
}

View file

@ -85,7 +85,7 @@ class DetentionSphereEntersEffect extends OneShotEffect {
} else {
String name = targetPermanent.getName();
for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) {
if (permanent != null && CardUtil.haveSameNames(permanent.getName(), name)) {
if (permanent != null && CardUtil.haveSameNames(permanent, name, game)) {
controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true);
}
}

View file

@ -92,7 +92,7 @@ public final class DiviningWitch extends CardImpl {
if (card != null) {
cardsToReaveal.add(card);
// Put that card into your hand
if (CardUtil.haveSameNames(card.getName(), name)) {
if (CardUtil.haveSameNames(card, name, game)) {
cardToHand = card;
break;
}

View file

@ -72,7 +72,7 @@ class ForeshadowEffect extends OneShotEffect {
Card card = targetPlayer.getLibrary().getFromTop(game);
if (card != null) {
controller.moveCards(card, Zone.GRAVEYARD, source, game);
if (CardUtil.haveSameNames(card.getName(), cardName)) {
if (CardUtil.haveSameNames(card, cardName, game)) {
controller.drawCards(1, source.getSourceId(), game);
}
}

View file

@ -71,7 +71,7 @@ class LammastideWeaveEffect extends OneShotEffect {
Card card = targetPlayer.getLibrary().getFromTop(game);
if (card != null) {
controller.moveCards(card, Zone.GRAVEYARD, source, game);
if (CardUtil.haveSameNames(card.getName(), cardName)) {
if (CardUtil.haveSameNames(card, cardName, game)) {
controller.gainLife(card.getConvertedManaCost(), game, source);
}
}

View file

@ -93,7 +93,7 @@ class LiarsPendulumEffect extends OneShotEffect {
rightGuess = opponentGuess;
}
}
if (CardUtil.haveSameNames(card.getName(), cardName)) {
if (CardUtil.haveSameNames(card, cardName, game)) {
rightGuess = opponentGuess;
}
}

View file

@ -76,7 +76,7 @@ class MagusOfTheScrollEffect extends OneShotEffect {
}
revealed.add(card);
you.revealCards(sourceObject.getName(), revealed, game);
if (CardUtil.haveSameNames(card.getName(), cardName)) {
if (CardUtil.haveSameNames(card, cardName, game)) {
Permanent creature = game.getPermanent(targetPointer.getFirst(game, source));
if (creature != null) {
creature.damage(2, source.getSourceId(), game, false, true);

View file

@ -78,7 +78,7 @@ class PetraSphinxEffect extends OneShotEffect {
if (card != null) {
Cards cards = new CardsImpl(card);
player.revealCards(source, cards, game);
if (CardUtil.haveSameNames(card.getName(), cardName)) {
if (CardUtil.haveSameNames(card, cardName, game)) {
player.moveCards(cards, Zone.HAND, source, game);
} else {
player.moveCards(cards, Zone.GRAVEYARD, source, game);

View file

@ -67,7 +67,7 @@ class PredictEffect extends OneShotEffect {
Card card = targetPlayer.getLibrary().getFromTop(game);
if (card != null) {
controller.moveCards(card, Zone.GRAVEYARD, source, game);
if (CardUtil.haveSameNames(card.getName(), cardName)) {
if (CardUtil.haveSameNames(card, cardName, game)) {
amount = 2;
}
}

View file

@ -119,7 +119,7 @@ class ExclusionRitualReplacementEffect extends ContinuousRuleModifyingEffectImpl
if (spell != null && spell.isFaceDown(game)) {
return false; // Face Down cast spell (Morph creature) has no name
}
return CardUtil.haveSameNames(card.getName(), creatureName) && Objects.equals(ownerId, card.getOwnerId());
return CardUtil.haveSameNames(card, creatureName, game) && Objects.equals(ownerId, card.getOwnerId());
}
return false;
}

View file

@ -157,7 +157,7 @@ class SearchTheCityExiledCardToHandEffect extends OneShotEffect {
ExileZone searchTheCityExileZone = game.getExile().getExileZone(source.getSourceId());
if (cardName != null && searchTheCityExileZone != null) {
for (Card card : searchTheCityExileZone.getCards(game)) {
if (CardUtil.haveSameNames(card.getName(), cardName)) {
if (CardUtil.haveSameNames(card, cardName, game)) {
if (card.moveToZone(Zone.HAND, source.getSourceId(), game, true)) {
game.informPlayers("Search the City: put " + card.getName() + " into owner's hand");
}

View file

@ -68,7 +68,7 @@ class SpoilsOfTheVaultEffect extends OneShotEffect {
for (Card card : controller.getLibrary().getCards(game)) {
if (card != null) {
cardsToReveal.add(card);
if (CardUtil.haveSameNames(card.getName(), cardName)) {
if (CardUtil.haveSameNames(card, cardName, game)) {
controller.moveCards(card, Zone.HAND, source, game);
break;
} else {

View file

@ -86,7 +86,7 @@ class ThoughtHemorrhageEffect extends OneShotEffect {
+ targetPlayer.getName(), targetPlayer.getHand(), game);
int cardsFound = 0;
for (Card card : targetPlayer.getHand().getCards(game)) {
if (CardUtil.haveSameNames(card.getName(), cardName)) {
if (CardUtil.haveSameNames(card, cardName, game)) {
cardsFound++;
}
}

View file

@ -73,7 +73,7 @@ class TunnelVisionEffect extends OneShotEffect {
for (Card card : targetPlayer.getLibrary().getCards(game)) {
cardsToReveal.add(card);
if (CardUtil.haveSameNames(card.getName(), cardName)) {
if (CardUtil.haveSameNames(card, cardName, game)) {
namedCard = card;
break;
}

View file

@ -74,7 +74,7 @@ class VexingArcanixEffect extends OneShotEffect {
if (card != null) {
Cards cards = new CardsImpl(card);
player.revealCards(sourceObject.getIdName(), cards, game);
if (CardUtil.haveSameNames(card.getName(), cardName)) {
if (CardUtil.haveSameNames(card, cardName, game)) {
player.moveCards(cards, Zone.HAND, source, game);
} else {
player.moveCards(cards, Zone.GRAVEYARD, source, game);

View file

@ -0,0 +1,201 @@
package org.mage.test.cards.split;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author JayDi85
*/
public class CastSplitCardsWithCostModificationTest extends CardTestPlayerBase {
@Test
public void test_CostReduction_Simple() {
// {2}{W}{U}
// As Council of the Absolute enters the battlefield, choose a noncreature, nonland card name.
// Your opponents cant cast spells with the chosen name.
// Spells with the chosen name you cast cost {2} less to cast.
addCard(Zone.HAND, playerA, "Council of the Absolute", 1);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
//
addCard(Zone.HAND, playerA, "Blastfire Bolt", 1); // {5}{R}, 5 damage
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6 - 2); // -2 for cost reduction
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1);
// cast Council
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Council of the Absolute");
setChoice(playerA, "Blastfire Bolt");
// cast bolt
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Blastfire Bolt", "Balduvian Bears");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertAllCommandsUsed();
assertGraveyardCount(playerB, "Balduvian Bears", 1);
}
@Test
public void test_CostReduction_SplitLeft() {
// {2}{W}{U}
// As Council of the Absolute enters the battlefield, choose a noncreature, nonland card name.
// Your opponents cant cast spells with the chosen name.
// Spells with the chosen name you cast cost {2} less to cast.
addCard(Zone.HAND, playerA, "Council of the Absolute", 1);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
//
// Armed {1}{R} Target creature gets +1/+1 and gains double strike until end of turn.
// Dangerous {3}{G} All creatures able to block target creature this turn do so.
addCard(Zone.HAND, playerA, "Armed // Dangerous", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2 - 1); // -1 from cost reduction
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4 - 2); // check not working right cost reduction
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1);
// cast Council
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {W}", 3);
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {U}", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Council of the Absolute");
setChoice(playerA, "Armed");
// cast Armed
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("after reduction", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Armed", true);
checkPlayableAbility("after reduction", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Dangerous", false);
checkPlayableAbility("after reduction", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast fused Armed // Dangerous", false);
showAvaileableAbilities("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Armed", "Balduvian Bears");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertAllCommandsUsed();
assertGraveyardCount(playerA, "Armed // Dangerous", 1);
}
@Test
public void test_CostReduction_SplitRight() {
// {2}{W}{U}
// As Council of the Absolute enters the battlefield, choose a noncreature, nonland card name.
// Your opponents cant cast spells with the chosen name.
// Spells with the chosen name you cast cost {2} less to cast.
addCard(Zone.HAND, playerA, "Council of the Absolute", 1);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
//
// Armed {1}{R} Target creature gets +1/+1 and gains double strike until end of turn.
// Dangerous {3}{G} All creatures able to block target creature this turn do so.
addCard(Zone.HAND, playerA, "Armed // Dangerous", 1);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4 - 2); // -2 from cost reduction
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1);
// cast Council
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {W}", 3);
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {U}", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Council of the Absolute");
setChoice(playerA, "Dangerous");
// cast Dangerous
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("after reduction", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Armed", false);
checkPlayableAbility("after reduction", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Dangerous", true);
checkPlayableAbility("after reduction", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast fused Armed // Dangerous", false);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Dangerous", "Balduvian Bears");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertAllCommandsUsed();
assertGraveyardCount(playerA, "Armed // Dangerous", 1);
}
@Test
@Ignore // TODO: cost modification don't work for fused spells, only for one of the part, see https://github.com/magefree/mage/issues/6603
public void test_CostReduction_SplitFused_ReduceRight() {
// {2}{W}{U}
// As Council of the Absolute enters the battlefield, choose a noncreature, nonland card name.
// Your opponents cant cast spells with the chosen name.
// Spells with the chosen name you cast cost {2} less to cast.
addCard(Zone.HAND, playerA, "Council of the Absolute", 1);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
//
// Armed {1}{R} Target creature gets +1/+1 and gains double strike until end of turn.
// Dangerous {3}{G} All creatures able to block target creature this turn do so.
addCard(Zone.HAND, playerA, "Armed // Dangerous", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); // no cost reduction
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4 - 2); // -2 from cost reduction
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1);
// cast Council
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {W}", 3);
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {U}", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Council of the Absolute");
setChoice(playerA, "Dangerous");
// cast fused
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("after reduction", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Armed", true);
checkPlayableAbility("after reduction", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Dangerous", true);
checkPlayableAbility("after reduction", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast fused Armed // Dangerous", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "fused Armed // Dangerous");
addTarget(playerA, "Balduvian Bears");
addTarget(playerA, "Balduvian Bears");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertAllCommandsUsed();
assertGraveyardCount(playerA, "Armed // Dangerous", 1);
}
@Test
@Ignore // TODO: cost modification don't work for fused spells, only for one of the part, see https://github.com/magefree/mage/issues/6603
public void test_CostReduction_SplitFused_ReduceLeft() {
// {2}{W}{U}
// As Council of the Absolute enters the battlefield, choose a noncreature, nonland card name.
// Your opponents cant cast spells with the chosen name.
// Spells with the chosen name you cast cost {2} less to cast.
addCard(Zone.HAND, playerA, "Council of the Absolute", 1);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
//
// Armed {1}{R} Target creature gets +1/+1 and gains double strike until end of turn.
// Dangerous {3}{G} All creatures able to block target creature this turn do so.
addCard(Zone.HAND, playerA, "Armed // Dangerous", 1);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2 - 1); // -1 from cost reduction
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4 - 1); // -1 from cost reduction ON FUSED
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1);
// cast Council
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {W}", 3);
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {U}", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Council of the Absolute");
setChoice(playerA, "Armed");
// cast fused
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPlayableAbility("after reduction", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Armed", true);
checkPlayableAbility("after reduction", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Dangerous", true);
checkPlayableAbility("after reduction", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast fused Armed // Dangerous", true);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "fused Armed // Dangerous");
addTarget(playerA, "Balduvian Bears");
addTarget(playerA, "Balduvian Bears");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertAllCommandsUsed();
assertGraveyardCount(playerA, "Armed // Dangerous", 1);
}
}

View file

@ -1,5 +1,7 @@
package org.mage.test.testapi;
import mage.cards.Card;
import mage.cards.repository.CardRepository;
import mage.constants.EmptyNames;
import mage.constants.PhaseStep;
import mage.constants.Zone;
@ -44,6 +46,18 @@ public class TestAliases extends CardTestPlayerBase {
Assert.assertFalse(CardUtil.haveSameNames("Name", "123", true));
Assert.assertFalse(CardUtil.haveSameNames("Name", EmptyNames.FACE_DOWN_CREATURE.toString(), true));
Assert.assertFalse(CardUtil.haveSameNames("Name1", "Name2", true));
// name with split card
Card splitCard1 = CardRepository.instance.findCard("Armed // Dangerous").getCard();
Card splitCard2 = CardRepository.instance.findCard("Alive // Well").getCard();
Assert.assertTrue(CardUtil.haveSameNames(splitCard1, "Armed", currentGame));
Assert.assertTrue(CardUtil.haveSameNames(splitCard1, "Dangerous", currentGame));
Assert.assertTrue(CardUtil.haveSameNames(splitCard1, "Armed // Dangerous", currentGame));
Assert.assertTrue(CardUtil.haveSameNames(splitCard1, splitCard1));
Assert.assertFalse(CardUtil.haveSameNames(splitCard1, "Other", currentGame));
Assert.assertFalse(CardUtil.haveSameNames(splitCard1, "Other // Dangerous", currentGame));
Assert.assertFalse(CardUtil.haveSameNames(splitCard1, "Armed // Other", currentGame));
Assert.assertFalse(CardUtil.haveSameNames(splitCard1, splitCard2));
}
@Test

View file

@ -31,11 +31,13 @@ public class NamePredicate implements Predicate<MageObject> {
// A split card has the chosen name if one of its two names matches the chosen name.
if (input instanceof SplitCard) {
return CardUtil.haveSameNames(name, ((SplitCard) input).getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) ||
CardUtil.haveSameNames(name, ((SplitCard) input).getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames);
CardUtil.haveSameNames(name, ((SplitCard) input).getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) ||
CardUtil.haveSameNames(name, input.getName(), this.ignoreMtgRuleForEmptyNames);
} else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) {
SplitCard card = (SplitCard) ((Spell) input).getCard();
return CardUtil.haveSameNames(name, card.getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) ||
CardUtil.haveSameNames(name, card.getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames);
CardUtil.haveSameNames(name, card.getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) ||
CardUtil.haveSameNames(name, card.getName(), this.ignoreMtgRuleForEmptyNames);
} else {
if (name.contains(" // ")) {
String leftName = name.substring(0, name.indexOf(" // "));

View file

@ -11,6 +11,7 @@ import mage.constants.ColoredManaSymbol;
import mage.constants.EmptyNames;
import mage.constants.ManaType;
import mage.filter.Filter;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.game.CardState;
import mage.game.Game;
import mage.game.permanent.Permanent;
@ -657,6 +658,14 @@ public final class CardUtil {
return object1 != null && object2 != null && haveSameNames(object1.getName(), object2.getName());
}
public static boolean haveSameNames(MageObject object, String needName, Game game) {
return containsName(object, needName, game);
}
public static boolean containsName(MageObject object, String name, Game game) {
return new NamePredicate(name).apply(object, game);
}
public static boolean haveEmptyName(String name) {
return name == null || name.isEmpty() || name.equals(EmptyNames.FACE_DOWN_CREATURE.toString()) || name.equals(EmptyNames.FACE_DOWN_TOKEN.toString());
}