diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index 4708905b368..501f5603474 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -1321,7 +1321,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (ability != null && ability.canActivate(playerId, game).canActivate() && !game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getSourceId(), ability.getSourceId(), playerId), ability, game, true)) { if (card.getCardType().contains(CardType.INSTANT) - || card.hasAbility(FlashAbility.getInstance().getId(), game)) { + || card.hasAbility(FlashAbility.getInstance(), game)) { playableInstant.add(card); } else { playableNonInstant.add(card); diff --git a/Mage.Sets/src/mage/cards/c/Chaosphere.java b/Mage.Sets/src/mage/cards/c/Chaosphere.java index 12511380fc7..73ed95605d7 100644 --- a/Mage.Sets/src/mage/cards/c/Chaosphere.java +++ b/Mage.Sets/src/mage/cards/c/Chaosphere.java @@ -82,7 +82,7 @@ class ChaosphereEffect extends RestrictionEffect { if (attacker == null) { return true; } - return attacker.hasAbility(FlyingAbility.getInstance().getId(), game); + return attacker.hasAbility(FlyingAbility.getInstance(), game); } @Override diff --git a/Mage.Sets/src/mage/cards/c/CrimsonRoc.java b/Mage.Sets/src/mage/cards/c/CrimsonRoc.java index 6b7d68697cd..1dab5eb0ff2 100644 --- a/Mage.Sets/src/mage/cards/c/CrimsonRoc.java +++ b/Mage.Sets/src/mage/cards/c/CrimsonRoc.java @@ -71,7 +71,7 @@ class CrimsonRocTriggeredAbility extends TriggeredAbilityImpl { Permanent permanent = game.getPermanent(event.getTargetId()); return permanent != null && permanent.isCreature() - && !permanent.getAbilities(game).contains(FlyingAbility.getInstance()); + && !permanent.hasAbility(FlyingAbility.getInstance(), game); } @Override diff --git a/Mage.Sets/src/mage/cards/d/DenseCanopy.java b/Mage.Sets/src/mage/cards/d/DenseCanopy.java index 9a43da5da03..3226e49efaf 100644 --- a/Mage.Sets/src/mage/cards/d/DenseCanopy.java +++ b/Mage.Sets/src/mage/cards/d/DenseCanopy.java @@ -66,7 +66,7 @@ class DenseCanopyCantBlockEffect extends RestrictionEffect { if (attacker == null) { return true; } - return attacker.hasAbility(FlyingAbility.getInstance().getId(), game); + return attacker.hasAbility(FlyingAbility.getInstance(), game); } @Override diff --git a/Mage.Sets/src/mage/cards/m/MomentumRumbler.java b/Mage.Sets/src/mage/cards/m/MomentumRumbler.java index e8d8087f9f1..b6875666aa8 100644 --- a/Mage.Sets/src/mage/cards/m/MomentumRumbler.java +++ b/Mage.Sets/src/mage/cards/m/MomentumRumbler.java @@ -75,6 +75,6 @@ enum MomentumRumblerCondition implements Condition { if (permanent == null) { return false; } - return hasAbility == permanent.getAbilities(game).containsKey(FirstStrikeAbility.getInstance().getId()); + return hasAbility == permanent.hasAbility(FirstStrikeAbility.getInstance(), game); } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/q/QuartzwoodCrasher.java b/Mage.Sets/src/mage/cards/q/QuartzwoodCrasher.java index 01f05f155e9..e83513d2237 100644 --- a/Mage.Sets/src/mage/cards/q/QuartzwoodCrasher.java +++ b/Mage.Sets/src/mage/cards/q/QuartzwoodCrasher.java @@ -82,7 +82,7 @@ class QuartzwoodCrasherTriggeredAbility extends TriggeredAbilityImpl { && ((DamagedPlayerEvent) event).isCombatDamage()) { Permanent creature = game.getPermanent(event.getSourceId()); if (creature != null && creature.isControlledBy(controllerId) - && creature.hasAbility(TrampleAbility.getInstance().getId(), game) + && creature.hasAbility(TrampleAbility.getInstance(), game) && !damagedPlayerIds.contains(event.getTargetId())) { damagedPlayerIds.add(event.getTargetId()); this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); @@ -143,7 +143,7 @@ class QuartzwoodCrasherWatcher extends Watcher { return; } Permanent creature = game.getPermanent(event.getSourceId()); - if (creature == null || !creature.getAbilities(game).containsKey(TrampleAbility.getInstance().getId())) { + if (creature == null || !creature.hasAbility(TrampleAbility.getInstance(), game)) { return; } damageMap diff --git a/Mage.Sets/src/mage/cards/r/ReturnFromExtinction.java b/Mage.Sets/src/mage/cards/r/ReturnFromExtinction.java index f6decd52d66..6a3f7ce162a 100644 --- a/Mage.Sets/src/mage/cards/r/ReturnFromExtinction.java +++ b/Mage.Sets/src/mage/cards/r/ReturnFromExtinction.java @@ -88,7 +88,7 @@ class ReturnFromExtinctionTarget extends TargetCardInYourGraveyard { return false; } for (Card card : player.getGraveyard().getCards(filter, sourceId, sourceControllerId, game)) { - if (card.isAllCreatureTypes() || card.getAbilities(game).contains(ChangelingAbility.getInstance())) { + if (card.isAllCreatureTypes() || card.hasAbility(ChangelingAbility.getInstance(), game)) { if (!subTypes.isEmpty()) { return true; } else { diff --git a/Mage.Sets/src/mage/cards/s/SidarKondoOfJamuraa.java b/Mage.Sets/src/mage/cards/s/SidarKondoOfJamuraa.java index f3db71d472b..6bbd1ab410c 100644 --- a/Mage.Sets/src/mage/cards/s/SidarKondoOfJamuraa.java +++ b/Mage.Sets/src/mage/cards/s/SidarKondoOfJamuraa.java @@ -80,8 +80,8 @@ class SidarKondoOfJamuraaCantBlockCreaturesSourceEffect extends RestrictionEffec @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (permanent.hasAbility(FlyingAbility.getInstance().getId(), game) - || permanent.hasAbility(ReachAbility.getInstance().getId(), game)) { + if (permanent.hasAbility(FlyingAbility.getInstance(), game) + || permanent.hasAbility(ReachAbility.getInstance(), game)) { return false; } return game.getOpponents(source.getControllerId()).contains(permanent.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/s/SlingbowTrap.java b/Mage.Sets/src/mage/cards/s/SlingbowTrap.java index 87f3856419e..8fcc5cd8a91 100644 --- a/Mage.Sets/src/mage/cards/s/SlingbowTrap.java +++ b/Mage.Sets/src/mage/cards/s/SlingbowTrap.java @@ -61,7 +61,7 @@ enum SlingbowTrapCondition implements Condition { for (UUID attackingCreatureId : game.getCombat().getAttackers()) { Permanent attackingCreature = game.getPermanent(attackingCreatureId); if (attackingCreature != null) { - if (attackingCreature.getColor(game).isBlack() && attackingCreature.hasAbility(FlyingAbility.getInstance().getId(), game)) { + if (attackingCreature.getColor(game).isBlack() && attackingCreature.hasAbility(FlyingAbility.getInstance(), game)) { return true; } } diff --git a/Mage.Sets/src/mage/cards/s/StormtideLeviathan.java b/Mage.Sets/src/mage/cards/s/StormtideLeviathan.java index 40e76151eed..0c46713eafe 100644 --- a/Mage.Sets/src/mage/cards/s/StormtideLeviathan.java +++ b/Mage.Sets/src/mage/cards/s/StormtideLeviathan.java @@ -91,7 +91,7 @@ public final class StormtideLeviathan extends CardImpl { // land abilities are intrinsic, so add them here, not in layer 6 if (!land.hasSubtype(SubType.ISLAND, game)) { land.getSubtype(game).add(SubType.ISLAND); - if (!land.getAbilities(game).contains(new BlueManaAbility())) { + if (!land.getAbilities(game).containsClass(BlueManaAbility.class)) { land.addAbility(new BlueManaAbility(), source.getSourceId(), game); } } diff --git a/Mage.Sets/src/mage/cards/t/TaigamOjutaiMaster.java b/Mage.Sets/src/mage/cards/t/TaigamOjutaiMaster.java index 4aeaa230494..236ce4ff01d 100644 --- a/Mage.Sets/src/mage/cards/t/TaigamOjutaiMaster.java +++ b/Mage.Sets/src/mage/cards/t/TaigamOjutaiMaster.java @@ -150,7 +150,7 @@ class TaigamOjutaiMasterGainReboundEffect extends ContinuousEffectImpl { } private void addReboundAbility(Card card, Ability source, Game game) { - boolean found = card.getAbilities(game).stream().anyMatch(ability -> ability instanceof ReboundAbility); + boolean found = card.getAbilities(game).containsClass(ReboundAbility.class); if (!found) { Ability ability = new ReboundAbility(); game.getState().addOtherAbility(card, ability); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/CommandersCastTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/CommandersCastTest.java index 4caf5347b13..b217f12dda2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/CommandersCastTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/CommandersCastTest.java @@ -113,7 +113,6 @@ public class CommandersCastTest extends CardTestCommander4Players { waitStackResolved(5, PhaseStep.POSTCOMBAT_MAIN); checkPermanentCount("after cast 2", 5, PhaseStep.POSTCOMBAT_MAIN, playerA, "Academy Ruins", 1); -// showBattlefield("end battlefield", 5, PhaseStep.END_TURN, playerA); setStopAt(5, PhaseStep.END_TURN); setStrictChooseMode(true); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/WonderTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/WonderTest.java index 440074c3e2b..d4c13331a88 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/WonderTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/WonderTest.java @@ -40,7 +40,7 @@ public class WonderTest extends CardTestPlayerBase { // check no flying in graveyard for (Card card : playerA.getGraveyard().getCards(currentGame)) { if (card.getName().equals("Runeclaw Bear")) { - Assert.assertFalse(card.getAbilities().contains(FlyingAbility.getInstance())); + Assert.assertFalse(card.hasAbility(FlyingAbility.getInstance(), currentGame)); } } } diff --git a/Mage/src/main/java/mage/MageObject.java b/Mage/src/main/java/mage/MageObject.java index 744ec43f071..b2c21ab27d9 100644 --- a/Mage/src/main/java/mage/MageObject.java +++ b/Mage/src/main/java/mage/MageObject.java @@ -41,9 +41,13 @@ public interface MageObject extends MageItem, Serializable { Set getSuperType(); + /** + * For cards: return basic abilities (without dynamic added) + * For permanents: return all abilities (dynamic ability inserts into permanent) + */ Abilities getAbilities(); - boolean hasAbility(UUID abilityId, Game game); + boolean hasAbility(Ability ability, Game game); ObjectColor getColor(Game game); @@ -180,9 +184,9 @@ public interface MageObject extends MageItem, Serializable { } if (this.isCreature() && otherCard.isCreature()) { - if (this.getAbilities().contains(ChangelingAbility.getInstance()) + if (this.hasAbility(ChangelingAbility.getInstance(), game) || this.isAllCreatureTypes() - || otherCard.getAbilities().contains(ChangelingAbility.getInstance()) + || otherCard.hasAbility(ChangelingAbility.getInstance(), game) || otherCard.isAllCreatureTypes()) { return true; } diff --git a/Mage/src/main/java/mage/MageObjectImpl.java b/Mage/src/main/java/mage/MageObjectImpl.java index b68592bb6b1..f25762695f6 100644 --- a/Mage/src/main/java/mage/MageObjectImpl.java +++ b/Mage/src/main/java/mage/MageObjectImpl.java @@ -132,12 +132,12 @@ public abstract class MageObjectImpl implements MageObject { } @Override - public boolean hasAbility(UUID abilityId, Game game) { - if (this.getAbilities().containsKey(abilityId)) { + public boolean hasAbility(Ability ability, Game game) { + if (this.getAbilities().contains(ability)) { return true; } Abilities otherAbilities = game.getState().getAllOtherAbilities(getId()); - return otherAbilities != null && otherAbilities.containsKey(abilityId); + return otherAbilities != null && otherAbilities.contains(ability); } @Override diff --git a/Mage/src/main/java/mage/abilities/SpellAbility.java b/Mage/src/main/java/mage/abilities/SpellAbility.java index 0df442d16cd..1978d8e1629 100644 --- a/Mage/src/main/java/mage/abilities/SpellAbility.java +++ b/Mage/src/main/java/mage/abilities/SpellAbility.java @@ -71,7 +71,7 @@ public class SpellAbility extends ActivatedAbilityImpl { } return null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game) // check this first to allow Offering in main phase || timing == TimingRule.INSTANT - || object.hasAbility(FlashAbility.getInstance().getId(), game) + || object.hasAbility(FlashAbility.getInstance(), game) || game.canPlaySorcery(playerId); } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SuspendedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SuspendedCondition.java index dcdd6a81627..ba7dc69d1b5 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SuspendedCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SuspendedCondition.java @@ -27,10 +27,10 @@ public enum SuspendedCondition implements Condition { public boolean apply(Game game, Ability source) { Card card = game.getCard(source.getSourceId()); if (card != null) { - boolean found = card.getAbilities().stream().anyMatch(ability -> ability instanceof SuspendAbility); + boolean found = card.getAbilities(game).containsClass(SuspendAbility.class); if (!found) { - found = game.getState().getAllOtherAbilities(source.getSourceId()).stream().anyMatch(ability -> ability instanceof SuspendAbility); + found = game.getState().getAllOtherAbilities(source.getSourceId()).containsClass(SuspendAbility.class); } if (found) { diff --git a/Mage/src/main/java/mage/abilities/effects/GainAbilitySpellsEffect.java b/Mage/src/main/java/mage/abilities/effects/GainAbilitySpellsEffect.java index 11545d7d271..0d96f2a9183 100644 --- a/Mage/src/main/java/mage/abilities/effects/GainAbilitySpellsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/GainAbilitySpellsEffect.java @@ -64,7 +64,7 @@ public class GainAbilitySpellsEffect extends ContinuousEffectImpl { if (stackObject.isControlledBy(source.getControllerId())) { Card card = game.getCard(stackObject.getSourceId()); if (card != null && filter.match(card, game)) { - if (!card.getAbilities().contains(ability)) { + if (!card.hasAbility(ability, game)) { game.getState().addOtherAbility(card, ability); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingAttachedEffect.java index ecb95414c9c..a3b94d6f0af 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingAttachedEffect.java @@ -33,7 +33,7 @@ public class CanBlockOnlyFlyingAttachedEffect extends RestrictionEffect { if (attacker == null) { return true; } - return attacker.getAbilities().contains(FlyingAbility.getInstance()); + return attacker.hasAbility(FlyingAbility.getInstance(), game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingEffect.java index c39e9d3188e..4d41916cb48 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingEffect.java @@ -33,7 +33,7 @@ public class CanBlockOnlyFlyingEffect extends RestrictionEffect { if (attacker == null) { return true; } - return attacker.getAbilities().contains(FlyingAbility.getInstance()); + return attacker.hasAbility(FlyingAbility.getInstance(), game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityControlledSpellsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityControlledSpellsEffect.java index e58f88cda63..424c996c1a1 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityControlledSpellsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityControlledSpellsEffect.java @@ -51,7 +51,7 @@ public class GainAbilityControlledSpellsEffect extends ContinuousEffectImpl { if ((stackObject instanceof Spell) && !stackObject.isCopy() && stackObject.isControlledBy(source.getControllerId())) { Spell spell = (Spell) stackObject; if (filter.match(spell, game)) { - if (!spell.getAbilities().contains(ability)) { + if (!spell.hasAbility(ability, game)) { game.getState().addOtherAbility(spell.getCard(), ability); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java index 379d81027bc..2bca55f26d3 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java @@ -213,7 +213,7 @@ public class SuspendAbility extends SpecialAction { } MageObject object = game.getObject(sourceId); return new ActivationStatus(object.isInstant() - || object.hasAbility(FlashAbility.getInstance().getId(), game) + || object.hasAbility(FlashAbility.getInstance(), game) || null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game) || game.canPlaySorcery(playerId), null); @@ -356,6 +356,13 @@ class SuspendPlayCardEffect extends OneShotEffect { } } // remove the abilities from the card + // TODO: will not work with Adventure Cards and another auto-generated abilities list + // TODO: is it work after blink or return to hand? + /* + bug example: + Epochrasite bug: It comes out of suspend, is cast and enters the battlefield. THEN if it's returned to + its owner's hand from battlefield, the bounced Epochrasite can't be cast for the rest of the game. + */ card.getAbilities().removeAll(abilitiesToRemove); } // cast the card for free diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index d5daa56d42c..f7d168227b5 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -285,7 +285,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { /** * Gets all current abilities - includes additional abilities added by other - * cards or effects + * cards or effects. Warning, you can't modify that list. * * @param game * @return A list of {@link Ability} - this collection is not modifiable @@ -295,15 +295,23 @@ public abstract class CardImpl extends MageObjectImpl implements Card { if (game == null) { return abilities; // deck editor with empty game } + CardState cardState = game.getState().getCardState(this.getId()); - if (!cardState.hasLostAllAbilities() && (cardState.getAbilities() == null || cardState.getAbilities().isEmpty())) { + if (cardState == null) { return abilities; } + + // collects all abilities Abilities all = new AbilitiesImpl<>(); + + // basic if (!cardState.hasLostAllAbilities()) { all.addAll(abilities); } + + // dynamic all.addAll(cardState.getAbilities()); + return all; } @@ -314,6 +322,12 @@ public abstract class CardImpl extends MageObjectImpl implements Card { cardState.getAbilities().clear(); } + @Override + public boolean hasAbility(Ability ability, Game game) { + // getAbilities(game) searches all abilities from base and dynamic lists (other) + return this.getAbilities(game).contains(ability); + } + /** * Public in order to support adding abilities to SplitCardHalf's * diff --git a/Mage/src/main/java/mage/designations/Designation.java b/Mage/src/main/java/mage/designations/Designation.java index 3554e68c508..4537abe3b09 100644 --- a/Mage/src/main/java/mage/designations/Designation.java +++ b/Mage/src/main/java/mage/designations/Designation.java @@ -171,8 +171,8 @@ public abstract class Designation implements MageObject { } @Override - public boolean hasAbility(UUID abilityId, Game game) { - return abilites.containsKey(abilityId); + public boolean hasAbility(Ability ability, Game game) { + return this.getAbilities().contains(ability); } @Override diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index c502dae73bc..32d834b1a16 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -306,7 +306,7 @@ public class Combat implements Serializable, Copyable { || getAttackers().size() <= 1) { return; } - boolean canBand = attacker.getAbilities().containsKey(BandingAbility.getInstance().getId()); + boolean canBand = attacker.hasAbility(BandingAbility.getInstance(), game); List bandsWithOther = new ArrayList<>(); for (Ability ability : attacker.getAbilities()) { if (ability.getClass().equals(BandsWithOtherAbility.class)) { @@ -390,7 +390,7 @@ public class Combat implements Serializable, Copyable { permanent.addBandedCard(creatureId); attacker.addBandedCard(targetId); if (canBand) { - if (!permanent.getAbilities().containsKey(BandingAbility.getInstance().getId())) { + if (!permanent.hasAbility(BandingAbility.getInstance(), game)) { filter.add(new AbilityPredicate(BandingAbility.class)); canBandWithOther = false; } @@ -1289,7 +1289,8 @@ public class Combat implements Serializable, Copyable { if (attacker != null) { if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARE_ATTACKER, defenderId, creatureId, playerId))) { if (addAttackerToCombat(creatureId, defenderId, game)) { - if (!attacker.getAbilities().containsKey(VigilanceAbility.getInstance().getId()) && !attacker.getAbilities().containsKey(JohanVigilanceAbility.getInstance().getId())) { + if (!attacker.hasAbility(VigilanceAbility.getInstance(), game) + && !attacker.hasAbility(JohanVigilanceAbility.getInstance(), game)) { if (!attacker.isTapped()) { attacker.setTapped(true); attackersTappedByAttack.add(attacker.getId()); diff --git a/Mage/src/main/java/mage/game/command/Commander.java b/Mage/src/main/java/mage/game/command/Commander.java index e8a34c3a7d6..c2cd0491bfa 100644 --- a/Mage/src/main/java/mage/game/command/Commander.java +++ b/Mage/src/main/java/mage/game/command/Commander.java @@ -158,12 +158,12 @@ public class Commander implements CommandObject { } @Override - public boolean hasAbility(UUID abilityId, Game game) { - if (this.getAbilities().containsKey(abilityId)) { + public boolean hasAbility(Ability ability, Game game) { + if (this.getAbilities().contains(ability)) { return true; } Abilities otherAbilities = game.getState().getAllOtherAbilities(getId()); - return otherAbilities != null && otherAbilities.containsKey(abilityId); + return otherAbilities != null && otherAbilities.contains(ability); } @Override diff --git a/Mage/src/main/java/mage/game/command/Emblem.java b/Mage/src/main/java/mage/game/command/Emblem.java index 7a4a8896aa7..b0de304a981 100644 --- a/Mage/src/main/java/mage/game/command/Emblem.java +++ b/Mage/src/main/java/mage/game/command/Emblem.java @@ -173,8 +173,8 @@ public class Emblem implements CommandObject { } @Override - public boolean hasAbility(UUID abilityId, Game game) { - return abilites.containsKey(abilityId); + public boolean hasAbility(Ability ability, Game game) { + return getAbilities().contains(ability); } @Override diff --git a/Mage/src/main/java/mage/game/command/Plane.java b/Mage/src/main/java/mage/game/command/Plane.java index 070a55c6ab8..be457ec6ed3 100644 --- a/Mage/src/main/java/mage/game/command/Plane.java +++ b/Mage/src/main/java/mage/game/command/Plane.java @@ -182,8 +182,8 @@ public class Plane implements CommandObject { } @Override - public boolean hasAbility(UUID abilityId, Game game) { - return abilites.containsKey(abilityId); + public boolean hasAbility(Ability ability, Game game) { + return getAbilities().contains(ability); } @Override diff --git a/Mage/src/main/java/mage/game/command/planes/TrailOfTheMageRingsPlane.java b/Mage/src/main/java/mage/game/command/planes/TrailOfTheMageRingsPlane.java index 6a5371e12fe..28e32d45198 100644 --- a/Mage/src/main/java/mage/game/command/planes/TrailOfTheMageRingsPlane.java +++ b/Mage/src/main/java/mage/game/command/planes/TrailOfTheMageRingsPlane.java @@ -120,7 +120,7 @@ class TrailOfTheMageRingsReboundEffect extends ContinuousEffectImpl { private void addReboundAbility(Card card, Ability source, Game game) { if (filter.match(card, game)) { - boolean found = card.getAbilities().stream().anyMatch(ability -> ability instanceof ReboundAbility); + boolean found = card.getAbilities(game).containsClass(ReboundAbility.class); if (!found) { Ability ability = new ReboundAbility(); game.getState().addOtherAbility(card, ability); diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index e9e262711a8..42c6ba27ec6 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -524,8 +524,8 @@ public class Spell extends StackObjImpl implements Card { } @Override - public boolean hasAbility(UUID abilityId, Game game) { - return card.hasAbility(abilityId, game); + public boolean hasAbility(Ability ability, Game game) { + return card.hasAbility(ability, game); } @Override diff --git a/Mage/src/main/java/mage/game/stack/StackAbility.java b/Mage/src/main/java/mage/game/stack/StackAbility.java index cb4149bcfef..d7f64cac955 100644 --- a/Mage/src/main/java/mage/game/stack/StackAbility.java +++ b/Mage/src/main/java/mage/game/stack/StackAbility.java @@ -178,7 +178,7 @@ public class StackAbility extends StackObjImpl implements Ability { } @Override - public boolean hasAbility(UUID abilityId, Game game) { + public boolean hasAbility(Ability ability, Game game) { return false; } @@ -672,4 +672,17 @@ public class StackAbility extends StackObjImpl implements Ability { public Outcome getCustomOutcome() { return this.ability.getCustomOutcome(); } + + @Override + public boolean isSameInstance(Ability ability) { + // same instance (by mtg rules) = same object, ID or class+text (you can't check class only cause it can be different by params/text) + if (ability == null) { + return false; + } + + return (this == ability) + || (this.getId().equals(ability.getId())) + || (this.getOriginalId().equals(ability.getOriginalId())) + || (this.getClass() == ability.getClass() && this.getRule().equals(ability.getRule())); + } }