mirror of
https://github.com/correl/mage.git
synced 2024-11-25 03:00:11 +00:00
[SNC] Implemented shield counter mechanic (#8830)
* [SNC] Implemented shield counter mechanic * Rework shield counter to be a global replacement effect * Add unit test for shield counter Co-authored-by: Evan Kranzler <theelk801@gmail.com>
This commit is contained in:
parent
a1c62f4495
commit
63239fe8e6
4 changed files with 134 additions and 1 deletions
|
@ -12,7 +12,7 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public final class StreetsOfNewCapenna extends ExpansionSet {
|
public final class StreetsOfNewCapenna extends ExpansionSet {
|
||||||
|
|
||||||
private static final List<String> unfinished = Arrays.asList("Caldaia Strongarm", "Disciplined Duelist", "Elspeth Resplendent", "Falco Spara, Pactweaver", "Jaxis, the Troublemaker", "Mayhem Patrol", "Night Clubber", "Plasma Jockey", "Workshop Warchief", "Ziatora's Envoy");
|
private static final List<String> unfinished = Arrays.asList("Elspeth Resplendent", "Falco Spara, Pactweaver", "Jaxis, the Troublemaker");
|
||||||
|
|
||||||
private static final StreetsOfNewCapenna instance = new StreetsOfNewCapenna();
|
private static final StreetsOfNewCapenna instance = new StreetsOfNewCapenna();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package org.mage.test.cards.replacement;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.counters.CounterType;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author weirddan455
|
||||||
|
*/
|
||||||
|
public class ShieldCounterTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoncombatDamage() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Disciplined Duelist");
|
||||||
|
addCard(Zone.HAND, playerA, "Lightning Bolt", 2);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt");
|
||||||
|
addTarget(playerA, "Disciplined Duelist");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertPermanentCount(playerA, "Disciplined Duelist", 1);
|
||||||
|
assertCounterCount("Disciplined Duelist", CounterType.SHIELD, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCombatDamage() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Disciplined Duelist");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Hill Giant");
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
attack(1, playerA, "Disciplined Duelist");
|
||||||
|
block(1, playerB, "Hill Giant", "Disciplined Duelist");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertPermanentCount(playerA, "Disciplined Duelist", 1);
|
||||||
|
assertCounterCount("Disciplined Duelist", CounterType.SHIELD, 0);
|
||||||
|
assertGraveyardCount(playerB, "Hill Giant", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDestroyEffect() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Disciplined Duelist");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||||
|
addCard(Zone.HAND, playerA, "Murder");
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Murder");
|
||||||
|
addTarget(playerA, "Disciplined Duelist");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertPermanentCount(playerA, "Disciplined Duelist", 1);
|
||||||
|
assertCounterCount("Disciplined Duelist", CounterType.SHIELD, 0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package mage.abilities.effects.keyword;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.effects.ReplacementEffectImpl;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.counters.CounterType;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author weirddan455
|
||||||
|
*/
|
||||||
|
public class ShieldCounterEffect extends ReplacementEffectImpl {
|
||||||
|
|
||||||
|
public ShieldCounterEffect() {
|
||||||
|
super(Duration.Custom, Outcome.PreventDamage);
|
||||||
|
this.staticText = "If it would be dealt damage or destroyed, remove a shield counter from it instead";
|
||||||
|
}
|
||||||
|
|
||||||
|
private ShieldCounterEffect(final ShieldCounterEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ShieldCounterEffect copy() {
|
||||||
|
return new ShieldCounterEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||||
|
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||||
|
if (permanent != null && permanent.getCounters(game).getCount(CounterType.SHIELD) > 0) {
|
||||||
|
permanent.removeCounters(CounterType.SHIELD.getName(), 1, source, game);
|
||||||
|
if (!game.isSimulation()) {
|
||||||
|
game.informPlayers("Removed a shield counter from " + permanent.getLogName());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checksEventType(GameEvent event, Game game) {
|
||||||
|
switch (event.getType()) {
|
||||||
|
case DAMAGE_PERMANENT:
|
||||||
|
case DESTROY_PERMANENT:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||||
|
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||||
|
return permanent != null && permanent.getCounters(game).getCount(CounterType.SHIELD) > 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ import mage.abilities.effects.Effect;
|
||||||
import mage.abilities.effects.PreventionEffectData;
|
import mage.abilities.effects.PreventionEffectData;
|
||||||
import mage.abilities.effects.common.CopyEffect;
|
import mage.abilities.effects.common.CopyEffect;
|
||||||
import mage.abilities.effects.common.InfoEffect;
|
import mage.abilities.effects.common.InfoEffect;
|
||||||
|
import mage.abilities.effects.keyword.ShieldCounterEffect;
|
||||||
import mage.abilities.keyword.*;
|
import mage.abilities.keyword.*;
|
||||||
import mage.abilities.mana.DelayedTriggeredManaAbility;
|
import mage.abilities.mana.DelayedTriggeredManaAbility;
|
||||||
import mage.abilities.mana.TriggeredManaAbility;
|
import mage.abilities.mana.TriggeredManaAbility;
|
||||||
|
@ -1130,6 +1131,9 @@ public abstract class GameImpl implements Game {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Apply shield counter mechanic from SNC
|
||||||
|
state.addAbility(new SimpleStaticAbility(Zone.ALL, new ShieldCounterEffect()), null);
|
||||||
|
|
||||||
// Handle companions
|
// Handle companions
|
||||||
Map<Player, Card> playerCompanionMap = new HashMap<>();
|
Map<Player, Card> playerCompanionMap = new HashMap<>();
|
||||||
for (Player player : state.getPlayers().values()) {
|
for (Player player : state.getPlayers().values()) {
|
||||||
|
|
Loading…
Reference in a new issue