mirror of
https://github.com/magefree/mage.git
synced 2026-01-09 20:32:06 -08:00
AI: improved combat support:
* added support to attack battle permanents (#10246); * fixed that AI was able to attack multiple targets by single creature (#7434); * added docs; * added todos with another bugs or possible problems with AI combat;
This commit is contained in:
parent
6858d43547
commit
e4157fefb8
16 changed files with 239 additions and 89 deletions
|
|
@ -3,20 +3,22 @@ package org.mage.test.cards.battle;
|
|||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class BattleBaseTest extends CardTestPlayerBase {
|
||||
public class BattleBaseTest extends CardTestPlayerBaseWithAIHelps {
|
||||
|
||||
protected static final String belenon = "Invasion of Belenon";
|
||||
protected static final String warAnthem = "Belenon War Anthem";
|
||||
protected static final String kaladesh = "Invasion of Kaladesh";
|
||||
protected static final String bear = "Grizzly Bears";
|
||||
protected static final String bearWithFlyingAndVigilance = "Abbey Griffin";
|
||||
protected static final String confiscate = "Confiscate";
|
||||
protected static final String impact = "Explosive Impact";
|
||||
protected static final String stifle = "Stifle";
|
||||
protected static final String fayden = "Dack Fayden";
|
||||
|
||||
protected void assertBattle(Player controller, Player protector, String name) {
|
||||
assertPermanentCount(controller, name, 1);
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import mage.counters.CounterType;
|
|||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
* @author TheElk801, JayDi85
|
||||
*/
|
||||
public class BattleDuelTest extends BattleBaseTest {
|
||||
|
||||
|
|
@ -155,6 +155,7 @@ public class BattleDuelTest extends BattleBaseTest {
|
|||
assertGraveyardCount(playerA, kaladesh, 1);
|
||||
assertPermanentCount(playerA, "Thopter Token", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSpellCardTypeTrigger() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plateau", 3 + 6);
|
||||
|
|
@ -174,6 +175,93 @@ public class BattleDuelTest extends BattleBaseTest {
|
|||
|
||||
assertPermanentCount(playerA, "Serra Faithkeeper", 1);
|
||||
assertPermanentCount(playerA, "Warrior Token", 1);
|
||||
assertPowerToughness(playerA, "Deeproot Champion",3,3);
|
||||
assertPowerToughness(playerA, "Deeproot Champion", 3, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_AI_CastBattle() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
|
||||
addCard(Zone.HAND, playerA, belenon);
|
||||
|
||||
aiPlayPriority(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertBattle(playerA, playerB, belenon);
|
||||
assertPermanentCount(playerA, "Knight Token", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_AI_AttackPriority_TargetBattleInsteadPlayer() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, bear);
|
||||
addCard(Zone.HAND, playerA, belenon);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, belenon);
|
||||
|
||||
// ai must attack planeswalker instead player
|
||||
aiPlayStep(1, PhaseStep.DECLARE_ATTACKERS, playerA);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertBattle(playerA, playerB, belenon);
|
||||
assertPermanentCount(playerA, "Knight Token", 1);
|
||||
assertTapped(bear, true);
|
||||
assertLife(playerB, 20);
|
||||
assertCounterCount(belenon, CounterType.DEFENSE, 5 - 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_AI_AttackPriority_TargetPlaneswalkerInsteadBattle() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, bear);
|
||||
addCard(Zone.BATTLEFIELD, playerB, fayden); // 3
|
||||
addCard(Zone.HAND, playerA, belenon);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, belenon);
|
||||
|
||||
// ai must attack planeswalker instead battle/player
|
||||
aiPlayStep(1, PhaseStep.DECLARE_ATTACKERS, playerA);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertBattle(playerA, playerB, belenon);
|
||||
assertPermanentCount(playerA, "Knight Token", 1);
|
||||
assertTapped(bear, true);
|
||||
assertLife(playerB, 20);
|
||||
assertCounterCount(belenon, CounterType.DEFENSE, 5);
|
||||
assertCounterCount(fayden, CounterType.LOYALTY, 3 - 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_AI_MustNotAttackMultipleTargets() {
|
||||
// bug with multiple targets for single attacker: https://github.com/magefree/mage/issues/7434
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
|
||||
addCard(Zone.BATTLEFIELD, playerA, bearWithFlyingAndVigilance);
|
||||
addCard(Zone.BATTLEFIELD, playerB, fayden); // 3
|
||||
addCard(Zone.HAND, playerA, belenon);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, belenon);
|
||||
|
||||
// ai must attack planeswalker instead battle/player
|
||||
// ai must attack only single target
|
||||
aiPlayStep(1, PhaseStep.DECLARE_ATTACKERS, playerA);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertBattle(playerA, playerB, belenon);
|
||||
assertPermanentCount(playerA, "Knight Token", 1);
|
||||
assertTapped(bearWithFlyingAndVigilance, false); // vigilance
|
||||
assertLife(playerB, 20);
|
||||
assertCounterCount(belenon, CounterType.DEFENSE, 5);
|
||||
assertCounterCount(fayden, CounterType.LOYALTY, 3 - 2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ public abstract class CardTestCommander4PlayersWithAIHelps extends CardTestComma
|
|||
@Override
|
||||
protected TestPlayer createPlayer(String name, RangeOfInfluence rangeOfInfluence) {
|
||||
// use same RangeOfInfluence.ALL as CardTestCommander4Players do
|
||||
TestPlayer testPlayer = new TestPlayer(new TestComputerPlayer7(name, RangeOfInfluence.ALL, 6));
|
||||
TestPlayer testPlayer = new TestPlayer(new TestComputerPlayer7(name, rangeOfInfluence, 6));
|
||||
testPlayer.setAIPlayer(false); // AI can't play it by itself, use AI commands
|
||||
return testPlayer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public abstract class CardTestPlayerBaseWithAIHelps extends CardTestPlayerBase {
|
|||
|
||||
@Override
|
||||
protected TestPlayer createPlayer(String name, RangeOfInfluence rangeOfInfluence) {
|
||||
TestPlayer testPlayer = new TestPlayer(new TestComputerPlayer7(name, RangeOfInfluence.ONE, 6));
|
||||
TestPlayer testPlayer = new TestPlayer(new TestComputerPlayer7(name, rangeOfInfluence, 6));
|
||||
testPlayer.setAIPlayer(false); // AI can't play it by itself, use AI commands
|
||||
return testPlayer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1681,6 +1681,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
|||
* AI play STEP to the end with multi game simulations (calcs and play best
|
||||
* actions until step ends, can be called in the middle of the step) All
|
||||
* choices must be made by AI (e.g. strict mode possible)
|
||||
* <p>
|
||||
* Can be used for AI's declare of attackers/blockers
|
||||
*/
|
||||
public void aiPlayStep(int turnNum, PhaseStep step, TestPlayer player) {
|
||||
assertAiPlayAndGameCompatible(player);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue