Eon Frolicker - fixed rollback error on play (#6780);

This commit is contained in:
Oleg Agafonov 2020-07-07 06:32:46 +04:00
parent 55f2893fc4
commit ecaa5a5b42
6 changed files with 91 additions and 29 deletions

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.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
@ -20,8 +18,9 @@ import mage.target.TargetPlayer;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/** /**
*
* @author TheElk801 * @author TheElk801
*/ */
public final class CulturalExchange extends CardImpl { public final class CulturalExchange extends CardImpl {

View file

@ -16,9 +16,9 @@ import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterObject; import mage.filter.FilterPlayer;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.filter.predicate.other.PlayerIdPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.turn.TurnMod; import mage.game.turn.TurnMod;
import mage.players.Player; import mage.players.Player;
@ -85,8 +85,8 @@ class EonFrolickerEffect extends OneShotEffect {
return false; return false;
} }
game.getState().getTurnMods().add(new TurnMod(player.getId(), false)); game.getState().getTurnMods().add(new TurnMod(player.getId(), false));
FilterObject filter = new FilterObject(player.getName()); FilterPlayer filter = new FilterPlayer(player.getName());
filter.add(new ControllerIdPredicate(player.getId())); filter.add(new PlayerIdPredicate(player.getId()));
Ability ability = new ProtectionAbility(filter); Ability ability = new ProtectionAbility(filter);
game.addEffect(new GainAbilityControlledEffect( game.addEffect(new GainAbilityControlledEffect(
ability, Duration.UntilYourNextTurn, ability, Duration.UntilYourNextTurn,

View file

@ -0,0 +1,46 @@
package org.mage.test.cards.single;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author JayDi85
*/
public class EonFrolickerTest extends CardTestPlayerBase {
@Test
public void test_EonFrolicker_NormalPlay() {
// https://github.com/magefree/mage/issues/6780
// {2}{U}{U}
// When Eon Frolicker enters the battlefield, if you cast it, target opponent takes an extra turn after this one.
// Until your next turn, you and planeswalkers you control gain protection from that player.
// (You and planeswalkers you control cant be targeted, dealt damage, or enchanted by anything controlled by that player.)
addCard(Zone.HAND, playerA, "Eon Frolicker", 1);
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
//
// Chandras Fury deals 4 damage to target player or planeswalker and 1 damage to each creature that player or that planeswalkers controller controls.
addCard(Zone.HAND, playerB, "Chandra's Fury", 1); // {4}{R}
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 5);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Eon Frolicker");
addTarget(playerA, playerB);
// AI can targets only Eon Frolicker (cause A protected from B)
checkPlayableAbility("after", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Cast Chandra's Fury", true);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Chandra's Fury");
//addTarget(playerB, playerB);
//setStrictChooseMode(true); // AI must choose target for fury (itself)
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertGraveyardCount(playerB, "Chandra's Fury", 1);
assertLife(playerA, 20);
assertLife(playerB, 20 - 4);
}
}

View file

@ -2124,16 +2124,17 @@ public class TestPlayer implements Player {
|| target.getOriginalTarget() instanceof TargetPermanentOrPlayer || target.getOriginalTarget() instanceof TargetPermanentOrPlayer
|| target.getOriginalTarget() instanceof TargetDefender) { || target.getOriginalTarget() instanceof TargetDefender) {
for (String targetDefinition : targets) { for (String targetDefinition : targets) {
if (targetDefinition.startsWith("targetPlayer=")) { if (!targetDefinition.startsWith("targetPlayer=")) {
checkTargetDefinitionMarksSupport(target, targetDefinition, "="); continue;
String playerName = targetDefinition.substring(targetDefinition.indexOf("targetPlayer=") + 13); }
for (Player player : game.getPlayers().values()) { checkTargetDefinitionMarksSupport(target, targetDefinition, "=");
if (player.getName().equals(playerName) String playerName = targetDefinition.substring(targetDefinition.indexOf("targetPlayer=") + 13);
&& target.canTarget(computerPlayer.getId(), player.getId(), source, game)) { for (Player player : game.getPlayers().values()) {
target.addTarget(player.getId(), source, game); if (player.getName().equals(playerName)
targets.remove(targetDefinition); && target.canTarget(computerPlayer.getId(), player.getId(), source, game)) {
return true; target.addTarget(player.getId(), source, game);
} targets.remove(targetDefinition);
return true;
} }
} }
} }
@ -2146,6 +2147,9 @@ public class TestPlayer implements Player {
|| (target.getOriginalTarget() instanceof TargetCreatureOrPlayer) || (target.getOriginalTarget() instanceof TargetCreatureOrPlayer)
|| (target.getOriginalTarget() instanceof TargetDefender)) { || (target.getOriginalTarget() instanceof TargetDefender)) {
for (String targetDefinition : targets) { for (String targetDefinition : targets) {
if (targetDefinition.startsWith("targetPlayer=")) {
continue;
}
checkTargetDefinitionMarksSupport(target, targetDefinition, "^[]"); checkTargetDefinitionMarksSupport(target, targetDefinition, "^[]");
String[] targetList = targetDefinition.split("\\^"); String[] targetList = targetDefinition.split("\\^");
boolean targetFound = false; boolean targetFound = false;

View file

@ -1,27 +1,24 @@
package mage.abilities.keyword; package mage.abilities.keyword;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.ObjectColor; import mage.ObjectColor;
import mage.abilities.StaticAbility; import mage.abilities.StaticAbility;
import mage.cards.Card; import mage.cards.Card;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.Filter; import mage.filter.*;
import mage.filter.FilterCard;
import mage.filter.FilterObject;
import mage.filter.FilterPermanent;
import mage.filter.FilterSpell;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.game.stack.StackObject; import mage.game.stack.StackObject;
import mage.players.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/** /**
*
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
public class ProtectionAbility extends StaticAbility { public class ProtectionAbility extends StaticAbility {
@ -87,6 +84,7 @@ public class ProtectionAbility extends StaticAbility {
} }
return true; return true;
} }
if (filter instanceof FilterSpell) { if (filter instanceof FilterSpell) {
if (source instanceof Spell) { if (source instanceof Spell) {
return !filter.match(source, game); return !filter.match(source, game);
@ -99,9 +97,21 @@ public class ProtectionAbility extends StaticAbility {
return true; return true;
} }
} }
if (filter instanceof FilterObject) { if (filter instanceof FilterObject) {
return !filter.match(source, game); return !filter.match(source, game);
} }
if (filter instanceof FilterPlayer) {
Player player = null;
if (source instanceof Permanent) {
player = game.getPlayer(((Permanent) source).getControllerId());
} else if (source instanceof Card) {
player = game.getPlayer(((Card) source).getOwnerId());
}
return !((FilterPlayer) filter).match(player, getSourceId(), this.getControllerId(), game);
}
return true; return true;
} }

View file

@ -345,9 +345,12 @@ public abstract class PlayerImpl implements Player, Serializable {
this.clearCastSourceIdManaCosts(); this.clearCastSourceIdManaCosts();
this.castSourceIdWithAlternateMana.addAll(player.getCastSourceIdWithAlternateMana()); this.castSourceIdWithAlternateMana.addAll(player.getCastSourceIdWithAlternateMana());
this.castSourceIdManaCosts.putAll(player.getCastSourceIdManaCosts()); for (Entry<UUID, ManaCosts<ManaCost>> entry : player.getCastSourceIdManaCosts().entrySet()) {
this.castSourceIdCosts.putAll(player.getCastSourceIdCosts()); this.castSourceIdManaCosts.put(entry.getKey(), entry.getValue().copy());
}
for (Entry<UUID, Costs<Cost>> entry : player.getCastSourceIdCosts().entrySet()) {
this.castSourceIdCosts.put(entry.getKey(), entry.getValue().copy());
}
this.phyrexianColors = player.getPhyrexianColors().copy(); this.phyrexianColors = player.getPhyrexianColors().copy();
this.designations.clear(); this.designations.clear();