mirror of
https://github.com/magefree/mage.git
synced 2026-01-26 21:29:17 -08:00
* Curse cards - fixed that it triggers on planeswalker attack only (#5566);
This commit is contained in:
parent
c6f0239bcd
commit
e285b2770d
6 changed files with 110 additions and 32 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue