forked from External/mage
tests: added verify check for wrong target tags usage, improved work with tagged targets (related to 8b2a81cb42)
This commit is contained in:
parent
3223d99b2a
commit
71b0613355
4 changed files with 121 additions and 36 deletions
|
|
@ -1,23 +1,26 @@
|
|||
package mage.cards.f;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SuperType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.predicate.other.AnotherTargetPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.Target;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Susucr
|
||||
*/
|
||||
public final class FriendlyRivalry extends CardImpl {
|
||||
|
|
@ -31,20 +34,18 @@ public final class FriendlyRivalry extends CardImpl {
|
|||
|
||||
public FriendlyRivalry(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}{G}");
|
||||
|
||||
|
||||
// Target creature you control and up to one other target legendary creature you control
|
||||
// each deal damage equal to their power to target creature you don't control.
|
||||
// Target creature you control and up to one other target legendary creature you control each deal damage equal to their power to target creature you don't control.
|
||||
this.getSpellAbility().addEffect(new FriendlyRivalryEffect());
|
||||
|
||||
TargetControlledCreaturePermanent target1 = new TargetControlledCreaturePermanent();
|
||||
this.getSpellAbility().addTarget(target1.setTargetTag(1));
|
||||
this.getSpellAbility().addTarget(target1.setTargetTag(1).withChooseHint("to deal damage"));
|
||||
|
||||
TargetControlledCreaturePermanent target2 = new TargetControlledCreaturePermanent(0, 1, filter2, false);
|
||||
this.getSpellAbility().addTarget(target2.setTargetTag(2));
|
||||
this.getSpellAbility().addTarget(target2.setTargetTag(2).withChooseHint("to deal damage"));
|
||||
|
||||
TargetCreaturePermanent target3 = new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL);
|
||||
this.getSpellAbility().addTarget(target3);
|
||||
this.getSpellAbility().addTarget(target3.setTargetTag(3).withChooseHint("to take damage"));
|
||||
}
|
||||
|
||||
private FriendlyRivalry(final FriendlyRivalry card) {
|
||||
|
|
@ -62,7 +63,7 @@ class FriendlyRivalryEffect extends OneShotEffect {
|
|||
FriendlyRivalryEffect() {
|
||||
super(Outcome.Benefit);
|
||||
staticText = "Target creature you control and up to one other target legendary " +
|
||||
"creature you control each deal damage equal to their power to target creature you don't control.";
|
||||
"creature you control each deal damage equal to their power to target creature you don't control.";
|
||||
}
|
||||
|
||||
private FriendlyRivalryEffect(final FriendlyRivalryEffect effect) {
|
||||
|
|
@ -77,34 +78,31 @@ class FriendlyRivalryEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
int size = source.getTargets().size();
|
||||
if (size < 2) {
|
||||
if (size < 3) {
|
||||
throw new IllegalArgumentException("Wrong code usage. Lost targets list, must has 3, but found: " + source.getTargets());
|
||||
}
|
||||
|
||||
List<Permanent> toDealDamage = new ArrayList<>();
|
||||
source.getTargets().getTargetsByTag(1).stream()
|
||||
.map(game::getPermanent)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(toDealDamage::add);
|
||||
source.getTargets().getTargetsByTag(2).stream()
|
||||
.map(game::getPermanent)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(toDealDamage::add);
|
||||
Permanent toTakeDamage = source.getTargets().getTargetsByTag(3).stream()
|
||||
.map(game::getPermanent)
|
||||
.filter(Objects::nonNull)
|
||||
.findFirst().orElse(null);
|
||||
if (toDealDamage.isEmpty() || toTakeDamage == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Target damageTarget1 = source.getTargets().get(0);
|
||||
Target damageTarget2 = size == 3 ? source.getTargets().get(1) : null;
|
||||
toDealDamage.forEach(permanent -> {
|
||||
toTakeDamage.damage(permanent.getPower().getValue(), permanent.getId(), source, game, false, true);
|
||||
});
|
||||
|
||||
Target destTarget = source.getTargets().get(size-1);
|
||||
if ((damageTarget1.getTargets().isEmpty() && (damageTarget2 == null || damageTarget2.getTargets().isEmpty()))
|
||||
|| destTarget.getTargets().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Permanent permanentDamage1 = damageTarget1.getTargets().isEmpty() ? null
|
||||
: game.getPermanent(damageTarget1.getTargets().get(0));
|
||||
Permanent permanentDamage2 = damageTarget2 == null || damageTarget2.getTargets().isEmpty() ? null
|
||||
: game.getPermanent(damageTarget2.getTargets().get(0));
|
||||
Permanent permanentDest = game.getPermanent(destTarget.getTargets().get(0));
|
||||
if (permanentDest == null){
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permanentDamage1 != null) {
|
||||
permanentDest.damage(permanentDamage1.getPower().getValue(), permanentDamage1.getId(), source, game, false, true);
|
||||
}
|
||||
if (permanentDamage2 != null) {
|
||||
permanentDest.damage(permanentDamage2.getPower().getValue(), permanentDamage2.getId(), source, game, false, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
package org.mage.test.cards.single.ltr;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.player.TestPlayer;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class FriendlyRivalryTest extends CardTestPlayerBase {
|
||||
|
||||
@Test
|
||||
public void test_target_both() {
|
||||
// Target creature you control and up to one other target legendary creature you control each deal damage
|
||||
// equal to their power to target creature you don't control.
|
||||
addCard(Zone.HAND, playerA, "Friendly Rivalry"); // {R}{G}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); // 2/2
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Aesi, Tyrant of Gyre Strait"); // legendary, 5/5
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Agonasaur Rex"); // 8/8
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Friendly Rivalry");
|
||||
addTarget(playerA, "Grizzly Bears");
|
||||
addTarget(playerA, "Aesi, Tyrant of Gyre Strait");
|
||||
addTarget(playerA, "Agonasaur Rex");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertDamageReceived(playerB, "Agonasaur Rex", 2 + 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_target_single() {
|
||||
// Target creature you control and up to one other target legendary creature you control each deal damage
|
||||
// equal to their power to target creature you don't control.
|
||||
addCard(Zone.HAND, playerA, "Friendly Rivalry"); // {R}{G}
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||
//
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); // 2/2
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Aesi, Tyrant of Gyre Strait"); // legendary, 5/5
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Agonasaur Rex"); // 8/8
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Friendly Rivalry");
|
||||
addTarget(playerA, "Grizzly Bears");
|
||||
addTarget(playerA, TestPlayer.TARGET_SKIP); // skip second target due "up to"
|
||||
addTarget(playerA, "Agonasaur Rex");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertDamageReceived(playerB, "Agonasaur Rex", 2);
|
||||
}
|
||||
}
|
||||
|
|
@ -43,6 +43,7 @@ import mage.game.permanent.token.TokenImpl;
|
|||
import mage.game.permanent.token.custom.CreatureToken;
|
||||
import mage.game.permanent.token.custom.XmageToken;
|
||||
import mage.sets.TherosBeyondDeath;
|
||||
import mage.target.Target;
|
||||
import mage.target.targetpointer.TargetPointer;
|
||||
import mage.tournament.cubes.CubeFromDeck;
|
||||
import mage.util.CardUtil;
|
||||
|
|
@ -2279,6 +2280,19 @@ public class VerifyCardDataTest {
|
|||
}
|
||||
});
|
||||
|
||||
// special check: target tags must be used for all targets and starts with 1
|
||||
card.getAbilities().stream().filter(a -> a.getTargets().size() >= 2).forEach(a -> {
|
||||
Set<Integer> tags = a.getTargets().stream().map(Target::getTargetTag).collect(Collectors.toSet());
|
||||
if (tags.size() == 1 && tags.stream().findFirst().get().equals(0)) {
|
||||
// no tags usage
|
||||
return;
|
||||
}
|
||||
if (tags.size() != a.getTargets().size() || (tags.size() > 1 && tags.contains(0))) {
|
||||
// how-to fix: make sure each target has it's own target tag like 1 and 2 (don't use 0 because it's default)
|
||||
fail(card, "abilities", "wrong target tags: miss tag in one of the targets, current list: " + tags);
|
||||
}
|
||||
});
|
||||
|
||||
// spells have only 1 ability
|
||||
if (card.isInstantOrSorcery()) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -40,6 +40,18 @@ public class Targets extends ArrayList<Target> implements Copyable<Targets> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Target getByTag(int tag) {
|
||||
return this.stream().filter(t -> t.getTargetTag() == tag).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
public List<UUID> getTargetsByTag(int tag) {
|
||||
Target target = getByTag(tag);
|
||||
if (target == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return target.getTargets();
|
||||
}
|
||||
|
||||
public Target getNextUnchosen(Game game) {
|
||||
return getNextUnchosen(game, 0);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue