mirror of
https://github.com/correl/mage.git
synced 2024-11-25 03:00:11 +00:00
Eon Frolicker - fixed rollback error on play (#6780);
This commit is contained in:
parent
55f2893fc4
commit
ecaa5a5b42
6 changed files with 91 additions and 29 deletions
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 can’t 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);
|
||||||
|
//
|
||||||
|
// Chandra’s Fury deals 4 damage to target player or planeswalker and 1 damage to each creature that player or that planeswalker’s 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue