* AI: fixed wrong targeting for gain control abilities (#6340);

This commit is contained in:
Oleg Agafonov 2020-03-11 18:22:58 +04:00
parent 3cd5682db7
commit 14ddb6eb28
7 changed files with 99 additions and 24 deletions

View file

@ -1,7 +1,5 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.AttachEffect;
@ -16,8 +14,9 @@ import mage.constants.Zone;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetLandPermanent; import mage.target.common.TargetLandPermanent;
import java.util.UUID;
/** /**
*
* @author andyfries * @author andyfries
*/ */
public final class Annex extends CardImpl { public final class Annex extends CardImpl {
@ -26,7 +25,6 @@ public final class Annex extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}");
this.subtype.add(SubType.AURA); this.subtype.add(SubType.AURA);
// Enchant land // Enchant land
TargetPermanent auraTarget = new TargetLandPermanent(); TargetPermanent auraTarget = new TargetLandPermanent();
this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addTarget(auraTarget);

View file

@ -1,7 +1,5 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.AttachEffect;
@ -10,16 +8,16 @@ import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
/** import java.util.UUID;
*
* @author KholdFuzion
/**
* @author KholdFuzion
*/ */
public final class ControlMagic extends CardImpl { public final class ControlMagic extends CardImpl {
@ -27,13 +25,13 @@ public final class ControlMagic extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}");
this.subtype.add(SubType.AURA); this.subtype.add(SubType.AURA);
// Enchant creature // Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent(); TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.GainControl)); this.getSpellAbility().addEffect(new AttachEffect(Outcome.GainControl));
Ability ability = new EnchantAbility(auraTarget.getTargetName()); Ability ability = new EnchantAbility(auraTarget.getTargetName());
this.addAbility(ability); this.addAbility(ability);
// You control enchanted creature. // You control enchanted creature.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ControlEnchantedEffect())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ControlEnchantedEffect()));
} }

View file

@ -38,7 +38,7 @@ public final class Preacher extends CardImpl {
// You may choose not to untap Preacher during your untap step. // You may choose not to untap Preacher during your untap step.
this.addAbility(new SkipUntapOptionalAbility()); this.addAbility(new SkipUntapOptionalAbility());
// {tap}: Gain control of target creature of an opponent's choice that they control for as long as Preacher remains tapped. // {T}: Gain control of target creature of an opponent's choice that they control for as long as Preacher remains tapped.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreacherEffect(), new TapSourceCost()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreacherEffect(), new TapSourceCost());
ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, new FilterControlledCreaturePermanent(), false)); ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, new FilterControlledCreaturePermanent(), false));
this.addAbility(ability); this.addAbility(ability);

View file

@ -0,0 +1,75 @@
package org.mage.test.AI.basic;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps;
/**
* @author JayDi85
*/
public class GainControlAITest extends CardTestPlayerBaseWithAIHelps {
@Test
public void test_GainControl_Manual() {
// You control enchanted land.
addCard(Zone.HAND, playerA, "Annex", 1); // {2}{U}{U}
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 1);
// take control
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Annex", "Swamp");
setStopAt(1, PhaseStep.END_TURN);
setStrictChooseMode(true);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Island", 4);
assertPermanentCount(playerA, "Swamp", 1);
assertPermanentCount(playerB, "Swamp", 0);
}
@Test
public void test_GainControl_AI_Single() {
// You control enchanted land.
addCard(Zone.HAND, playerA, "Annex", 1); // {2}{U}{U}
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 1);
// take control by AI
aiPlayPriority(1, PhaseStep.PRECOMBAT_MAIN, playerA);
setStopAt(1, PhaseStep.END_TURN);
setStrictChooseMode(true);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Island", 4);
assertPermanentCount(playerA, "Swamp", 1);
assertPermanentCount(playerB, "Swamp", 0);
}
@Test
public void test_GainControl_AI_MostValuable() {
// You control enchanted land.
addCard(Zone.HAND, playerA, "Annex", 1); // {2}{U}{U}
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 1);
addCard(Zone.BATTLEFIELD, playerB, "Badlands", 1);
// take control by AI (selects most valueable enemy card)
aiPlayPriority(1, PhaseStep.PRECOMBAT_MAIN, playerA);
setStopAt(1, PhaseStep.END_TURN);
setStrictChooseMode(true);
execute();
assertAllCommandsUsed();
assertPermanentCount(playerA, "Island", 4);
assertPermanentCount(playerA, "Swamp", 0);
assertPermanentCount(playerA, "Badlands", 1);
assertPermanentCount(playerB, "Swamp", 1);
assertPermanentCount(playerB, "Badlands", 0);
}
}

View file

@ -55,6 +55,6 @@ public class TargetControllerChangeTest extends CardTestPlayerBase {
assertAllCommandsUsed(); assertAllCommandsUsed();
assertGraveyardCount(playerA, "Evangelize", 1); assertGraveyardCount(playerA, "Evangelize", 1);
assertPermanentCount(playerA, "Balduvian Bears", 1); // AI give smallest permanent to A as bad effect for B assertPermanentCount(playerA, "Balduvian Bears", 1); // AI give smallest permanent to A as bad effect for target (target control change)
} }
} }

View file

@ -17,7 +17,7 @@ public enum Outcome {
PutCreatureInPlay(true), PutCreatureInPlay(true),
PutCardInPlay(true), PutCardInPlay(true),
PutLandInPlay(true), PutLandInPlay(true),
GainControl(true), GainControl(false),
DrawCard(true), DrawCard(true),
Discard(false), Discard(false),
Sacrifice(false), Sacrifice(false),
@ -27,9 +27,9 @@ public enum Outcome {
Protect(true), Protect(true),
PutManaInPool(true), PutManaInPool(true),
Regenerate(true), Regenerate(true),
PreventDamage(true), PreventDamage(true), // TODO: check good or bad
PreventCast(false), PreventCast(false), // TODO: check good or bad
RedirectDamage(true), RedirectDamage(true), // TODO: check good or bad
Tap(false), Tap(false),
Transform(true), Transform(true),
Untap(true), Untap(true),
@ -40,9 +40,13 @@ public enum Outcome {
Neutral(true), Neutral(true),
Removal(false), Removal(false),
AIDontUseIt(false), AIDontUseIt(false),
Vote(true); Vote(true); // TODO: check good or bad
private final boolean good; // good or bad effect for targeting player (for AI usage) // good or bad effect for TARGET, not targeting player (for AI usage)
// AI sorting targets by priorities (own or opponents) and selects most valueable or weakest
private final boolean good;
// no different between own or opponent targets (example: copy must choose from all permanents) // TODO: copy must choose most valueable from opponent too
private boolean canTargetAll; private boolean canTargetAll;
Outcome(boolean good) { Outcome(boolean good) {
@ -63,7 +67,7 @@ public enum Outcome {
} }
public static Outcome inverse(Outcome outcome) { public static Outcome inverse(Outcome outcome) {
// inverse bad/good effect (as example, after controlling player change) // inverse bad/good effect
if (outcome.isGood()) { if (outcome.isGood()) {
return Outcome.Detriment; return Outcome.Detriment;
} else { } else {

View file

@ -70,8 +70,8 @@ public class TargetOpponentsChoicePermanent extends TargetPermanent {
return false; return false;
} }
// opponent choose real targets (outcome must be inversed) // opponent choose real targets
return super.chooseTarget(Outcome.inverse(outcome), opponentId, source, game); return super.chooseTarget(outcome, opponentId, source, game);
} }
@Override @Override