mirror of
https://github.com/magefree/mage.git
synced 2025-12-23 03:51:58 -08:00
* AI: fixed wrong targeting for gain control abilities (#6340);
This commit is contained in:
parent
3cd5682db7
commit
14ddb6eb28
7 changed files with 99 additions and 24 deletions
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue