* Curse cards - fixed that it triggers on planeswalker attack only (#5566);

This commit is contained in:
Oleg Agafonov 2019-02-09 15:40:23 +04:00
parent c6f0239bcd
commit e285b2770d
6 changed files with 110 additions and 32 deletions

View file

@ -1,4 +1,3 @@
package mage.cards.c;
import mage.abilities.Ability;
@ -24,13 +23,12 @@ import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class CurseOfChaos extends CardImpl {
public CurseOfChaos(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}");
this.subtype.add(SubType.AURA, SubType.CURSE);
@ -74,9 +72,9 @@ class CurseOfChaosTriggeredAbility extends TriggeredAbilityImpl {
Permanent enchantment = game.getPermanent(this.getSourceId());
if (enchantment != null
&& enchantment.getAttachedTo() != null
&& game.getCombat().getPlayerDefenders(game).contains(enchantment.getAttachedTo())) {
for (Effect effect: this.getEffects()) {
effect.setTargetPointer(new FixedTarget(game.getCombat().getAttackingPlayerId()));
&& game.getCombat().getPlayerDefenders(game, false).contains(enchantment.getAttachedTo())) {
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(game.getCombat().getAttackingPlayerId()));
}
return true;
}
@ -115,7 +113,7 @@ class CurseOfChaosEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player attacker = game.getPlayer(this.getTargetPointer().getFirst(game, source));
if (attacker != null) {
if (!attacker.getHand().isEmpty() && attacker.chooseUse(outcome, "Discard a card and draw a card?", source, game)){
if (!attacker.getHand().isEmpty() && attacker.chooseUse(outcome, "Discard a card and draw a card?", source, game)) {
attacker.discard(1, false, source, game);
attacker.drawCards(1, game);
}

View file

@ -1,4 +1,3 @@
package mage.cards.c;
import mage.abilities.Ability;
@ -23,13 +22,12 @@ import mage.target.TargetPlayer;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class CurseOfInertia extends CardImpl {
public CurseOfInertia(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}");
this.subtype.add(SubType.AURA, SubType.CURSE);
@ -59,7 +57,7 @@ class CurseOfInertiaTriggeredAbility extends TriggeredAbilityImpl {
public CurseOfInertiaTriggeredAbility() {
super(Zone.BATTLEFIELD, new CurseOfInertiaTapOrUntapTargetEffect(), false);
}
public CurseOfInertiaTriggeredAbility(final CurseOfInertiaTriggeredAbility ability) {
super(ability);
}
@ -74,7 +72,7 @@ class CurseOfInertiaTriggeredAbility extends TriggeredAbilityImpl {
Permanent enchantment = game.getPermanent(this.getSourceId());
if (enchantment != null
&& enchantment.getAttachedTo() != null
&& game.getCombat().getPlayerDefenders(game).contains(enchantment.getAttachedTo())) {
&& game.getCombat().getPlayerDefenders(game, false).contains(enchantment.getAttachedTo())) {
TargetPermanent target = new TargetPermanent();
target.setTargetController(game.getCombat().getAttackingPlayerId());
addTarget(target);

View file

@ -1,4 +1,3 @@
package mage.cards.c;
import mage.abilities.Ability;
@ -27,7 +26,6 @@ import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class CurseOfShallowGraves extends CardImpl {
@ -80,7 +78,7 @@ class CurseOfShallowTriggeredAbility extends TriggeredAbilityImpl {
Permanent enchantment = game.getPermanent(this.getSourceId());
if (enchantment != null
&& enchantment.getAttachedTo() != null
&& game.getCombat().getPlayerDefenders(game).contains(enchantment.getAttachedTo())) {
&& game.getCombat().getPlayerDefenders(game, false).contains(enchantment.getAttachedTo())) {
for (Effect effect : this.getEffects()) {
effect.setTargetPointer(new FixedTarget(game.getCombat().getAttackingPlayerId()));
}

View file

@ -0,0 +1,79 @@
package org.mage.test.cards.abilities.curses;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author JayDi85
*/
public class CurseOfShallowGravesTest extends CardTestPlayerBase {
/*
Curse of Shallow Graves
{2}{B}
Enchant player
Whenever a player attacks enchanted player with one or more creatures, that attacking player may create a tapped 2/2 black Zombie creature token.
bug: https://www.slightlymagic.net/forum/viewtopic.php?f=70&t=23164&p=229567#p229567
*/
@Test
public void test_AttackPlayer() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
addCard(Zone.HAND, playerA, "Curse of Shallow Graves");
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1); // 2/2
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curse of Shallow Graves", playerB);
checkPermanentCount("curse on battle", 1, PhaseStep.BEGIN_COMBAT, playerA, "Curse of Shallow Graves", 1);
// turn 1 - attack without token
attack(1, playerA, "Balduvian Bears", playerB);
setChoice(playerA, "No"); // don't create token
checkPermanentCount("zombie 0", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie", 0);
// turn 3 - attack with token
attack(3, playerA, "Balduvian Bears", playerB);
setChoice(playerA, "Yes"); // create token
checkPermanentCount("zombie 1", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie", 1);
setStopAt(3, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertLife(playerA, 20);
assertLife(playerB, 20 - 2 - 2);
}
@Test
public void test_AttackPlaneswalker() {
// planeswalker only attack must be ignored by token's effect
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
addCard(Zone.HAND, playerA, "Curse of Shallow Graves");
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1); // 2/2
addCard(Zone.BATTLEFIELD, playerB, "Chandra Ablaze", 1); // 5 loyalty
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curse of Shallow Graves", playerB);
checkPermanentCount("curse on battle", 1, PhaseStep.BEGIN_COMBAT, playerA, "Curse of Shallow Graves", 1);
// turn 1 - attack player without token
attack(1, playerA, "Balduvian Bears", playerB);
setChoice(playerA, "No"); // don't create token
checkPermanentCount("zombie 0", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie", 0);
// turn 3 - attack planeswalker (no choices at all)
attack(3, playerA, "Balduvian Bears", "Chandra Ablaze");
//setChoice(playerA, "Yes");
checkPermanentCount("zombie 0", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie", 0);
setStopAt(3, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertLife(playerA, 20);
assertLife(playerB, 20 - 2);
assertCounterCount(playerB, "Chandra Ablaze", CounterType.LOYALTY, 5 - 2);
}
}

View file

@ -1,4 +1,3 @@
package mage.abilities.common;
import mage.abilities.TriggeredAbilityImpl;
@ -10,7 +9,6 @@ import mage.game.permanent.Permanent;
import mage.players.Player;
/**
*
* @author LevelX2
*/
public class EnchantedPlayerAttackedTriggeredAbility extends TriggeredAbilityImpl {
@ -35,7 +33,7 @@ public class EnchantedPlayerAttackedTriggeredAbility extends TriggeredAbilityImp
Permanent enchantment = game.getPermanentOrLKIBattlefield(getSourceId());
Player controller = game.getPlayer(getControllerId());
if (controller != null && enchantment != null) {
return game.getCombat().getPlayerDefenders(game).contains(enchantment.getAttachedTo());
return game.getCombat().getPlayerDefenders(game, false).contains(enchantment.getAttachedTo());
}
return false;
}

View file

@ -275,7 +275,7 @@ public class Combat implements Serializable, Copyable<Combat> {
Permanent attackingPermanent = game.getPermanent(attacker);
if (attackingPermanent != null) {
attackingPermanent.setTapped(false);
attackingPermanent.tap(true,game); // to tap with event finally here is needed to prevent abusing of Vampire Envoy like cards
attackingPermanent.tap(true, game); // to tap with event finally here is needed to prevent abusing of Vampire Envoy like cards
}
}
handleBanding(attacker, game);
@ -298,11 +298,11 @@ public class Combat implements Serializable, Copyable<Combat> {
private void handleBanding(UUID creatureId, Game game) {
Player player = game.getPlayer(attackingPlayerId);
Permanent attacker = game.getPermanent(creatureId);
if (attacker != null
if (attacker != null
&& player != null) {
CombatGroup combatGroup = findGroup(attacker.getId());
if (combatGroup != null
&& attacker.getBandedCards().isEmpty()
if (combatGroup != null
&& attacker.getBandedCards().isEmpty()
&& getAttackers().size() > 1) {
boolean canBand = attacker.getAbilities().containsKey(BandingAbility.getInstance().getId());
List<Ability> bandsWithOther = new ArrayList<>();
@ -318,7 +318,7 @@ public class Combat implements Serializable, Copyable<Combat> {
filter.add(Predicates.not(new PermanentIdPredicate(creatureId)));
filter.add(new AttackingSameNotBandedPredicate(combatGroup.getDefenderId())); // creature that isn't already banded, and is attacking the same player or planeswalker
List<Predicate<MageObject>> predicates = new ArrayList<>();
if (!canBand
if (!canBand
&& canBandWithOther) {
for (Ability ab : bandsWithOther) {
BandsWithOtherAbility ability = (BandsWithOtherAbility) ab;
@ -341,15 +341,15 @@ public class Combat implements Serializable, Copyable<Combat> {
canBandWithOther &= target.canChoose(attackingPlayerId, game);
if (game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_ATTACKERS, attackingPlayerId, attackingPlayerId))
|| (!canBand && !canBandWithOther)
|| !player.chooseUse(Outcome.Benefit,
"Do you wish to " + (isBanded ? "band " + attacker.getLogName()
+ " with another " : "form a band with " + attacker.getLogName() + " and an ")
+ "attacking creature?", null, game)) {
|| !player.chooseUse(Outcome.Benefit,
"Do you wish to " + (isBanded ? "band " + attacker.getLogName()
+ " with another " : "form a band with " + attacker.getLogName() + " and an ")
+ "attacking creature?", null, game)) {
break;
}
if (canBand && canBandWithOther) {
if (player.chooseUse(Outcome.Detriment, "Choose type of banding ability to apply:",
if (player.chooseUse(Outcome.Detriment, "Choose type of banding ability to apply:",
attacker.getLogName(), "Banding", "Bands with other", null, game)) {
canBandWithOther = false;
} else {
@ -564,7 +564,7 @@ public class Combat implements Serializable, Copyable<Combat> {
* Handle the blocker selection process
*
* @param blockController player that controls how to block, if null the
* defender is the controller
* defender is the controller
* @param game
*/
public void selectBlockers(Player blockController, Game game) {
@ -752,8 +752,8 @@ public class Combat implements Serializable, Copyable<Combat> {
* creature can't block unless a player pays a cost, that player is not
* required to pay that cost, even if blocking with that creature would
* increase the number of requirements being obeyed.
*
*
* <p>
* <p>
* Example: A player controls one creature that "blocks if able" and another
* creature with no abilities. An effect states "Creatures can't be blocked
* except by two or more creatures." Having only the first creature block
@ -1374,7 +1374,7 @@ public class Combat implements Serializable, Copyable<Combat> {
* @param playerId
* @param game
* @param solveBanding check whether also add creatures banded with
* attackerId
* attackerId
*/
public void addBlockingGroup(UUID blockerId, UUID attackerId, UUID playerId, Game game, boolean solveBanding) {
Permanent blocker = game.getPermanent(blockerId);
@ -1578,8 +1578,15 @@ public class Combat implements Serializable, Copyable<Combat> {
}
public Set<UUID> getPlayerDefenders(Game game) {
return getPlayerDefenders(game, true);
}
public Set<UUID> getPlayerDefenders(Game game, boolean includePlaneswalkers) {
Set<UUID> playerDefenders = new HashSet<>();
for (CombatGroup group : groups) {
if (group.defenderIsPlaneswalker && !includePlaneswalkers) {
continue;
}
if (group.defenderIsPlaneswalker) {
Permanent permanent = game.getPermanent(group.getDefenderId());
if (permanent != null) {