mirror of
https://github.com/correl/mage.git
synced 2024-11-15 03:00:16 +00:00
Updated implementation of Hexproof abilities (#6451)
* updated implementation of hexproof abilities * added hexproof from color test * updated generic in AbilityPredicate
This commit is contained in:
parent
f7309919b9
commit
7f32ea0be2
17 changed files with 128 additions and 126 deletions
|
@ -137,7 +137,7 @@ class KathrilAspectWarperEffect extends OneShotEffect {
|
|||
if (ability instanceof DeathtouchAbility) {
|
||||
return CounterType.DEATHTOUCH;
|
||||
}
|
||||
if (ability instanceof HexproofInterface) {
|
||||
if (ability instanceof HexproofBaseAbility) {
|
||||
return CounterType.HEXPROOF;
|
||||
}
|
||||
if (ability instanceof IndestructibleAbility) {
|
||||
|
|
|
@ -75,7 +75,7 @@ class MajesticMyriarchEffect extends OneShotEffect {
|
|||
filterDeathtouch.add(new AbilityPredicate(DeathtouchAbility.class));
|
||||
filterDoubleStrike.add(new AbilityPredicate(DoubleStrikeAbility.class));
|
||||
filterHaste.add(new AbilityPredicate(HasteAbility.class));
|
||||
filterHexproof.add(new AbilityPredicate(HexproofInterface.class));
|
||||
filterHexproof.add(new AbilityPredicate(HexproofBaseAbility.class));
|
||||
filterIndestructible.add(new AbilityPredicate(IndestructibleAbility.class));
|
||||
filterLifelink.add(new AbilityPredicate(LifelinkAbility.class));
|
||||
filterMenace.add(new AbilityPredicate(MenaceAbility.class));
|
||||
|
|
|
@ -66,7 +66,7 @@ class OdricLunarchMarshalEffect extends OneShotEffect {
|
|||
filterDeathtouch.add(new AbilityPredicate(DeathtouchAbility.class));
|
||||
filterDoubleStrike.add(new AbilityPredicate(DoubleStrikeAbility.class));
|
||||
filterHaste.add(new AbilityPredicate(HasteAbility.class));
|
||||
filterHexproof.add(new AbilityPredicate(HexproofInterface.class));
|
||||
filterHexproof.add(new AbilityPredicate(HexproofBaseAbility.class));
|
||||
filterIndestructible.add(new AbilityPredicate(IndestructibleAbility.class));
|
||||
filterLifelink.add(new AbilityPredicate(LifelinkAbility.class));
|
||||
filterMenace.add(new AbilityPredicate(MenaceAbility.class));
|
||||
|
|
|
@ -85,7 +85,7 @@ class RayamiFirstOfTheFallenEffect extends ContinuousEffectImpl {
|
|||
|| ability instanceof DoubleStrikeAbility
|
||||
|| ability instanceof DeathtouchAbility
|
||||
|| ability instanceof HasteAbility
|
||||
|| ability instanceof HexproofInterface
|
||||
|| ability instanceof HexproofBaseAbility
|
||||
|| ability instanceof IndestructibleAbility
|
||||
|| ability instanceof LifelinkAbility
|
||||
|| ability instanceof MenaceAbility
|
||||
|
|
|
@ -49,7 +49,7 @@ class SelectiveAdaptationEffect extends OneShotEffect {
|
|||
DOUBLE_STRIKE(DoubleStrikeAbility.class, "double strike"),
|
||||
DEATHTOUCH(DeathtouchAbility.class, "deathtouch"),
|
||||
HASTE(HasteAbility.class, "haste"),
|
||||
HEXPROOF(HexproofInterface.class, "hexproof"),
|
||||
HEXPROOF(HexproofBaseAbility.class, "hexproof"),
|
||||
INDESTRUCTIBLE(IndestructibleAbility.class, "indestructible"),
|
||||
LIFELINK(LifelinkAbility.class, "lifelink"),
|
||||
MENACE(MenaceAbility.class, "menace"),
|
||||
|
|
|
@ -107,7 +107,7 @@ class SoulflayerEffect extends ContinuousEffectImpl implements SourceEffect {
|
|||
if (cardAbility instanceof HasteAbility) {
|
||||
abilitiesToAdd.add(HasteAbility.getInstance());
|
||||
}
|
||||
if (cardAbility instanceof HexproofInterface) {
|
||||
if (cardAbility instanceof HexproofBaseAbility) {
|
||||
abilitiesToAdd.add(HexproofAbility.getInstance());
|
||||
}
|
||||
if (cardAbility instanceof IndestructibleAbility) {
|
||||
|
|
|
@ -9,7 +9,6 @@ import org.junit.Test;
|
|||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class HexproofTest extends CardTestPlayerBase {
|
||||
|
@ -37,6 +36,7 @@ public class HexproofTest extends CardTestPlayerBase {
|
|||
assertPowerToughness(playerA, "Elder of Laurels", 3, 4);
|
||||
assertAbility(playerA, "Elder of Laurels", HexproofAbility.getInstance(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests one target gets hexproof
|
||||
*/
|
||||
|
@ -64,4 +64,42 @@ public class HexproofTest extends CardTestPlayerBase {
|
|||
assertAbility(playerA, "Elder of Laurels", HexproofAbility.getInstance(), true);
|
||||
assertPermanentCount(playerA, "Arbor Elf", 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests hexproof from a color with opponent's spells
|
||||
*/
|
||||
@Test
|
||||
public void testHexproofFromColorOpponentSpells() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6);
|
||||
addCard(Zone.HAND, playerA, "Murder", 2);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Knight of Grace");
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Knight of Malice");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Murder", "Knight of Grace");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Murder", "Knight of Malice");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerB, "Knight of Grace", 1);
|
||||
assertPermanentCount(playerB, "Knight of Malice", 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests hexproof from a color with controller's spells
|
||||
*/
|
||||
@Test
|
||||
public void testHexproofFromColorOwnSpells() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Knight of Grace");
|
||||
addCard(Zone.HAND, playerA, "Murder");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Murder", "Knight of Grace");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Knight of Grace", 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.MageSingleton;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.constants.Zone;
|
||||
import mage.MageObject;
|
||||
import mage.game.Game;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
|
||||
|
@ -12,7 +11,7 @@ import java.io.ObjectStreamException;
|
|||
*
|
||||
* @author loki
|
||||
*/
|
||||
public class HexproofAbility extends SimpleStaticAbility implements MageSingleton, HexproofInterface {
|
||||
public class HexproofAbility extends HexproofBaseAbility {
|
||||
|
||||
private static final HexproofAbility instance;
|
||||
|
||||
|
@ -29,7 +28,12 @@ public class HexproofAbility extends SimpleStaticAbility implements MageSingleto
|
|||
}
|
||||
|
||||
private HexproofAbility() {
|
||||
super(Zone.BATTLEFIELD, null);
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkObject(MageObject source, Game game) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.MageSingleton;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* an abstract base class for hexproof abilities
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public abstract class HexproofBaseAbility extends SimpleStaticAbility implements MageSingleton {
|
||||
|
||||
HexproofBaseAbility() {
|
||||
super(Zone.BATTLEFIELD, null);
|
||||
}
|
||||
|
||||
public abstract boolean checkObject(MageObject source, Game game);
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.MageSingleton;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.constants.Zone;
|
||||
import mage.MageObject;
|
||||
import mage.game.Game;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
|
||||
|
@ -12,7 +11,7 @@ import java.io.ObjectStreamException;
|
|||
*
|
||||
* @author igoudt
|
||||
*/
|
||||
public class HexproofFromBlackAbility extends SimpleStaticAbility implements MageSingleton, HexproofInterface {
|
||||
public class HexproofFromBlackAbility extends HexproofBaseAbility {
|
||||
|
||||
private static final HexproofFromBlackAbility instance;
|
||||
|
||||
|
@ -29,7 +28,12 @@ public class HexproofFromBlackAbility extends SimpleStaticAbility implements Mag
|
|||
}
|
||||
|
||||
private HexproofFromBlackAbility() {
|
||||
super(Zone.BATTLEFIELD, null);
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkObject(MageObject source, Game game) {
|
||||
return source.getColor(game).isBlack();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.MageSingleton;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.constants.Zone;
|
||||
import mage.MageObject;
|
||||
import mage.game.Game;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
|
||||
|
@ -12,7 +11,7 @@ import java.io.ObjectStreamException;
|
|||
*
|
||||
* @author igoudt
|
||||
*/
|
||||
public class HexproofFromBlueAbility extends SimpleStaticAbility implements MageSingleton, HexproofInterface {
|
||||
public class HexproofFromBlueAbility extends HexproofBaseAbility {
|
||||
|
||||
private static final HexproofFromBlueAbility instance;
|
||||
|
||||
|
@ -29,7 +28,12 @@ public class HexproofFromBlueAbility extends SimpleStaticAbility implements Mage
|
|||
}
|
||||
|
||||
private HexproofFromBlueAbility() {
|
||||
super(Zone.BATTLEFIELD, null);
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkObject(MageObject source, Game game) {
|
||||
return source.getColor(game).isBlue();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.MageSingleton;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.constants.Zone;
|
||||
import mage.MageObject;
|
||||
import mage.game.Game;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
|
||||
|
@ -12,7 +11,7 @@ import java.io.ObjectStreamException;
|
|||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class HexproofFromMonocoloredAbility extends SimpleStaticAbility implements MageSingleton, HexproofInterface {
|
||||
public class HexproofFromMonocoloredAbility extends HexproofBaseAbility {
|
||||
|
||||
private static final HexproofFromMonocoloredAbility instance;
|
||||
|
||||
|
@ -29,7 +28,12 @@ public class HexproofFromMonocoloredAbility extends SimpleStaticAbility implemen
|
|||
}
|
||||
|
||||
private HexproofFromMonocoloredAbility() {
|
||||
super(Zone.BATTLEFIELD, null);
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkObject(MageObject source, Game game) {
|
||||
return !source.getColor(game).isMulticolored() && !source.getColor(game).isColorless();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import mage.abilities.MageSingleton;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.constants.Zone;
|
||||
import mage.MageObject;
|
||||
import mage.game.Game;
|
||||
|
||||
import java.io.ObjectStreamException;
|
||||
|
||||
|
@ -12,7 +11,7 @@ import java.io.ObjectStreamException;
|
|||
*
|
||||
* @author igoudt
|
||||
*/
|
||||
public class HexproofFromWhiteAbility extends SimpleStaticAbility implements MageSingleton, HexproofInterface {
|
||||
public class HexproofFromWhiteAbility extends HexproofBaseAbility {
|
||||
|
||||
private static final HexproofFromWhiteAbility instance;
|
||||
|
||||
|
@ -29,7 +28,12 @@ public class HexproofFromWhiteAbility extends SimpleStaticAbility implements Mag
|
|||
}
|
||||
|
||||
private HexproofFromWhiteAbility() {
|
||||
super(Zone.BATTLEFIELD, null);
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkObject(MageObject source, Game game) {
|
||||
return source.getColor(game).isWhite();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
/**
|
||||
* an interface for hexproof abilities
|
||||
*
|
||||
* @author TheElk801
|
||||
*/
|
||||
public interface HexproofInterface {
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.filter.predicate.mageobject;
|
||||
|
||||
import mage.MageObject;
|
||||
|
@ -13,9 +12,9 @@ import mage.game.Game;
|
|||
*/
|
||||
public class AbilityPredicate implements Predicate<MageObject> {
|
||||
|
||||
private final Class<?> abilityClass;
|
||||
private final Class<? extends Ability> abilityClass;
|
||||
|
||||
public AbilityPredicate(Class<?> abilityClass) {
|
||||
public AbilityPredicate(Class<? extends Ability> abilityClass) {
|
||||
this.abilityClass = abilityClass;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ import mage.game.command.CommandObject;
|
|||
import mage.game.events.*;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.token.SquirrelToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
|
@ -1062,43 +1061,13 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
if (abilities.containsKey(HexproofAbility.getInstance().getId())) {
|
||||
if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (abilities.containsKey(HexproofFromWhiteAbility.getInstance().getId())) {
|
||||
if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)
|
||||
&& source.getColor(game).isWhite()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (abilities.containsKey(HexproofFromBlueAbility.getInstance().getId())) {
|
||||
if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)
|
||||
&& source.getColor(game).isBlue()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (abilities.containsKey(HexproofFromBlackAbility.getInstance().getId())) {
|
||||
if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)
|
||||
&& source.getColor(game).isBlack()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (abilities.containsKey(HexproofFromMonocoloredAbility.getInstance().getId())) {
|
||||
if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)
|
||||
&& !source.getColor(game).isColorless() && !source.getColor(game).isMulticolored()) {
|
||||
return false;
|
||||
}
|
||||
if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game)
|
||||
&& game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) == null
|
||||
&& abilities.stream()
|
||||
.filter(HexproofBaseAbility.class::isInstance)
|
||||
.map(HexproofBaseAbility.class::cast)
|
||||
.anyMatch(ability -> ability.checkObject(source, game))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasProtectionFrom(source, game)) {
|
||||
|
|
|
@ -610,50 +610,14 @@ public abstract class PlayerImpl implements Player, Serializable {
|
|||
if (abilities.containsKey(ShroudAbility.getInstance().getId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (abilities.containsKey(HexproofAbility.getInstance().getId())) {
|
||||
if (sourceControllerId != null && this.hasOpponent(sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(),
|
||||
AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (abilities.containsKey(HexproofFromWhiteAbility.getInstance().getId())) {
|
||||
if (sourceControllerId != null && this.hasOpponent(sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(),
|
||||
AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)
|
||||
&& source.getColor(game).isWhite()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (abilities.containsKey(HexproofFromBlueAbility.getInstance().getId())) {
|
||||
if (sourceControllerId != null && this.hasOpponent(sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(),
|
||||
AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)
|
||||
&& source.getColor(game).isBlue()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (abilities.containsKey(HexproofFromBlackAbility.getInstance().getId())) {
|
||||
if (sourceControllerId != null && this.hasOpponent(sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(),
|
||||
AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)
|
||||
&& source.getColor(game).isBlack()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (abilities.containsKey(HexproofFromMonocoloredAbility.getInstance().getId())) {
|
||||
if (sourceControllerId != null && this.hasOpponent(sourceControllerId, game)
|
||||
&& null == game.getContinuousEffects().asThough(this.getId(),
|
||||
AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)
|
||||
&& !source.getColor(game).isColorless()
|
||||
&& !source.getColor(game).isMulticolored()) {
|
||||
return false;
|
||||
}
|
||||
if (sourceControllerId != null
|
||||
&& this.hasOpponent(sourceControllerId, game)
|
||||
&& game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) == null
|
||||
&& abilities.stream()
|
||||
.filter(HexproofBaseAbility.class::isInstance)
|
||||
.map(HexproofBaseAbility.class::cast)
|
||||
.anyMatch(ability -> ability.checkObject(source, game))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !hasProtectionFrom(source, game);
|
||||
|
|
Loading…
Reference in a new issue