diff --git a/Mage.Sets/src/mage/cards/a/AdventurersGuildhouse.java b/Mage.Sets/src/mage/cards/a/AdventurersGuildhouse.java new file mode 100644 index 0000000000..f52a02aa30 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AdventurersGuildhouse.java @@ -0,0 +1,47 @@ + +package mage.cards.a; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; + +/** + * + * @author L_J + */ +public final class AdventurersGuildhouse extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Green legendary creatures"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + filter.add(new SupertypePredicate(SuperType.LEGENDARY)); + } + + public AdventurersGuildhouse(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Green legendary creatures you control have "bands with other legendary creatures." + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(new BandsWithOtherAbility(SuperType.LEGENDARY), Duration.WhileOnBattlefield, filter))); + } + + public AdventurersGuildhouse(final AdventurersGuildhouse card) { + super(card); + } + + @Override + public AdventurersGuildhouse copy() { + return new AdventurersGuildhouse(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CathedralOfSerra.java b/Mage.Sets/src/mage/cards/c/CathedralOfSerra.java new file mode 100644 index 0000000000..b570289989 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CathedralOfSerra.java @@ -0,0 +1,47 @@ + +package mage.cards.c; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; + +/** + * + * @author L_J + */ +public final class CathedralOfSerra extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("White legendary creatures"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + filter.add(new SupertypePredicate(SuperType.LEGENDARY)); + } + + public CathedralOfSerra(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // White legendary creatures you control have "bands with other legendary creatures." + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(new BandsWithOtherAbility(SuperType.LEGENDARY), Duration.WhileOnBattlefield, filter))); + } + + public CathedralOfSerra(final CathedralOfSerra card) { + super(card); + } + + @Override + public CathedralOfSerra copy() { + return new CathedralOfSerra(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MasterOfTheHunt.java b/Mage.Sets/src/mage/cards/m/MasterOfTheHunt.java new file mode 100644 index 0000000000..32ea8a44b5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MasterOfTheHunt.java @@ -0,0 +1,40 @@ + +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.permanent.token.WolvesOfTheHuntToken; + +/** + * @author L_J + */ +public final class MasterOfTheHunt extends CardImpl { + + public MasterOfTheHunt(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{G}"); + this.subtype.add(SubType.HUMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Create a 1/1 green Wolf creature token named Wolves of the Hunt. It has “bands with other creatures named Wolves of the Hunt.” + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new WolvesOfTheHuntToken()), new ManaCostsImpl("{2}{G}{G}"))); + } + + public MasterOfTheHunt(final MasterOfTheHunt card) { + super(card); + } + + @Override + public MasterOfTheHunt copy() { + return new MasterOfTheHunt(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/m/MountainStronghold.java b/Mage.Sets/src/mage/cards/m/MountainStronghold.java new file mode 100644 index 0000000000..64775cba11 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MountainStronghold.java @@ -0,0 +1,47 @@ + +package mage.cards.m; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; + +/** + * + * @author L_J + */ +public final class MountainStronghold extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Red legendary creatures"); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + filter.add(new SupertypePredicate(SuperType.LEGENDARY)); + } + + public MountainStronghold(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Red legendary creatures you control have "bands with other legendary creatures." + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(new BandsWithOtherAbility(SuperType.LEGENDARY), Duration.WhileOnBattlefield, filter))); + } + + public MountainStronghold(final MountainStronghold card) { + super(card); + } + + @Override + public MountainStronghold copy() { + return new MountainStronghold(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OldFogey.java b/Mage.Sets/src/mage/cards/o/OldFogey.java new file mode 100644 index 0000000000..4dd4ed481a --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OldFogey.java @@ -0,0 +1,75 @@ + +package mage.cards.o; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.abilities.keyword.CumulativeUpkeepAbility; +import mage.abilities.keyword.EchoAbility; +import mage.abilities.keyword.FadingAbility; +import mage.abilities.keyword.FlankingAbility; +import mage.abilities.keyword.LandwalkAbility; +import mage.abilities.keyword.PhasingAbility; +import mage.abilities.keyword.ProtectionAbility; +import mage.abilities.keyword.RampageAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; + +/** + * + * @author L_J + */ +public final class OldFogey extends CardImpl { + + private static final FilterCard filter = new FilterCard("Homarids"); + private static final FilterLandPermanent filter2 = new FilterLandPermanent("snow-covered plains"); + + static { + filter.add(new SubtypePredicate(SubType.HOMARID)); + filter2.add(new SupertypePredicate(SuperType.SNOW)); + filter2.add(new SubtypePredicate(SubType.PLAINS)); + } + + public OldFogey(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}{G}"); + this.subtype.add(SubType.DINOSAUR); + this.power = new MageInt(7); + this.toughness = new MageInt(7); + + // Phasing + this.addAbility(PhasingAbility.getInstance()); + // Cumulative upkeep {1} + this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl("{1}"))); + // Echo {G}{G} + this.addAbility(new EchoAbility("{G}{G}")); + // Fading 3 + this.addAbility(new FadingAbility(3, this)); + // Bands with other Dinosaurs + this.addAbility(new BandsWithOtherAbility(SubType.DINOSAUR)); + // Protection from Homarids + this.addAbility(new ProtectionAbility(filter)); + // Snow-covered plainswalk + this.addAbility(new LandwalkAbility(filter2)); + // Flanking + this.addAbility(new FlankingAbility()); + // Rampage 2 + this.addAbility(new RampageAbility(2)); + } + + public OldFogey(final OldFogey card) { + super(card); + } + + @Override + public OldFogey copy() { + return new OldFogey(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SeafarersQuay.java b/Mage.Sets/src/mage/cards/s/SeafarersQuay.java new file mode 100644 index 0000000000..ce62ca0040 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SeafarersQuay.java @@ -0,0 +1,47 @@ + +package mage.cards.s; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; + +/** + * + * @author L_J + */ +public final class SeafarersQuay extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Blue legendary creatures"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLUE)); + filter.add(new SupertypePredicate(SuperType.LEGENDARY)); + } + + public SeafarersQuay(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Blue legendary creatures you control have "bands with other legendary creatures." + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(new BandsWithOtherAbility(SuperType.LEGENDARY), Duration.WhileOnBattlefield, filter))); + } + + public SeafarersQuay(final SeafarersQuay card) { + super(card); + } + + @Override + public SeafarersQuay copy() { + return new SeafarersQuay(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShelkinBrownie.java b/Mage.Sets/src/mage/cards/s/ShelkinBrownie.java new file mode 100644 index 0000000000..0d5f206ecf --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShelkinBrownie.java @@ -0,0 +1,45 @@ + +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.continuous.LoseAbilityTargetEffect; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public final class ShelkinBrownie extends CardImpl { + + public ShelkinBrownie(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + this.subtype.add(SubType.OUPHE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {T}: Target creature loses all "bands with other" abilities until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseAbilityTargetEffect(new BandsWithOtherAbility(), Duration.EndOfTurn), new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public ShelkinBrownie(final ShelkinBrownie card) { + super(card); + } + + @Override + public ShelkinBrownie copy() { + return new ShelkinBrownie(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/Tolaria.java b/Mage.Sets/src/mage/cards/t/Tolaria.java new file mode 100644 index 0000000000..24543958ca --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/Tolaria.java @@ -0,0 +1,52 @@ + +package mage.cards.t; + +import java.util.UUID; +import mage.abilities.ActivatedAbilityImpl; +import mage.abilities.condition.common.IsStepCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.effects.common.continuous.LoseAbilityTargetEffect; +import mage.abilities.keyword.BandingAbility; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public final class Tolaria extends CardImpl { + + public Tolaria(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + this.addSuperType(SuperType.LEGENDARY); + + // {T}: Add {U}. + this.addAbility(new BlueManaAbility()); + + // {T}: Target creature loses banding and all "bands with other" abilities until end of turn. Activate this ability only during any upkeep step. + ActivatedAbilityImpl ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, + new LoseAbilityTargetEffect(BandingAbility.getInstance(), Duration.EndOfTurn), new TapSourceCost(), new IsStepCondition(PhaseStep.UPKEEP, false), + "{T}: Target creature loses banding and all \"bands with other\" abilities until end of turn. Activate this ability only during any upkeep step."); + ability.addEffect(new LoseAbilityTargetEffect(new BandsWithOtherAbility(), Duration.EndOfTurn)); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public Tolaria(final Tolaria card) { + super(card); + } + + @Override + public Tolaria copy() { + return new Tolaria(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnholyCitadel.java b/Mage.Sets/src/mage/cards/u/UnholyCitadel.java new file mode 100644 index 0000000000..7153b14a32 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnholyCitadel.java @@ -0,0 +1,47 @@ + +package mage.cards.u; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; + +/** + * + * @author L_J + */ +public final class UnholyCitadel extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Black legendary creatures"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + filter.add(new SupertypePredicate(SuperType.LEGENDARY)); + } + + public UnholyCitadel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Black legendary creatures you control have "bands with other legendary creatures." + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(new BandsWithOtherAbility(SuperType.LEGENDARY), Duration.WhileOnBattlefield, filter))); + } + + public UnholyCitadel(final UnholyCitadel card) { + super(card); + } + + @Override + public UnholyCitadel copy() { + return new UnholyCitadel(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Unhinged.java b/Mage.Sets/src/mage/sets/Unhinged.java index 9a927bad34..bc8b373053 100644 --- a/Mage.Sets/src/mage/sets/Unhinged.java +++ b/Mage.Sets/src/mage/sets/Unhinged.java @@ -39,6 +39,7 @@ public final class Unhinged extends ExpansionSet { cards.add(new SetCardInfo("Mountain", 139, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false))); cards.add(new SetCardInfo("Mox Lotus", 124, Rarity.RARE, mage.cards.m.MoxLotus.class)); cards.add(new SetCardInfo("Now I Know My ABC's", 41, Rarity.RARE, mage.cards.n.NowIKnowMyABCs.class)); + cards.add(new SetCardInfo("Old Fogey", 106, Rarity.RARE, mage.cards.o.OldFogey.class)); cards.add(new SetCardInfo("Plains", 136, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false))); cards.add(new SetCardInfo("Rare-B-Gone", 119, Rarity.RARE, mage.cards.r.RareBGone.class)); cards.add(new SetCardInfo("Six-y Beast", 89, Rarity.UNCOMMON, mage.cards.s.SixyBeast.class)); diff --git a/Mage/src/main/java/mage/abilities/keyword/BandsWithOtherAbility.java b/Mage/src/main/java/mage/abilities/keyword/BandsWithOtherAbility.java new file mode 100644 index 0000000000..528cc744df --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/BandsWithOtherAbility.java @@ -0,0 +1,79 @@ + +package mage.abilities.keyword; + +import mage.abilities.StaticAbility; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; + +/** + * + * @author L_J + */ +public class BandsWithOtherAbility extends StaticAbility { + + private SubType subtype; + private SuperType supertype; + private String bandingName; + + public BandsWithOtherAbility() { + this(null, null, null); + } + + public BandsWithOtherAbility(SubType subtype) { + this(subtype, null, null); + } + + public BandsWithOtherAbility(SuperType supertype) { + this(null, supertype, null); + } + + public BandsWithOtherAbility(String bandingName) { + this(null, null, bandingName); + } + + public BandsWithOtherAbility(SubType subtype, SuperType supertype, String bandingName) { + super(Zone.ALL, null); + this.subtype = subtype; + this.supertype = supertype; + this.bandingName = bandingName; + } + + public BandsWithOtherAbility(BandsWithOtherAbility ability) { + super(ability); + this.subtype = ability.subtype; + this.supertype = ability.supertype; + this.bandingName = ability.bandingName; + } + + @Override + public BandsWithOtherAbility copy() { + return new BandsWithOtherAbility(this); + } + + public SubType getSubtype() { + return subtype; + } + + public SuperType getSupertype() { + return supertype; + } + + public String getName() { + return bandingName; + } + + @Override + public String getRule() { + StringBuilder sb = new StringBuilder("bands with other"); + if (subtype != null) { + return sb.append(' ').append(subtype.getDescription()).append('s').toString(); + } else if (supertype != null) { + return sb.append(' ').append(supertype.toString()).append(" creatures").toString(); + } else if (bandingName != null) { + return sb.append(" creatures named ").append(bandingName).toString(); + } + return "all \"" + sb.toString() + "\" abilities"; + } + +} diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index 5b56d49347..7a1c7a71d8 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -6,6 +6,7 @@ import mage.abilities.Ability; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.RestrictionEffect; import mage.abilities.keyword.BandingAbility; +import mage.abilities.keyword.BandsWithOtherAbility; import mage.abilities.keyword.VigilanceAbility; import mage.abilities.keyword.special.JohanVigilanceAbility; import mage.constants.Outcome; @@ -14,8 +15,12 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreatureForCombatBlock; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; import mage.filter.predicate.permanent.AttackingSameNotBandedPredicate; import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; @@ -293,53 +298,115 @@ public class Combat implements Serializable, Copyable { Permanent attacker = game.getPermanent(creatureId); if (attacker != null && player != null) { CombatGroup combatGroup = findGroup(attacker.getId()); - if (combatGroup != null && attacker.getAbilities().containsKey(BandingAbility.getInstance().getId()) && attacker.getBandedCards().isEmpty() && getAttackers().size() > 1) { - boolean isBanded = false; - FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("attacking creature to band with " + attacker.getLogName()); - 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 - while (player.canRespond()) { - TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); - target.setRequired(false); - if (!target.canChoose(attackingPlayerId, game) - || game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_ATTACKERS, attackingPlayerId, attackingPlayerId)) - || !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 (target.choose(Outcome.Benefit, attackingPlayerId, null, game)) { - isBanded = true; - for (UUID targetId : target.getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { - - for (UUID bandedId : attacker.getBandedCards()) { - permanent.addBandedCard(bandedId); - Permanent banded = game.getPermanent(bandedId); - if (banded != null) { - banded.addBandedCard(targetId); - } - } - permanent.addBandedCard(creatureId); - attacker.addBandedCard(targetId); - if (!permanent.getAbilities().containsKey(BandingAbility.getInstance().getId())) { - filter.add(new AbilityPredicate(BandingAbility.class)); - } - } - - } + if (combatGroup != null && attacker.getBandedCards().isEmpty() && getAttackers().size() > 1) { + boolean canBand = attacker.getAbilities().containsKey(BandingAbility.getInstance().getId()); + List bandsWithOther = new ArrayList<>(); + for (Ability ability : attacker.getAbilities()) { + if (ability.getClass().equals(BandsWithOtherAbility.class)) { + bandsWithOther.add(ability); } } - if (isBanded) { - StringBuilder sb = new StringBuilder(player.getLogName()).append(" formed a band with ").append((attacker.getBandedCards().size() + 1) + " creatures: "); - sb.append(attacker.getLogName()); - for (UUID id : attacker.getBandedCards()) { - sb.append(", "); - Permanent permanent = game.getPermanent(id); - if (permanent != null) { - sb.append(permanent.getLogName()); + boolean canBandWithOther = !bandsWithOther.isEmpty(); + if (canBand || canBandWithOther) { + boolean isBanded = false; + FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("attacking creature to band with " + attacker.getLogName()); + 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> predicates = new ArrayList<>(); + if (!canBand && canBandWithOther) { + for (Ability ab : bandsWithOther) { + BandsWithOtherAbility ability = (BandsWithOtherAbility) ab; + if (ability.getSubtype() != null) { + predicates.add(new SubtypePredicate(ability.getSubtype())); + } + if (ability.getSupertype() != null) { + predicates.add(new SupertypePredicate(ability.getSupertype())); + } + if (ability.getName() != null) { + predicates.add(new NamePredicate(ability.getName())); + } + } + filter.add(Predicates.or(predicates)); + } + while (player.canRespond()) { + TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); + target.setRequired(false); + canBand &= target.canChoose(attackingPlayerId, game); + 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)) { + break; + } + + if (canBand && canBandWithOther) { + if (player.chooseUse(Outcome.Detriment, "Choose type of banding ability to apply:", attacker.getLogName(), "Banding", "Bands with other", null, game)) { + canBandWithOther = false; + } else { + canBand = false; + for (Ability ab : bandsWithOther) { + BandsWithOtherAbility ability = (BandsWithOtherAbility) ab; + if (ability.getSubtype() != null) { + predicates.add(new SubtypePredicate(ability.getSubtype())); + } + if (ability.getSupertype() != null) { + predicates.add(new SupertypePredicate(ability.getSupertype())); + } + if (ability.getName() != null) { + predicates.add(new NamePredicate(ability.getName())); + } + } + filter.add(Predicates.or(predicates)); + } + } + + if (target.choose(Outcome.Benefit, attackingPlayerId, null, game)) { + isBanded = true; + for (UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + + for (UUID bandedId : attacker.getBandedCards()) { + permanent.addBandedCard(bandedId); + Permanent banded = game.getPermanent(bandedId); + if (banded != null) { + banded.addBandedCard(targetId); + } + } + permanent.addBandedCard(creatureId); + attacker.addBandedCard(targetId); + if (canBand) { + if (!permanent.getAbilities().containsKey(BandingAbility.getInstance().getId())) { + filter.add(new AbilityPredicate(BandingAbility.class)); + canBandWithOther = false; + } + } else if (canBandWithOther) { + List> newPredicates = new ArrayList<>(); + for (Predicate predicate : predicates) { + if (predicate.apply(permanent, game)) { + newPredicates.add(predicate); + } + } + filter.add(Predicates.or(newPredicates)); + canBand = false; + } + } + + } } } - game.informPlayers(sb.toString()); + if (isBanded) { + StringBuilder sb = new StringBuilder(player.getLogName()).append(" formed a band with ").append((attacker.getBandedCards().size() + 1) + " creatures: "); + sb.append(attacker.getLogName()); + for (UUID id : attacker.getBandedCards()) { + sb.append(", "); + Permanent permanent = game.getPermanent(id); + if (permanent != null) { + sb.append(permanent.getLogName()); + } + } + game.informPlayers(sb.toString()); + } } } } diff --git a/Mage/src/main/java/mage/game/combat/CombatGroup.java b/Mage/src/main/java/mage/game/combat/CombatGroup.java index e357b6df97..be2f139af6 100644 --- a/Mage/src/main/java/mage/game/combat/CombatGroup.java +++ b/Mage/src/main/java/mage/game/combat/CombatGroup.java @@ -5,10 +5,12 @@ import java.io.Serializable; import java.util.*; import java.util.stream.Stream; +import mage.abilities.Ability; import mage.abilities.common.ControllerAssignCombatDamageToBlockersAbility; import mage.abilities.common.ControllerDivideCombatDamageAbility; import mage.abilities.common.DamageAsThoughNotBlockedAbility; import mage.abilities.keyword.BandingAbility; +import mage.abilities.keyword.BandsWithOtherAbility; import mage.abilities.keyword.CantBlockAloneAbility; import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.DoubleStrikeAbility; @@ -110,6 +112,56 @@ public class CombatGroup implements Serializable, Copyable { return perm.getAbilities().containsKey(BandingAbility.getInstance().getId()); } + private boolean appliesBandsWithOther(List creatureIds, Game game) { + for (UUID creatureId : creatureIds) { + Permanent perm = game.getPermanent(creatureId); + if (perm != null && perm.getBandedCards() != null) { + for (Ability ab : perm.getAbilities()) { + if (ab.getClass().equals(BandsWithOtherAbility.class)) { + BandsWithOtherAbility ability = (BandsWithOtherAbility) ab; + if (ability.getSubtype() != null) { + if (perm.hasSubtype(ability.getSubtype(), game)) { + for (UUID bandedId : creatureIds) { + if (!bandedId.equals(creatureId)) { + Permanent banded = game.getPermanent(bandedId); + if (banded != null && banded.hasSubtype(ability.getSubtype(), game)) { + return true; + } + } + } + } + } + if (ability.getSupertype() != null) { + if (perm.getSuperType().contains(ability.getSupertype())) { + for (UUID bandedId : creatureIds) { + if (!bandedId.equals(creatureId)) { + Permanent banded = game.getPermanent(bandedId); + if (banded != null && banded.getSuperType().contains(ability.getSupertype())) { + return true; + } + } + } + } + } + if (ability.getName() != null) { + if (perm.getName().equals(ability.getName())) { + for (UUID bandedId : creatureIds) { + if (!bandedId.equals(creatureId)) { + Permanent banded = game.getPermanent(bandedId); + if (banded != null && banded.getName().equals(ability.getName())) { + return true; + } + } + } + } + } + } + } + } + } + return false; + } + public void assignDamageToBlockers(boolean first, Game game) { if (!attackers.isEmpty() && (!first || hasFirstOrDoubleStrike(game))) { Permanent attacker = game.getPermanent(attackers.get(0)); @@ -837,6 +889,9 @@ public class CombatGroup implements Serializable, Copyable { } } } + if (appliesBandsWithOther(attackers, game)) { // 702.21k - both a [quality] creature with “bands with other [quality]” and another [quality] creature (...) + return true; + } return false; } @@ -855,6 +910,9 @@ public class CombatGroup implements Serializable, Copyable { } } } + if (appliesBandsWithOther(blockers, game)) { // 702.21j - both a [quality] creature with “bands with other [quality]” and another [quality] creature (...) + return true; + } for (Permanent defensiveFormation : game.getBattlefield().getAllActivePermanents(defendingPlayerId)) { if (defensiveFormation.getAbilities().containsKey(ControllerAssignCombatDamageToBlockersAbility.getInstance().getId())) { return true; diff --git a/Mage/src/main/java/mage/game/permanent/token/WolvesOfTheHuntToken.java b/Mage/src/main/java/mage/game/permanent/token/WolvesOfTheHuntToken.java new file mode 100644 index 0000000000..af156cd597 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/WolvesOfTheHuntToken.java @@ -0,0 +1,32 @@ + +package mage.game.permanent.token; + +import mage.constants.CardType; +import mage.constants.SubType; +import mage.MageInt; +import mage.abilities.keyword.BandsWithOtherAbility; + +/** + * + * @author L_J + */ +public final class WolvesOfTheHuntToken extends TokenImpl { + + public WolvesOfTheHuntToken() { + super("Wolves of the Hunt", "1/1 green Wolf creature token named Wolves of the Hunt"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.WOLF); + color.setGreen(true); + power = new MageInt(1); + toughness = new MageInt(1); + this.addAbility(new BandsWithOtherAbility("Wolves of the Hunt")); + } + + public WolvesOfTheHuntToken(final WolvesOfTheHuntToken token) { + super(token); + } + + public WolvesOfTheHuntToken copy() { + return new WolvesOfTheHuntToken(this); + } +}