[CMR] fixed Akroma's Will - missing copy of new condition in modes (#7210);

Improved compatibility of new modes condition with choose dialogs and test framework;
This commit is contained in:
Oleg Agafonov 2020-11-28 19:49:16 +04:00
parent 64821a50d3
commit 2b78388eab
5 changed files with 131 additions and 32 deletions

View file

@ -1924,7 +1924,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
@Override
public Mode chooseMode(Modes modes, Ability source, Game game) {
log.debug("chooseMode");
if (modes.getMode() != null && modes.getMaxModes() == modes.getSelectedModes().size()) {
if (modes.getMode() != null && modes.getMaxModes(game, source) == modes.getSelectedModes().size()) {
// mode was already set by the AI
return modes.getMode();
}

View file

@ -2085,7 +2085,7 @@ public class HumanPlayer extends PlayerImpl {
boolean done = false;
while (!done && canRespond()) {
String message = "Choose mode (selected " + modes.getSelectedModes().size() + " of " + modes.getMaxModes()
String message = "Choose mode (selected " + modes.getSelectedModes().size() + " of " + modes.getMaxModes(game, source)
+ ", min " + modes.getMinModes() + ")";
if (obj != null) {
message = message + "<br>" + obj.getLogName();

View file

@ -0,0 +1,81 @@
package org.mage.test.cards.single.cmr;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.LifelinkAbility;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestCommanderDuelBase;
/**
* @author JayDi85
*/
public class AkromasWillTest extends CardTestCommanderDuelBase {
@Test
public void test_OneMode() {
// https://github.com/magefree/mage/issues/7210
// Choose one. If you control a commander as you cast this spell, you may choose both.
// * Creatures you control gain flying, vigilance, and double strike until end of turn.
// * Creatures you control gain lifelink, indestructible, and protection from all colors until end of turn.
addCard(Zone.HAND, playerA, "Akroma's Will", 1); // {3}{W}
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
//
addCard(Zone.BATTLEFIELD, playerA, "Kitesail Corsair", 1);
checkAbility("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Kitesail Corsair", FlyingAbility.class, false);
checkAbility("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Kitesail Corsair", LifelinkAbility.class, false);
// cast and use ONE mode only
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akroma's Will");
setModeChoice(playerA, "1");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkAbility("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Kitesail Corsair", FlyingAbility.class, true);
checkAbility("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Kitesail Corsair", LifelinkAbility.class, false);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
}
@Test
public void test_MultiModesOnCommander() {
// https://github.com/magefree/mage/issues/7210
// Choose one. If you control a commander as you cast this spell, you may choose both.
// * Creatures you control gain flying, vigilance, and double strike until end of turn.
// * Creatures you control gain lifelink, indestructible, and protection from all colors until end of turn.
addCard(Zone.HAND, playerA, "Akroma's Will", 1); // {3}{W}
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
//
addCard(Zone.COMMAND, playerA, "Balduvian Bears", 1); // {1}{G}
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2);
//
addCard(Zone.BATTLEFIELD, playerA, "Kitesail Corsair", 1);
checkAbility("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Kitesail Corsair", FlyingAbility.class, false);
checkAbility("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Kitesail Corsair", LifelinkAbility.class, false);
// prepare commander
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {G}", 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Balduvian Bears");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPermanentCount("commander on battle", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Balduvian Bears", 1);
// cast and use two modes instead one
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akroma's Will");
setModeChoice(playerA, "2");
setModeChoice(playerA, "1");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkAbility("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Kitesail Corsair", FlyingAbility.class, true);
checkAbility("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Kitesail Corsair", LifelinkAbility.class, true);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
}
}

View file

@ -1869,7 +1869,7 @@ public class TestPlayer implements Player {
@Override
public Mode chooseMode(Modes modes, Ability source, Game game) {
if (!modesSet.isEmpty() && modes.getMaxModes() > modes.getSelectedModes().size()) {
if (!modesSet.isEmpty() && modes.getMaxModes(game, source) > modes.getSelectedModes().size()) {
// set mode to null to select less than maximum modes if multiple modes are allowed
if (modesSet.get(0) == null) {
modesSet.remove(0);

View file

@ -76,6 +76,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
} else {
this.currentMode = get(modes.getMode().getId()); // need fix?
}
this.moreCondition = modes.moreCondition;
}
public Modes copy() {
@ -190,8 +191,41 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
this.maxModesFilter = maxModesFilter;
}
public int getMaxModes() {
return this.maxModes;
/**
* Return real affected max modes in current game. Use null params for default max modes value.
*
* @param game
* @param source
* @return
*/
public int getMaxModes(Game game, Ability source) {
int realMaxModes = this.maxModes;
if (game == null || source == null) {
return realMaxModes;
}
// use case: make all modes chooseable
if (moreCondition != null && moreCondition.apply(game, source)) {
realMaxModes = Integer.MAX_VALUE;
}
// use case: limit max modes by opponents (wtf?!)
if (getMaxModesFilter() != null) {
if (this.maxModesFilter instanceof FilterPlayer) {
realMaxModes = 0;
for (UUID targetPlayerId : game.getState().getPlayersInRange(source.getControllerId(), game)) {
Player targetPlayer = game.getPlayer(targetPlayerId);
if (((FilterPlayer) this.maxModesFilter).match(targetPlayer, source.getSourceId(), source.getControllerId(), game)) {
realMaxModes++;
}
}
if (realMaxModes > this.maxModes) {
realMaxModes = this.maxModes;
}
}
}
return realMaxModes;
}
public void setModeChooser(TargetController modeChooser) {
@ -222,9 +256,9 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
public boolean choose(Game game, Ability source) {
if (this.isResetEachTurn()) {
if (this.getTurnNum(game, source) != game.getTurnNum()) {
if (getTurnNum(game, source) != game.getTurnNum()) {
this.clearAlreadySelectedModes(source, game);
this.setTurnNum(game, source);
setTurnNum(game, source);
}
}
if (this.size() > 1) {
@ -284,24 +318,8 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
// player chooses modes manually
this.currentMode = null;
int currentMaxModes = this.getMaxModes();
if (moreCondition != null && moreCondition.apply(game, source)) {
currentMaxModes = Integer.MAX_VALUE;
}
if (getMaxModesFilter() != null) {
if (maxModesFilter instanceof FilterPlayer) {
currentMaxModes = 0;
for (UUID targetPlayerId : game.getState().getPlayersInRange(source.getControllerId(), game)) {
Player targetPlayer = game.getPlayer(targetPlayerId);
if (((FilterPlayer) maxModesFilter).match(targetPlayer, source.getSourceId(), source.getControllerId(), game)) {
currentMaxModes++;
}
}
if (currentMaxModes > this.getMaxModes()) {
currentMaxModes = this.getMaxModes();
}
}
}
int currentMaxModes = this.getMaxModes(game, source);
while (this.selectedModes.size() < currentMaxModes) {
Mode choice = player.chooseMode(this, source, game);
if (choice == null) {
@ -446,19 +464,19 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
sb.append(chooseText);
} else if (this.getMaxModesFilter() != null) {
sb.append("choose one or more. Each mode must target ").append(getMaxModesFilter().getMessage());
} else if (this.getMinModes() == 0 && this.getMaxModes() == 1) {
} else if (this.getMinModes() == 0 && this.getMaxModes(null, null) == 1) {
sb.append("choose up to one");
} else if (this.getMinModes() == 0 && this.getMaxModes() == 3) {
} else if (this.getMinModes() == 0 && this.getMaxModes(null, null) == 3) {
sb.append("choose any number");
} else if (this.getMinModes() == 1 && this.getMaxModes() > 2) {
} else if (this.getMinModes() == 1 && this.getMaxModes(null, null) > 2) {
sb.append("choose one or more");
} else if (this.getMinModes() == 1 && this.getMaxModes() == 2) {
} else if (this.getMinModes() == 1 && this.getMaxModes(null, null) == 2) {
sb.append("choose one or both");
} else if (this.getMinModes() == 2 && this.getMaxModes() == 2) {
} else if (this.getMinModes() == 2 && this.getMaxModes(null, null) == 2) {
sb.append("choose two");
} else if (this.getMinModes() == 3 && this.getMaxModes() == 3) {
} else if (this.getMinModes() == 3 && this.getMaxModes(null, null) == 3) {
sb.append("choose three");
} else if (this.getMinModes() == 4 && this.getMaxModes() == 4) {
} else if (this.getMinModes() == 4 && this.getMaxModes(null, null) == 4) {
sb.append("choose four");
} else {
sb.append("choose one");