Fix TargetStackObject not handling some predicate types correctly. Implement card to test it: Diplomatic Escort

This commit is contained in:
LoneFox 2015-10-14 22:58:43 +03:00 committed by AlumiuN
parent 11efdcad78
commit f801477ab5
2 changed files with 99 additions and 16 deletions

View file

@ -0,0 +1,83 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.sets.mercadianmasques;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.filter.FilterStackObject;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.other.TargetsPermanentPredicate;
import mage.target.TargetStackObject;
/**
*
* @author LoneFox
*/
public class DiplomaticEscort extends CardImpl {
private final static FilterStackObject filter = new FilterStackObject("spell or ability that targets a creature");
static {
filter.add(new TargetsPermanentPredicate(new FilterCreaturePermanent()));
}
public DiplomaticEscort(UUID ownerId) {
super(ownerId, 74, "Diplomatic Escort", Rarity.UNCOMMON, new CardType[]{CardType.CREATURE}, "{1}{U}");
this.expansionSetCode = "MMQ";
this.subtype.add("Human");
this.subtype.add("Spellshaper");
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// {U}, {tap}, Discard a card: Counter target spell or ability that targets a creature.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new ManaCostsImpl("{U}"));
ability.addCost(new TapSourceCost());
ability.addCost(new DiscardCardCost());
ability.addTarget(new TargetStackObject(filter));
this.addAbility(ability);
}
public DiplomaticEscort(final DiplomaticEscort card) {
super(card);
}
@Override
public DiplomaticEscort copy() {
return new DiplomaticEscort(this);
}
}

View file

@ -1,16 +1,16 @@
/* /*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without modification, are * Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met: * permitted provided that the following conditions are met:
* *
* 1. Redistributions of source code must retain the above copyright notice, this list of * 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer. * conditions and the following disclaimer.
* *
* 2. Redistributions in binary form must reproduce the above copyright notice, this list * 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials * of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution. * provided with the distribution.
* *
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
@ -20,7 +20,7 @@
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* The views and conclusions contained in the software and documentation are those of the * The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
@ -80,21 +80,16 @@ public class TargetStackObject extends TargetObject {
public boolean canTarget(UUID id, Ability source, Game game) { public boolean canTarget(UUID id, Ability source, Game game) {
StackObject stackObject = game.getStack().getStackObject(id); StackObject stackObject = game.getStack().getStackObject(id);
if (stackObject != null) { if (stackObject != null) {
return filter.match(stackObject, game); return filter.match(stackObject, source.getSourceId(), source.getControllerId(), game);
} }
return false; return false;
} }
@Override @Override
public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) {
return canChoose(sourceControllerId, game);
}
@Override
public boolean canChoose(UUID sourceControllerId, Game game) {
int count = 0; int count = 0;
for (StackObject stackObject: game.getStack()) { for (StackObject stackObject: game.getStack()) {
if (game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match(stackObject, game)) { if (game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match(stackObject, sourceId, sourceControllerId, game)) {
count++; count++;
if (count >= this.minNumberOfTargets) { if (count >= this.minNumberOfTargets) {
return true; return true;
@ -105,21 +100,26 @@ public class TargetStackObject extends TargetObject {
} }
@Override @Override
public Set<UUID> possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { public boolean canChoose(UUID sourceControllerId, Game game) {
return possibleTargets(sourceControllerId, game); return canChoose(null, sourceControllerId, game);
} }
@Override @Override
public Set<UUID> possibleTargets(UUID sourceControllerId, Game game) { public Set<UUID> possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) {
Set<UUID> possibleTargets = new HashSet<>(); Set<UUID> possibleTargets = new HashSet<>();
for (StackObject stackObject: game.getStack()) { for (StackObject stackObject: game.getStack()) {
if (game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match(stackObject, game)) { if (game.getPlayer(sourceControllerId).getInRange().contains(stackObject.getControllerId()) && filter.match(stackObject, sourceId, sourceControllerId, game)) {
possibleTargets.add(stackObject.getId()); possibleTargets.add(stackObject.getId());
} }
} }
return possibleTargets; return possibleTargets;
} }
@Override
public Set<UUID> possibleTargets(UUID sourceControllerId, Game game) {
return this.possibleTargets(null, sourceControllerId, game);
}
@Override @Override
public TargetStackObject copy() { public TargetStackObject copy() {
return new TargetStackObject(this); return new TargetStackObject(this);