mirror of
https://github.com/correl/mage.git
synced 2025-04-13 01:01:11 -09:00
* Replicate abilities - fixed that AI can freeze the game after play card with replicate (AI don't use it now);
This commit is contained in:
parent
a249dcffd8
commit
1ae9fc883e
4 changed files with 74 additions and 23 deletions
Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords
Mage/src/main/java/mage/abilities
|
@ -1,14 +1,12 @@
|
||||||
|
|
||||||
|
|
||||||
package org.mage.test.cards.abilities.keywords;
|
package org.mage.test.cards.abilities.keywords;
|
||||||
|
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author BetaSteward
|
* @author BetaSteward
|
||||||
*/
|
*/
|
||||||
public class ReplicateTest extends CardTestPlayerBase {
|
public class ReplicateTest extends CardTestPlayerBase {
|
||||||
|
@ -24,17 +22,16 @@ public class ReplicateTest extends CardTestPlayerBase {
|
||||||
* replicate cost follows the rules for paying additional costs in rules 601.2b and 601.2e–g.
|
* replicate cost follows the rules for paying additional costs in rules 601.2b and 601.2e–g.
|
||||||
* 702.55b If a spell has multiple instances of replicate, each is paid separately and triggers based on
|
* 702.55b If a spell has multiple instances of replicate, each is paid separately and triggers based on
|
||||||
* the payments made for it, not any other instance of replicate.
|
* the payments made for it, not any other instance of replicate.
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Train of Thought
|
|
||||||
* Sorcery, 1U (2)
|
|
||||||
* Replicate {1}{U} (When you cast this spell, copy it for each time you paid its replicate cost.)
|
|
||||||
* Draw a card.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Train of Thought
|
||||||
|
* Sorcery, 1U (2)
|
||||||
|
* Replicate {1}{U} (When you cast this spell, copy it for each time you paid its replicate cost.)
|
||||||
|
* Draw a card.
|
||||||
|
*/
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReplicate1Time() {
|
public void testReplicate1Time() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
||||||
|
@ -49,9 +46,8 @@ public class ReplicateTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
assertGraveyardCount(playerA, "Train of Thought", 1);
|
assertGraveyardCount(playerA, "Train of Thought", 1);
|
||||||
assertHandCount(playerA, 2);
|
assertHandCount(playerA, 2);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReplicate2Times() {
|
public void testReplicate2Times() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
||||||
|
@ -67,7 +63,6 @@ public class ReplicateTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
assertGraveyardCount(playerA, "Train of Thought", 1);
|
assertGraveyardCount(playerA, "Train of Thought", 1);
|
||||||
assertHandCount(playerA, 3);
|
assertHandCount(playerA, 3);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -83,7 +78,55 @@ public class ReplicateTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
assertGraveyardCount(playerA, "Train of Thought", 1);
|
assertGraveyardCount(playerA, "Train of Thought", 1);
|
||||||
assertHandCount(playerA, 1);
|
assertHandCount(playerA, 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReplicate_User() {
|
||||||
|
// Replicate {1}{R} (When you cast this spell, copy it for each time you paid its replicate cost. You may choose new targets for the copies.)
|
||||||
|
// Pyromatics deals 1 damage to any target.
|
||||||
|
addCard(Zone.HAND, playerA, "Pyromatics", 1); // {1}{R}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pyromatics");
|
||||||
|
addTarget(playerA, playerB);
|
||||||
|
setChoice(playerA, "Yes"); // replicate 1
|
||||||
|
setChoice(playerA, "Yes"); // replicate 2
|
||||||
|
setChoice(playerA, "No"); // stop
|
||||||
|
//
|
||||||
|
setChoice(playerA, "No"); // don't change target 1
|
||||||
|
setChoice(playerA, "No"); // don't change target 2
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertLife(playerB, 20 - 3); // 1 + 2 replicates
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore // TODO: enable test after replicate ability will be supported by AI
|
||||||
|
public void testReplicate_AI() {
|
||||||
|
// Replicate {1}{R} (When you cast this spell, copy it for each time you paid its replicate cost. You may choose new targets for the copies.)
|
||||||
|
// Pyromatics deals 1 damage to any target.
|
||||||
|
addCard(Zone.HAND, playerA, "Pyromatics", 1); // {1}{R}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pyromatics");
|
||||||
|
addTarget(playerA, playerB);
|
||||||
|
//setChoice(playerA, "Yes"); // replicate 1 - AI must choice max possible
|
||||||
|
//setChoice(playerA, "Yes"); // replicate 2 - AI must choice max possible
|
||||||
|
//setChoice(playerA, "No"); // stop - AI must choice max possible
|
||||||
|
//
|
||||||
|
//setChoice(playerA, "No"); // don't change target 1
|
||||||
|
//setChoice(playerA, "No"); // don't change target 2
|
||||||
|
|
||||||
|
//setStrictChooseMode(true); - AI must choice
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertLife(playerB, 20 - 3); // 1 + 2 replicates
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
|
|
||||||
package mage.abilities.costs;
|
package mage.abilities.costs;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.target.Targets;
|
import mage.target.Targets;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public interface Cost extends Serializable {
|
public interface Cost extends Serializable {
|
||||||
|
|
||||||
UUID getId();
|
UUID getId();
|
||||||
|
@ -15,6 +15,10 @@ public interface Cost extends Serializable {
|
||||||
|
|
||||||
void setText(String text);
|
void setText(String text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check is it possible to pay
|
||||||
|
* For mana it checks only single color and amount available, not total mana cost
|
||||||
|
*/
|
||||||
boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game);
|
boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game);
|
||||||
|
|
||||||
boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana);
|
boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
package mage.abilities.costs;
|
package mage.abilities.costs;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
@ -6,7 +5,7 @@ import mage.game.Game;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for abilities that add additional costs to the source.
|
* Interface for abilities that add additional costs to the source.
|
||||||
*
|
* <p>
|
||||||
* Example of such additional source costs:
|
* Example of such additional source costs:
|
||||||
* {@link mage.abilities.keyword.KickerAbility}
|
* {@link mage.abilities.keyword.KickerAbility}
|
||||||
*
|
*
|
||||||
|
@ -14,6 +13,7 @@ import mage.game.Game;
|
||||||
*/
|
*/
|
||||||
public interface OptionalAdditionalSourceCosts {
|
public interface OptionalAdditionalSourceCosts {
|
||||||
|
|
||||||
|
// TODO: add AI support to use buyback, replicate and other additional costs (current version can't calc available mana before buyback use)
|
||||||
void addOptionalAdditionalCosts(Ability ability, Game game);
|
void addOptionalAdditionalCosts(Ability ability, Game game);
|
||||||
|
|
||||||
String getCastMessageSuffix();
|
String getCastMessageSuffix();
|
||||||
|
|
|
@ -88,8 +88,12 @@ public class ReplicateAbility extends StaticAbility implements OptionalAdditiona
|
||||||
int numActivations = additionalCost.getActivateCount();
|
int numActivations = additionalCost.getActivateCount();
|
||||||
times = (numActivations + 1) + (numActivations == 0 ? " time " : " times ");
|
times = (numActivations + 1) + (numActivations == 0 ? " time " : " times ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test costs
|
||||||
|
// TODO: add AI support to find max number of possible activations (from available mana)
|
||||||
|
// canPay checks only single mana available, not total mana usage
|
||||||
if (additionalCost.canPay(ability, sourceId, controllerId, game)
|
if (additionalCost.canPay(ability, sourceId, controllerId, game)
|
||||||
&& player.chooseUse(Outcome.Benefit, new StringBuilder("Pay ").append(times).append(additionalCost.getText(false)).append(" ?").toString(), ability, game)) {
|
&& player.chooseUse(/*Outcome.Benefit*/Outcome.AIDontUseIt, new StringBuilder("Pay ").append(times).append(additionalCost.getText(false)).append(" ?").toString(), ability, game)) {
|
||||||
additionalCost.activate();
|
additionalCost.activate();
|
||||||
for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext(); ) {
|
for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext(); ) {
|
||||||
Cost cost = (Cost) it.next();
|
Cost cost = (Cost) it.next();
|
||||||
|
|
Loading…
Add table
Reference in a new issue