forked from External/mage
* Until end of your turn - fixed that effects discarded too early in multiplayer games (#5759, #5676);
Tests: added dozen tests for end of turn effects and related cards.
This commit is contained in:
parent
4288e45c23
commit
534037e095
22 changed files with 758 additions and 137 deletions
|
|
@ -130,7 +130,7 @@ class GideonBattleForgedAttacksIfAbleTargetEffect extends RequirementEffect {
|
||||||
if (targetPermanent == null) {
|
if (targetPermanent == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return game.getPhase().getType() == TurnPhase.END && game.getTurnNum() > getNextStartingControllerTurnNum();
|
return game.getPhase().getType() == TurnPhase.END && this.isYourNextTurn(game); // discard on end of their next turn
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -114,20 +114,21 @@ class GideonJuraEffect extends RequirementEffect {
|
||||||
public void init(Ability source, Game game) {
|
public void init(Ability source, Game game) {
|
||||||
super.init(source, game);
|
super.init(source, game);
|
||||||
creatingPermanent = new MageObjectReference(source.getSourceId(), game);
|
creatingPermanent = new MageObjectReference(source.getSourceId(), game);
|
||||||
|
setStartingControllerAndTurnNum(game, source.getFirstTarget(), game.getActivePlayerId()); // setup startingController to calc isYourTurn calls
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||||
return permanent.isControlledBy(source.getFirstTarget());
|
return permanent.isControlledBy(source.getFirstTarget()) && this.isYourNextTurn(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInactive(Ability source, Game game) {
|
public boolean isInactive(Ability source, Game game) {
|
||||||
return (getStartingTurnNum() != game.getTurnNum()
|
return (game.getPhase().getType() == TurnPhase.END && this.isYourNextTurn(game))
|
||||||
&& (game.getPhase().getType() == TurnPhase.END
|
// 6/15/2010: If a creature controlled by the affected player can't attack Gideon Jura
|
||||||
&& game.isActivePlayer(source.getFirstTarget())))
|
// (because he's no longer on the battlefield, for example), that player may have it attack you,
|
||||||
|| // 6/15/2010: If a creature controlled by the affected player can't attack Gideon Jura (because he's no longer on the battlefield, for example), that player may have it attack you, another one of your planeswalkers, or nothing at all.
|
// another one of your planeswalkers, or nothing at all.
|
||||||
creatingPermanent.getPermanent(game) == null;
|
|| creatingPermanent.getPermanent(game) == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,9 @@ public final class OracleEnVec extends CardImpl {
|
||||||
this.power = new MageInt(1);
|
this.power = new MageInt(1);
|
||||||
this.toughness = new MageInt(1);
|
this.toughness = new MageInt(1);
|
||||||
|
|
||||||
// {tap}: Target opponent chooses any number of creatures he or she controls. During that player's next turn, the chosen creatures attack if able, and other creatures can't attack. At the beginning of that turn's end step, destroy each of the chosen creatures that didn't attack. Activate this ability only during your turn.
|
// {T}: Target opponent chooses any number of creatures they control. During that player’s next turn, the chosen
|
||||||
|
// creatures attack if able, and other creatures can’t attack. At the beginning of that turn’s end step,
|
||||||
|
// destroy each of the chosen creatures that didn’t attack this turn. Activate this ability only during your turn.
|
||||||
Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new OracleEnVecEffect(), new TapSourceCost(), MyTurnCondition.instance);
|
Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new OracleEnVecEffect(), new TapSourceCost(), MyTurnCondition.instance);
|
||||||
ability.addTarget(new TargetOpponent());
|
ability.addTarget(new TargetOpponent());
|
||||||
this.addAbility(ability, new AttackedThisTurnWatcher());
|
this.addAbility(ability, new AttackedThisTurnWatcher());
|
||||||
|
|
@ -62,7 +64,9 @@ class OracleEnVecEffect extends OneShotEffect {
|
||||||
|
|
||||||
OracleEnVecEffect() {
|
OracleEnVecEffect() {
|
||||||
super(Outcome.Benefit);
|
super(Outcome.Benefit);
|
||||||
this.staticText = "Target opponent chooses any number of creatures he or she controls. During that player's next turn, the chosen creatures attack if able, and other creatures can't attack. At the beginning of that turn's end step, destroy each of the chosen creatures that didn't attack";
|
this.staticText = "Target opponent chooses any number of creatures he or she controls. During that player's next turn, " +
|
||||||
|
"the chosen creatures attack if able, and other creatures can't attack. At the beginning of that turn's end step, " +
|
||||||
|
"destroy each of the chosen creatures that didn't attack";
|
||||||
}
|
}
|
||||||
|
|
||||||
OracleEnVecEffect(final OracleEnVecEffect effect) {
|
OracleEnVecEffect(final OracleEnVecEffect effect) {
|
||||||
|
|
@ -102,7 +106,7 @@ class OracleEnVecEffect extends OneShotEffect {
|
||||||
class OracleEnVecMustAttackRequirementEffect extends RequirementEffect {
|
class OracleEnVecMustAttackRequirementEffect extends RequirementEffect {
|
||||||
|
|
||||||
OracleEnVecMustAttackRequirementEffect() {
|
OracleEnVecMustAttackRequirementEffect() {
|
||||||
super(Duration.Custom);
|
super(Duration.UntilEndOfYourNextTurn);
|
||||||
}
|
}
|
||||||
|
|
||||||
OracleEnVecMustAttackRequirementEffect(final OracleEnVecMustAttackRequirementEffect effect) {
|
OracleEnVecMustAttackRequirementEffect(final OracleEnVecMustAttackRequirementEffect effect) {
|
||||||
|
|
@ -117,7 +121,8 @@ class OracleEnVecMustAttackRequirementEffect extends RequirementEffect {
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||||
return this.getTargetPointer().getFirst(game, source) != null
|
return this.getTargetPointer().getFirst(game, source) != null
|
||||||
&& this.getTargetPointer().getFirst(game, source).equals(permanent.getId());
|
&& this.getTargetPointer().getFirst(game, source).equals(permanent.getId())
|
||||||
|
&& this.isYourNextTurn(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -130,11 +135,20 @@ class OracleEnVecMustAttackRequirementEffect extends RequirementEffect {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Ability source, Game game) {
|
||||||
|
super.init(source, game);
|
||||||
|
Permanent perm = game.getPermanent(this.getTargetPointer().getFirst(game, source));
|
||||||
|
if (perm != null) {
|
||||||
|
setStartingControllerAndTurnNum(game, perm.getControllerId(), game.getActivePlayerId()); // setup startingController to calc isYourTurn calls
|
||||||
|
} else {
|
||||||
|
discard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInactive(Ability source, Game game) {
|
public boolean isInactive(Ability source, Game game) {
|
||||||
return getStartingTurnNum() != game.getTurnNum()
|
return game.getPhase().getType() == TurnPhase.END && this.isYourNextTurn(game);
|
||||||
&& (game.getPhase().getType() == TurnPhase.END
|
|
||||||
&& game.isActivePlayer(this.getTargetPointer().getFirst(game, source)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -169,11 +183,20 @@ class OracleEnVecCantAttackRestrictionEffect extends RestrictionEffect {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Ability source, Game game) {
|
||||||
|
super.init(source, game);
|
||||||
|
Permanent perm = game.getPermanent(this.getTargetPointer().getFirst(game, source));
|
||||||
|
if (perm != null) {
|
||||||
|
setStartingControllerAndTurnNum(game, perm.getControllerId(), game.getActivePlayerId()); // setup startingController to calc isYourTurn calls
|
||||||
|
} else {
|
||||||
|
discard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInactive(Ability source, Game game) {
|
public boolean isInactive(Ability source, Game game) {
|
||||||
return getStartingTurnNum() != game.getTurnNum()
|
return game.getPhase().getType() == TurnPhase.END && this.isYourNextTurn(game);
|
||||||
&& (game.getPhase().getType() == TurnPhase.END
|
|
||||||
&& game.isActivePlayer(this.getTargetPointer().getFirst(game, source)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -71,13 +71,22 @@ class PeaceTalksEffect extends OneShotEffect {
|
||||||
|
|
||||||
class PeaceTalksCantAttackEffect extends RestrictionEffect {
|
class PeaceTalksCantAttackEffect extends RestrictionEffect {
|
||||||
|
|
||||||
|
int startedTurnNum = 0;
|
||||||
|
|
||||||
public PeaceTalksCantAttackEffect() {
|
public PeaceTalksCantAttackEffect() {
|
||||||
super(Duration.Custom);
|
super(Duration.Custom);
|
||||||
staticText = "Creatures can't attack this turn and next turn";
|
staticText = "Creatures can't attack this turn and next turn";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Ability source, Game game) {
|
||||||
|
super.init(source, game);
|
||||||
|
startedTurnNum = game.getTurnNum();
|
||||||
|
}
|
||||||
|
|
||||||
public PeaceTalksCantAttackEffect(final PeaceTalksCantAttackEffect effect) {
|
public PeaceTalksCantAttackEffect(final PeaceTalksCantAttackEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.startedTurnNum = effect.startedTurnNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -97,7 +106,7 @@ class PeaceTalksCantAttackEffect extends RestrictionEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInactive(Ability source, Game game) {
|
public boolean isInactive(Ability source, Game game) {
|
||||||
if (getStartingTurnNum() + 2 <= game.getTurnNum()) {
|
if (game.getTurnNum() > (startedTurnNum + 1)) {
|
||||||
this.discard();
|
this.discard();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -107,6 +116,8 @@ class PeaceTalksCantAttackEffect extends RestrictionEffect {
|
||||||
|
|
||||||
class PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities extends ContinuousRuleModifyingEffectImpl {
|
class PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities extends ContinuousRuleModifyingEffectImpl {
|
||||||
|
|
||||||
|
int startedTurnNum = 0;
|
||||||
|
|
||||||
public PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities() {
|
public PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities() {
|
||||||
super(Duration.Custom, Outcome.Neutral);
|
super(Duration.Custom, Outcome.Neutral);
|
||||||
staticText = "players and permanents can't be the targets of spells or activated abilities";
|
staticText = "players and permanents can't be the targets of spells or activated abilities";
|
||||||
|
|
@ -114,6 +125,13 @@ class PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities ex
|
||||||
|
|
||||||
public PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities(final PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities effect) {
|
public PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities(final PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.startedTurnNum = effect.startedTurnNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Ability source, Game game) {
|
||||||
|
super.init(source, game);
|
||||||
|
startedTurnNum = game.getTurnNum();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -149,7 +167,7 @@ class PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities ex
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInactive(Ability source, Game game) {
|
public boolean isInactive(Ability source, Game game) {
|
||||||
if (getStartingTurnNum() + 2 <= game.getTurnNum()) {
|
if (game.getTurnNum() > (startedTurnNum + 1)) {
|
||||||
this.discard();
|
this.discard();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,20 +92,21 @@ class RowanKenrithAttackEffect extends RequirementEffect {
|
||||||
public void init(Ability source, Game game) {
|
public void init(Ability source, Game game) {
|
||||||
super.init(source, game);
|
super.init(source, game);
|
||||||
creatingPermanent = new MageObjectReference(source.getSourceId(), game);
|
creatingPermanent = new MageObjectReference(source.getSourceId(), game);
|
||||||
|
setStartingControllerAndTurnNum(game, source.getFirstTarget(), game.getActivePlayerId()); // setup startingController to calc isYourTurn calls
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||||
return permanent.isControlledBy(source.getFirstTarget());
|
return permanent.isControlledBy(source.getFirstTarget()) && this.isYourNextTurn(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInactive(Ability source, Game game) {
|
public boolean isInactive(Ability source, Game game) {
|
||||||
return (getStartingTurnNum() != game.getTurnNum()
|
return (game.getPhase().getType() == TurnPhase.END && this.isYourNextTurn(game))
|
||||||
&& (game.getPhase().getType() == TurnPhase.END
|
// 6/15/2010: If a creature controlled by the affected player can't attack Gideon Jura
|
||||||
&& game.isActivePlayer(source.getFirstTarget())))
|
// (because he's no longer on the battlefield, for example), that player may have it attack you,
|
||||||
|| // 6/15/2010: If a creature controlled by the affected player can't attack Gideon Jura (because he's no longer on the battlefield, for example), that player may have it attack you, another one of your planeswalkers, or nothing at all.
|
// another one of your planeswalkers, or nothing at all.
|
||||||
creatingPermanent.getPermanent(game) == null;
|
|| creatingPermanent.getPermanent(game) == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -59,9 +59,7 @@ class TauntEffect extends RequirementEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInactive(Ability source, Game game) {
|
public boolean isInactive(Ability source, Game game) {
|
||||||
return getStartingTurnNum() != game.getTurnNum() &&
|
return game.getPhase().getType() == TurnPhase.END && this.isYourNextTurn(game);
|
||||||
(game.getPhase().getType() == TurnPhase.END &&
|
|
||||||
game.isActivePlayer(this.getTargetPointer().getFirst(game, source)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -94,10 +94,7 @@ class VraskaTheUnseenGainAbilityEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInactive(Ability source, Game game) {
|
public boolean isInactive(Ability source, Game game) {
|
||||||
if (getStartingTurnNum() != 0 && game.getTurnNum() != getStartingTurnNum()) {
|
return game.getPhase().getType() == TurnPhase.END && this.isYourNextTurn(game);
|
||||||
return game.isActivePlayer(source.getControllerId());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,6 @@ public final class WallOfDust extends CardImpl {
|
||||||
|
|
||||||
class WallOfDustRestrictionEffect extends RestrictionEffect {
|
class WallOfDustRestrictionEffect extends RestrictionEffect {
|
||||||
|
|
||||||
int nextTurnTargetController = 0;
|
|
||||||
protected MageObjectReference targetPermanentReference;
|
protected MageObjectReference targetPermanentReference;
|
||||||
|
|
||||||
public WallOfDustRestrictionEffect() {
|
public WallOfDustRestrictionEffect() {
|
||||||
|
|
@ -57,7 +56,6 @@ class WallOfDustRestrictionEffect extends RestrictionEffect {
|
||||||
|
|
||||||
public WallOfDustRestrictionEffect(final WallOfDustRestrictionEffect effect) {
|
public WallOfDustRestrictionEffect(final WallOfDustRestrictionEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
this.nextTurnTargetController = effect.nextTurnTargetController;
|
|
||||||
this.targetPermanentReference = effect.targetPermanentReference;
|
this.targetPermanentReference = effect.targetPermanentReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,26 +66,22 @@ class WallOfDustRestrictionEffect extends RestrictionEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInactive(Ability source, Game game) {
|
public boolean isInactive(Ability source, Game game) {
|
||||||
if (targetPermanentReference == null) {
|
if (targetPermanentReference == null || targetPermanentReference.getPermanent(game) == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Permanent targetPermanent = targetPermanentReference.getPermanent(game);
|
|
||||||
if (targetPermanent == null) {
|
return game.getPhase().getType() == TurnPhase.END && this.isYourNextTurn(game);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (nextTurnTargetController == 0 && getStartingTurnNum() != game.getTurnNum() && game.isActivePlayer(targetPermanent.getControllerId())) {
|
|
||||||
nextTurnTargetController = game.getTurnNum();
|
|
||||||
}
|
|
||||||
return game.getPhase().getType() == TurnPhase.END && nextTurnTargetController > 0 && game.getTurnNum() > nextTurnTargetController;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Ability source, Game game) {
|
public void init(Ability source, Game game) {
|
||||||
super.init(source, game);
|
super.init(source, game);
|
||||||
if (getTargetPointer().getFirst(game, source) == null) {
|
Permanent perm = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||||
discard();
|
if (perm != null) {
|
||||||
|
targetPermanentReference = new MageObjectReference(perm, game);
|
||||||
|
setStartingControllerAndTurnNum(game, perm.getControllerId(), game.getActivePlayerId());
|
||||||
} else {
|
} else {
|
||||||
targetPermanentReference = new MageObjectReference(getTargetPointer().getFirst(game, source), game);
|
discard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
package org.mage.test.cards.continuous;
|
||||||
|
|
||||||
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
import mage.abilities.effects.common.continuous.BoostAllEffect;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestMultiPlayerBaseWithRangeAll;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public class EndOfTurnMultiOpponentsTest extends CardTestMultiPlayerBaseWithRangeAll {
|
||||||
|
|
||||||
|
String cardBear2 = EndOfTurnOneOpponentTest.cardBear2;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_EndOfTurnMulti() {
|
||||||
|
// Player order: A -> D -> C -> B
|
||||||
|
addCustomCardWithAbility("boost1", playerA, new SimpleStaticAbility(Zone.ALL, new BoostAllEffect(1, 1, Duration.EndOfTurn)));
|
||||||
|
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.EndOfTurn effect", 1, playerA, true, PhaseStep.END_TURN);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.EndOfTurn effect", 2, playerD, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.EndOfTurn effect", 3, playerC, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.EndOfTurn effect", 4, playerB, true, null);
|
||||||
|
//
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.EndOfTurn effect", 5, playerA, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.EndOfTurn effect", 6, playerD, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.EndOfTurn effect", 7, playerC, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.EndOfTurn effect", 8, playerB, true, null);
|
||||||
|
//
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.EndOfTurn effect", 9, playerA, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.EndOfTurn effect", 10, playerD, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.EndOfTurn effect", 11, playerC, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.EndOfTurn effect", 12, playerB, true, null);
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, cardBear2, 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, cardBear2, 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerC, cardBear2, 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerD, cardBear2, 1);
|
||||||
|
|
||||||
|
attack(1, playerA, cardBear2);
|
||||||
|
attack(2, playerD, cardBear2);
|
||||||
|
attack(3, playerC, cardBear2);
|
||||||
|
attack(4, playerB, cardBear2);
|
||||||
|
//
|
||||||
|
attack(5, playerA, cardBear2);
|
||||||
|
attack(6, playerD, cardBear2);
|
||||||
|
attack(7, playerC, cardBear2);
|
||||||
|
attack(8, playerB, cardBear2);
|
||||||
|
//
|
||||||
|
attack(9, playerA, cardBear2);
|
||||||
|
attack(10, playerD, cardBear2);
|
||||||
|
attack(11, playerC, cardBear2);
|
||||||
|
attack(12, playerB, cardBear2);
|
||||||
|
|
||||||
|
setStopAt(12, PhaseStep.CLEANUP);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_UntilYourNextTurnMulti() {
|
||||||
|
// Player order: A -> D -> C -> B
|
||||||
|
addCustomCardWithAbility("boost1", playerA, new SimpleStaticAbility(Zone.ALL, new BoostAllEffect(1, 1, Duration.UntilYourNextTurn)));
|
||||||
|
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 1, playerA, true, PhaseStep.END_TURN);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 2, playerD, true, PhaseStep.END_TURN);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 3, playerC, true, PhaseStep.END_TURN);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 4, playerB, true, PhaseStep.END_TURN);
|
||||||
|
//
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 5, playerA, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 6, playerD, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 7, playerC, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 8, playerB, true, null);
|
||||||
|
//
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 9, playerA, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 10, playerD, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 11, playerC, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 12, playerB, true, null);
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, cardBear2, 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, cardBear2, 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerC, cardBear2, 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerD, cardBear2, 1);
|
||||||
|
|
||||||
|
attack(1, playerA, cardBear2);
|
||||||
|
attack(2, playerD, cardBear2);
|
||||||
|
attack(3, playerC, cardBear2);
|
||||||
|
attack(4, playerB, cardBear2);
|
||||||
|
//
|
||||||
|
attack(5, playerA, cardBear2);
|
||||||
|
attack(6, playerD, cardBear2);
|
||||||
|
attack(7, playerC, cardBear2);
|
||||||
|
attack(8, playerB, cardBear2);
|
||||||
|
//
|
||||||
|
attack(9, playerA, cardBear2);
|
||||||
|
attack(10, playerD, cardBear2);
|
||||||
|
attack(11, playerC, cardBear2);
|
||||||
|
attack(12, playerB, cardBear2);
|
||||||
|
|
||||||
|
setStopAt(12, PhaseStep.CLEANUP);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_UntilEndOfYourNextTurnMulti() {
|
||||||
|
// Player order: A -> D -> C -> B
|
||||||
|
addCustomCardWithAbility("boost1", playerA, new SimpleStaticAbility(Zone.ALL, new BoostAllEffect(1, 1, Duration.UntilEndOfYourNextTurn)));
|
||||||
|
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilEndOfYourNextTurn effect", 1, playerA, true, PhaseStep.END_TURN);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilEndOfYourNextTurn effect", 2, playerD, true, PhaseStep.END_TURN);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilEndOfYourNextTurn effect", 3, playerC, true, PhaseStep.END_TURN);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilEndOfYourNextTurn effect", 4, playerB, true, PhaseStep.END_TURN);
|
||||||
|
//
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilEndOfYourNextTurn effect", 5, playerA, true, PhaseStep.END_TURN);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilEndOfYourNextTurn effect", 6, playerD, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilEndOfYourNextTurn effect", 7, playerC, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilEndOfYourNextTurn effect", 8, playerB, true, null);
|
||||||
|
//
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilEndOfYourNextTurn effect", 9, playerA, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilEndOfYourNextTurn effect", 10, playerD, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilEndOfYourNextTurn effect", 11, playerC, true, null);
|
||||||
|
EndOfTurnOneOpponentTest.prepareStepChecks(this, "Duration.UntilEndOfYourNextTurn effect", 12, playerB, true, null);
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, cardBear2, 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, cardBear2, 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerC, cardBear2, 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerD, cardBear2, 1);
|
||||||
|
|
||||||
|
attack(1, playerA, cardBear2);
|
||||||
|
attack(2, playerD, cardBear2);
|
||||||
|
attack(3, playerC, cardBear2);
|
||||||
|
attack(4, playerB, cardBear2);
|
||||||
|
//
|
||||||
|
attack(5, playerA, cardBear2);
|
||||||
|
attack(6, playerD, cardBear2);
|
||||||
|
attack(7, playerC, cardBear2);
|
||||||
|
attack(8, playerB, cardBear2);
|
||||||
|
//
|
||||||
|
attack(9, playerA, cardBear2);
|
||||||
|
attack(10, playerD, cardBear2);
|
||||||
|
attack(11, playerC, cardBear2);
|
||||||
|
attack(12, playerB, cardBear2);
|
||||||
|
|
||||||
|
setStopAt(12, PhaseStep.CLEANUP);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
package org.mage.test.cards.continuous;
|
||||||
|
|
||||||
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
import mage.abilities.effects.common.continuous.BoostAllEffect;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.player.TestPlayer;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
import org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public class EndOfTurnOneOpponentTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
public static String cardBear2 = "Balduvian Bears"; // 2/2
|
||||||
|
|
||||||
|
public static void prepareStepChecks(CardTestPlayerAPIImpl testEngine, String testName, int turnNum, TestPlayer player, boolean willBeBattle, PhaseStep mustExistUntilStep) {
|
||||||
|
for (PhaseStep step : PhaseStep.values()) {
|
||||||
|
// skip auto-steps without priority/checks
|
||||||
|
switch (step) {
|
||||||
|
case UNTAP:
|
||||||
|
case DRAW:
|
||||||
|
case UPKEEP:
|
||||||
|
case FIRST_COMBAT_DAMAGE:
|
||||||
|
case CLEANUP:
|
||||||
|
continue; // auto-skip steps without priority
|
||||||
|
case PRECOMBAT_MAIN:
|
||||||
|
case POSTCOMBAT_MAIN:
|
||||||
|
case END_TURN:
|
||||||
|
break; // always use
|
||||||
|
case BEGIN_COMBAT:
|
||||||
|
case DECLARE_ATTACKERS:
|
||||||
|
case DECLARE_BLOCKERS:
|
||||||
|
case COMBAT_DAMAGE:
|
||||||
|
case END_COMBAT:
|
||||||
|
if (!willBeBattle) continue; // combat skip
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unknown phase step " + step);
|
||||||
|
}
|
||||||
|
|
||||||
|
int permP = 2;
|
||||||
|
int permT = 2;
|
||||||
|
String existsStr = "must NOT EXISTS";
|
||||||
|
if (mustExistUntilStep != null && step.getIndex() <= mustExistUntilStep.getIndex()) {
|
||||||
|
permP++;
|
||||||
|
permT++;
|
||||||
|
existsStr = "must EXISTS";
|
||||||
|
}
|
||||||
|
|
||||||
|
testEngine.checkPT(testName + " " + existsStr + " on turn " + turnNum + " - " + step.toString() + " for " + player.getName(),
|
||||||
|
turnNum, step, player, cardBear2, permP, permT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_EndOfTurnSingle() {
|
||||||
|
addCustomCardWithAbility("boost1", playerA, new SimpleStaticAbility(Zone.ALL, new BoostAllEffect(1, 1, Duration.EndOfTurn)));
|
||||||
|
prepareStepChecks(this, "Duration.EndOfTurn effect", 1, playerA, true, PhaseStep.END_TURN);
|
||||||
|
prepareStepChecks(this, "Duration.EndOfTurn effect", 2, playerA, true, null);
|
||||||
|
prepareStepChecks(this, "Duration.EndOfTurn effect", 3, playerA, true, null);
|
||||||
|
prepareStepChecks(this, "Duration.EndOfTurn effect", 4, playerA, true, null);
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, cardBear2, 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, cardBear2, 1);
|
||||||
|
|
||||||
|
attack(1, playerA, cardBear2);
|
||||||
|
attack(2, playerB, cardBear2);
|
||||||
|
attack(3, playerA, cardBear2);
|
||||||
|
attack(4, playerB, cardBear2);
|
||||||
|
|
||||||
|
setStopAt(4, PhaseStep.CLEANUP);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_UntilYourNextTurnSingle() {
|
||||||
|
addCustomCardWithAbility("boost1", playerA, new SimpleStaticAbility(Zone.ALL, new BoostAllEffect(1, 1, Duration.UntilYourNextTurn)));
|
||||||
|
prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 1, playerA, true, PhaseStep.END_TURN);
|
||||||
|
prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 2, playerA, true, PhaseStep.END_TURN);
|
||||||
|
prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 3, playerA, true, null);
|
||||||
|
prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 4, playerA, true, null);
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, cardBear2, 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, cardBear2, 1);
|
||||||
|
|
||||||
|
attack(1, playerA, cardBear2);
|
||||||
|
attack(2, playerB, cardBear2);
|
||||||
|
attack(3, playerA, cardBear2);
|
||||||
|
attack(4, playerB, cardBear2);
|
||||||
|
|
||||||
|
setStopAt(4, PhaseStep.CLEANUP);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_UntilEndOfYourNextTurnSingle() {
|
||||||
|
addCustomCardWithAbility("boost1", playerA, new SimpleStaticAbility(Zone.ALL, new BoostAllEffect(1, 1, Duration.UntilEndOfYourNextTurn)));
|
||||||
|
prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 1, playerA, true, PhaseStep.END_TURN);
|
||||||
|
prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 2, playerA, true, PhaseStep.END_TURN);
|
||||||
|
prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 3, playerA, true, PhaseStep.END_TURN);
|
||||||
|
prepareStepChecks(this, "Duration.UntilYourNextTurn effect", 4, playerA, true, null);
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, cardBear2, 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, cardBear2, 1);
|
||||||
|
|
||||||
|
attack(1, playerA, cardBear2);
|
||||||
|
attack(2, playerB, cardBear2);
|
||||||
|
attack(3, playerA, cardBear2);
|
||||||
|
attack(4, playerB, cardBear2);
|
||||||
|
|
||||||
|
setStopAt(4, PhaseStep.CLEANUP);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
package org.mage.test.cards.continuous;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.counters.CounterType;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public class GideonJuraAndRowanKenrithNextTurnTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_SingleOpponentMustAttackGideonJura() {
|
||||||
|
// +2: During target opponent's next turn, creatures that player controls attack Gideon Jura if able.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Gideon Jura");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1); // 2/2
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+2:", playerB);
|
||||||
|
|
||||||
|
checkPermanentCounters("turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Gideon Jura", CounterType.LOYALTY, 6 + 2);
|
||||||
|
checkPermanentCounters("turn 2", 2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Gideon Jura", CounterType.LOYALTY, 6 + 2 - 2);
|
||||||
|
checkPermanentCounters("turn 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Gideon Jura", CounterType.LOYALTY, 6 + 2 - 2);
|
||||||
|
checkPermanentCounters("turn 4", 4, PhaseStep.POSTCOMBAT_MAIN, playerA, "Gideon Jura", CounterType.LOYALTY, 6 + 2 - 2);
|
||||||
|
|
||||||
|
setStopAt(4, PhaseStep.END_TURN);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_SingleOpponentMustAttackRowanKenrith() {
|
||||||
|
// +2: During target player's next turn, each creature that player controls attacks if able.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Rowan Kenrith");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1); // 2/2
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+2:", playerB);
|
||||||
|
addTarget(playerB, playerA);
|
||||||
|
|
||||||
|
checkLife("turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, 20);
|
||||||
|
checkLife("turn 2", 2, PhaseStep.POSTCOMBAT_MAIN, playerA, 20 - 2);
|
||||||
|
checkLife("turn 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, 20 - 2);
|
||||||
|
checkLife("turn 4", 4, PhaseStep.POSTCOMBAT_MAIN, playerA, 20 - 2);
|
||||||
|
|
||||||
|
setStopAt(4, PhaseStep.END_TURN);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
package org.mage.test.cards.continuous;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public class OracleEnVecNextTurnTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_SingleOpponentMustAttack() {
|
||||||
|
// {T}: Target opponent chooses any number of creatures they control. During that player’s next turn, the chosen
|
||||||
|
// creatures attack if able, and other creatures can’t attack. At the beginning of that turn’s end step,
|
||||||
|
// destroy each of the chosen creatures that didn’t attack this turn. Activate this ability only during your turn.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Oracle en-Vec");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1); // 2/2
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Angelic Wall", 1); // wall, can't attack
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Ashcoat Bear", 1); // 2/2
|
||||||
|
|
||||||
|
// 1 - activate
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Target opponent", playerB);
|
||||||
|
setChoice(playerB, "Balduvian Bears^Angelic Wall");
|
||||||
|
//
|
||||||
|
checkLife("turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, 20);
|
||||||
|
checkPermanentCount("turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 1);
|
||||||
|
checkPermanentCount("turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Angelic Wall", 1);
|
||||||
|
checkPermanentCount("turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ashcoat Bear", 1);
|
||||||
|
|
||||||
|
// 2 - attack and destroy at the end
|
||||||
|
checkLife("turn 2", 2, PhaseStep.POSTCOMBAT_MAIN, playerA, 20 - 2);
|
||||||
|
checkPermanentCount("turn 2a", 2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 1);
|
||||||
|
checkPermanentCount("turn 2a", 2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Angelic Wall", 1);
|
||||||
|
checkPermanentCount("turn 2a", 2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ashcoat Bear", 1);
|
||||||
|
|
||||||
|
// 3 - nothing
|
||||||
|
// after destroy at the end
|
||||||
|
checkLife("turn 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, 20 - 2);
|
||||||
|
checkPermanentCount("turn 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 1);
|
||||||
|
checkPermanentCount("turn 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerB, "Angelic Wall", 0);
|
||||||
|
checkPermanentCount("turn 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ashcoat Bear", 1);
|
||||||
|
|
||||||
|
// 4 - nothing
|
||||||
|
checkLife("turn 4", 4, PhaseStep.POSTCOMBAT_MAIN, playerA, 20 - 2);
|
||||||
|
checkPermanentCount("turn 4", 4, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 1);
|
||||||
|
checkPermanentCount("turn 4", 4, PhaseStep.POSTCOMBAT_MAIN, playerB, "Angelic Wall", 0);
|
||||||
|
checkPermanentCount("turn 4", 4, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ashcoat Bear", 1);
|
||||||
|
|
||||||
|
setStopAt(4, PhaseStep.END_TURN);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
package org.mage.test.cards.continuous;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public class ShinenOfLifesRoarTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_SingleOpponentMustBlock() {
|
||||||
|
// All creatures able to block Shinen of Life’s Roar do so.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Shinen of Life's Roar");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1); // 2/2
|
||||||
|
|
||||||
|
attack(1, playerA, "Shinen of Life's Roar", playerB);
|
||||||
|
|
||||||
|
setStopAt(2, PhaseStep.END_TURN);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertGraveyardCount(playerA, "Shinen of Life's Roar", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
package org.mage.test.cards.continuous;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.counters.CounterType;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public class VraskaTheUnseenNextTurnTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_SingleOpponentMustAttack() {
|
||||||
|
// +1: Until your next turn, whenever a creature deals combat damage to Vraska the Unseen, destroy that creature.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Vraska the Unseen");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 3); // 2/2
|
||||||
|
|
||||||
|
// 1 - activate
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1:");
|
||||||
|
checkPermanentCounters("turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Vraska the Unseen", CounterType.LOYALTY, 5 + 1);
|
||||||
|
checkPermanentCount("turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 3);
|
||||||
|
|
||||||
|
// 2 - attack and destroy
|
||||||
|
attack(2, playerB, "Balduvian Bears", "Vraska the Unseen");
|
||||||
|
checkPermanentCounters("turn 2", 2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Vraska the Unseen", CounterType.LOYALTY, 5 + 1 - 2);
|
||||||
|
checkPermanentCount("turn 2", 2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 3 - 1);
|
||||||
|
|
||||||
|
// 3 - nothing
|
||||||
|
checkPermanentCounters("turn 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Vraska the Unseen", CounterType.LOYALTY, 5 + 1 - 2);
|
||||||
|
checkPermanentCount("turn 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 3 - 1);
|
||||||
|
|
||||||
|
// 4 - attack and DO NOT destroy
|
||||||
|
checkPermanentCounters("turn 4", 4, PhaseStep.POSTCOMBAT_MAIN, playerA, "Vraska the Unseen", CounterType.LOYALTY, 5 + 1 - 2 * 2);
|
||||||
|
attack(4, playerB, "Balduvian Bears", "Vraska the Unseen");
|
||||||
|
checkPermanentCount("turn 4", 4, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 3 - 1);
|
||||||
|
|
||||||
|
setStopAt(4, PhaseStep.END_TURN);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,66 @@
|
||||||
|
package org.mage.test.cards.continuous;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
import mage.abilities.effects.common.combat.AttacksIfAbleAllEffect;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.filter.StaticFilters;
|
||||||
|
import mage.watchers.common.AttackedThisTurnWatcher;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public class WallOfDustNextTurnTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_SingleOpponentMustAttack() {
|
||||||
|
// Whenever Wall of Dust blocks a creature, that creature can't attack during its controller's next turn.
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Wall of Dust");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears", 1); // 2/2
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Ashcoat Bear", 1); // 2/2
|
||||||
|
//
|
||||||
|
Ability ability = new SimpleStaticAbility(new AttacksIfAbleAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, Duration.EndOfGame));
|
||||||
|
ability.addWatcher(new AttackedThisTurnWatcher());
|
||||||
|
addCustomCardWithAbility("all attacks", playerA, ability);
|
||||||
|
|
||||||
|
// 1 - nothing
|
||||||
|
checkPermanentCount("turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 1);
|
||||||
|
checkPermanentCount("turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ashcoat Bear", 1);
|
||||||
|
checkLife("turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, 20);
|
||||||
|
|
||||||
|
// 2 - auto-attack B -> A, 1 attacked, 1 blocked (by wall)
|
||||||
|
block(2, playerA, "Wall of Dust", "Balduvian Bears");
|
||||||
|
checkPermanentCount("turn 2", 2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 1);
|
||||||
|
checkPermanentCount("turn 2", 2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ashcoat Bear", 1);
|
||||||
|
checkLife("turn 2", 2, PhaseStep.POSTCOMBAT_MAIN, playerA, 20 - 2);
|
||||||
|
|
||||||
|
// 3 - nothing
|
||||||
|
checkPermanentCount("turn 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 1);
|
||||||
|
checkPermanentCount("turn 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ashcoat Bear", 1);
|
||||||
|
checkLife("turn 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, 20 - 2);
|
||||||
|
|
||||||
|
// 4 - auto-attack, B -> A, 1 attacked, 1 can't attacked (by wall's abilitiy during next turn)
|
||||||
|
checkPermanentCount("turn 4", 4, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 1);
|
||||||
|
checkPermanentCount("turn 4", 4, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ashcoat Bear", 1);
|
||||||
|
checkLife("turn 4", 4, PhaseStep.POSTCOMBAT_MAIN, playerA, 20 - 2 * 2);
|
||||||
|
|
||||||
|
// 5 - nothing
|
||||||
|
checkPermanentCount("turn 5", 5, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 1);
|
||||||
|
checkPermanentCount("turn 5", 5, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ashcoat Bear", 1);
|
||||||
|
checkLife("turn 5", 5, PhaseStep.POSTCOMBAT_MAIN, playerA, 20 - 2 * 2);
|
||||||
|
|
||||||
|
// 6 - auto-attack, B -> A, 2 attacked
|
||||||
|
checkPermanentCount("turn 6", 6, PhaseStep.POSTCOMBAT_MAIN, playerB, "Balduvian Bears", 1);
|
||||||
|
checkPermanentCount("turn 6", 6, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ashcoat Bear", 1);
|
||||||
|
checkLife("turn 6", 6, PhaseStep.POSTCOMBAT_MAIN, playerA, 20 - 2 * 2 - 2 * 2);
|
||||||
|
|
||||||
|
setStopAt(6, PhaseStep.END_TURN);
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
|
|
||||||
|
|
||||||
package mage.abilities;
|
package mage.abilities;
|
||||||
|
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
|
|
@ -48,8 +46,8 @@ public class DelayedTriggeredAbilities extends AbilitiesImpl<DelayedTriggeredAbi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeEndOfTurnAbilities() {
|
public void removeEndOfTurnAbilities(Game game) {
|
||||||
this.removeIf(ability -> ability.getDuration() == Duration.EndOfTurn);
|
this.removeIf(ability -> ability.getDuration() == Duration.EndOfTurn); // TODO: add Duration.EndOfYourTurn like effects
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeEndOfCombatAbilities() {
|
public void removeEndOfCombatAbilities() {
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ public interface ContinuousEffect extends Effect {
|
||||||
|
|
||||||
void init(Ability source, Game game);
|
void init(Ability source, Game game);
|
||||||
|
|
||||||
|
void init(Ability source, Game game, UUID activePlayerId);
|
||||||
|
|
||||||
Layer getLayer();
|
Layer getLayer();
|
||||||
|
|
||||||
SubLayer getSublayer();
|
SubLayer getSublayer();
|
||||||
|
|
@ -58,14 +60,14 @@ public interface ContinuousEffect extends Effect {
|
||||||
|
|
||||||
void addDependedToType(DependencyType dependencyType);
|
void addDependedToType(DependencyType dependencyType);
|
||||||
|
|
||||||
void setStartingTurnNum(Game game, UUID startingController);
|
void setStartingControllerAndTurnNum(Game game, UUID startingController, UUID activePlayerId);
|
||||||
|
|
||||||
int getStartingTurnNum();
|
|
||||||
|
|
||||||
int getNextStartingControllerTurnNum();
|
|
||||||
|
|
||||||
UUID getStartingController();
|
UUID getStartingController();
|
||||||
|
|
||||||
|
void incYourTurnNumPlayed();
|
||||||
|
|
||||||
|
boolean isYourNextTurn(Game game);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void newId();
|
void newId();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import mage.players.Player;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com, JayDi85
|
||||||
*/
|
*/
|
||||||
public abstract class ContinuousEffectImpl extends EffectImpl implements ContinuousEffect {
|
public abstract class ContinuousEffectImpl extends EffectImpl implements ContinuousEffect {
|
||||||
|
|
||||||
|
|
@ -38,10 +38,10 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
||||||
*/
|
*/
|
||||||
protected boolean characterDefining = false;
|
protected boolean characterDefining = false;
|
||||||
|
|
||||||
// until your next turn
|
// until your next turn or until end of your next turn
|
||||||
private int startingTurnNum;
|
private UUID startingControllerId; // player to checkss turns (can't different with real controller ability)
|
||||||
private int yourNextTurnNum;
|
private boolean startingTurnWasActive;
|
||||||
private UUID startingControllerId;
|
private int yourTurnNumPlayed = 0; // turnes played after effect was created
|
||||||
|
|
||||||
public ContinuousEffectImpl(Duration duration, Outcome outcome) {
|
public ContinuousEffectImpl(Duration duration, Outcome outcome) {
|
||||||
super(outcome);
|
super(outcome);
|
||||||
|
|
@ -69,9 +69,9 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
||||||
this.affectedObjectsSet = effect.affectedObjectsSet;
|
this.affectedObjectsSet = effect.affectedObjectsSet;
|
||||||
this.affectedObjectList.addAll(effect.affectedObjectList);
|
this.affectedObjectList.addAll(effect.affectedObjectList);
|
||||||
this.temporary = effect.temporary;
|
this.temporary = effect.temporary;
|
||||||
this.startingTurnNum = effect.startingTurnNum;
|
|
||||||
this.yourNextTurnNum = effect.yourNextTurnNum;
|
|
||||||
this.startingControllerId = effect.startingControllerId;
|
this.startingControllerId = effect.startingControllerId;
|
||||||
|
this.startingTurnWasActive = effect.startingTurnWasActive;
|
||||||
|
this.yourTurnNumPlayed = effect.yourTurnNumPlayed;
|
||||||
this.dependencyTypes = effect.dependencyTypes;
|
this.dependencyTypes = effect.dependencyTypes;
|
||||||
this.dependendToTypes = effect.dependendToTypes;
|
this.dependendToTypes = effect.dependendToTypes;
|
||||||
this.characterDefining = effect.characterDefining;
|
this.characterDefining = effect.characterDefining;
|
||||||
|
|
@ -139,6 +139,11 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Ability source, Game game) {
|
public void init(Ability source, Game game) {
|
||||||
|
init(source, game, game.getActivePlayerId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Ability source, Game game, UUID activePlayerId) {
|
||||||
targetPointer.init(game, source);
|
targetPointer.init(game, source);
|
||||||
//20100716 - 611.2c
|
//20100716 - 611.2c
|
||||||
if (AbilityType.ACTIVATED == source.getAbilityType()
|
if (AbilityType.ACTIVATED == source.getAbilityType()
|
||||||
|
|
@ -161,52 +166,77 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
||||||
this.affectedObjectsSet = true;
|
this.affectedObjectsSet = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setStartingTurnNum(game, source.getControllerId());
|
setStartingControllerAndTurnNum(game, source.getControllerId(), activePlayerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStartingTurnNum(Game game, UUID startingController) {
|
|
||||||
this.startingControllerId = startingController;
|
|
||||||
this.startingTurnNum = game.getTurnNum();
|
|
||||||
this.yourNextTurnNum = game.isActivePlayer(startingControllerId) ? startingTurnNum + 2 : startingTurnNum + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getStartingTurnNum() {
|
|
||||||
return this.startingTurnNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNextStartingControllerTurnNum() {
|
|
||||||
return this.yourNextTurnNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getStartingController() {
|
public UUID getStartingController() {
|
||||||
return this.startingControllerId;
|
return startingControllerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setStartingControllerAndTurnNum(Game game, UUID startingController, UUID activePlayerId) {
|
||||||
|
this.startingControllerId = startingController;
|
||||||
|
this.startingTurnWasActive = activePlayerId != null && activePlayerId.equals(startingController); // you can't use "game" for active player cause it's called from tests/cheat too
|
||||||
|
this.yourTurnNumPlayed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void incYourTurnNumPlayed() {
|
||||||
|
yourTurnNumPlayed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isYourNextTurn(Game game) {
|
||||||
|
if (this.startingTurnWasActive) {
|
||||||
|
return yourTurnNumPlayed == 1 && game.isActivePlayer(startingControllerId);
|
||||||
|
} else {
|
||||||
|
return yourTurnNumPlayed == 0 && game.isActivePlayer(startingControllerId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInactive(Ability source, Game game) {
|
public boolean isInactive(Ability source, Game game) {
|
||||||
if (duration == Duration.UntilYourNextTurn || duration == Duration.UntilEndOfYourNextTurn) {
|
// YOUR turn checks
|
||||||
Player player = game.getPlayer(startingControllerId);
|
// until end of turn - must be checked on cleanup step, see rules 514.2
|
||||||
if (player != null) {
|
// other must checked here (active and leave players), see rules 800.4
|
||||||
if (player.isInGame()) {
|
|
||||||
boolean canDelete = false;
|
|
||||||
switch (duration) {
|
switch (duration) {
|
||||||
case UntilYourNextTurn:
|
case UntilYourNextTurn:
|
||||||
canDelete = game.getTurnNum() >= yourNextTurnNum;
|
|
||||||
break;
|
|
||||||
case UntilEndOfYourNextTurn:
|
case UntilEndOfYourNextTurn:
|
||||||
canDelete = (game.getTurnNum() > yourNextTurnNum)
|
break;
|
||||||
|| (game.getTurnNum() == yourNextTurnNum && game.getStep().getType().isAfter(PhaseStep.END_TURN));
|
default:
|
||||||
}
|
|
||||||
return canDelete;
|
|
||||||
}
|
|
||||||
return player.hasReachedNextTurnAfterLeaving();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cheat engine put cards without play and calls direct applyEffects with clean -- need to ignore it
|
||||||
|
if (game.getActivePlayerId() == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canDelete = false;
|
||||||
|
Player player = game.getPlayer(startingControllerId);
|
||||||
|
|
||||||
|
// discard on start of turn for leave player
|
||||||
|
// 800.4i When a player leaves the game, any continuous effects with durations that last until that player's next turn
|
||||||
|
// or until a specific point in that turn will last until that turn would have begun.
|
||||||
|
// They neither expire immediately nor last indefinitely.
|
||||||
|
switch (duration) {
|
||||||
|
case UntilYourNextTurn:
|
||||||
|
case UntilEndOfYourNextTurn:
|
||||||
|
canDelete = player == null || (!player.isInGame() && player.hasReachedNextTurnAfterLeaving());
|
||||||
|
}
|
||||||
|
|
||||||
|
// discard on another conditions (start of your turn)
|
||||||
|
switch (duration) {
|
||||||
|
case UntilYourNextTurn:
|
||||||
|
if (player != null && player.isInGame()) {
|
||||||
|
canDelete = canDelete || this.isYourNextTurn(game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return canDelete;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Layer getLayer() {
|
public Layer getLayer() {
|
||||||
return layer;
|
return layer;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,5 @@
|
||||||
package mage.abilities.effects;
|
package mage.abilities.effects;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.MageObjectReference;
|
import mage.MageObjectReference;
|
||||||
import mage.abilities.*;
|
import mage.abilities.*;
|
||||||
|
|
@ -31,6 +27,11 @@ import mage.players.Player;
|
||||||
import mage.target.common.TargetCardInHand;
|
import mage.target.common.TargetCardInHand;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
*/
|
*/
|
||||||
|
|
@ -134,18 +135,18 @@ public class ContinuousEffects implements Serializable {
|
||||||
spliceCardEffects.removeEndOfCombatEffects();
|
spliceCardEffects.removeEndOfCombatEffects();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void removeEndOfTurnEffects() {
|
public synchronized void removeEndOfTurnEffects(Game game) {
|
||||||
layeredEffects.removeEndOfTurnEffects();
|
layeredEffects.removeEndOfTurnEffects(game);
|
||||||
continuousRuleModifyingEffects.removeEndOfTurnEffects();
|
continuousRuleModifyingEffects.removeEndOfTurnEffects(game);
|
||||||
replacementEffects.removeEndOfTurnEffects();
|
replacementEffects.removeEndOfTurnEffects(game);
|
||||||
preventionEffects.removeEndOfTurnEffects();
|
preventionEffects.removeEndOfTurnEffects(game);
|
||||||
requirementEffects.removeEndOfTurnEffects();
|
requirementEffects.removeEndOfTurnEffects(game);
|
||||||
restrictionEffects.removeEndOfTurnEffects();
|
restrictionEffects.removeEndOfTurnEffects(game);
|
||||||
for (ContinuousEffectsList asThoughtlist : asThoughEffectsMap.values()) {
|
for (ContinuousEffectsList asThoughtlist : asThoughEffectsMap.values()) {
|
||||||
asThoughtlist.removeEndOfTurnEffects();
|
asThoughtlist.removeEndOfTurnEffects(game);
|
||||||
}
|
}
|
||||||
costModificationEffects.removeEndOfTurnEffects();
|
costModificationEffects.removeEndOfTurnEffects(game);
|
||||||
spliceCardEffects.removeEndOfTurnEffects();
|
spliceCardEffects.removeEndOfTurnEffects(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void removeInactiveEffects(Game game) {
|
public synchronized void removeInactiveEffects(Game game) {
|
||||||
|
|
@ -163,6 +164,20 @@ public class ContinuousEffects implements Serializable {
|
||||||
spliceCardEffects.removeInactiveEffects(game);
|
spliceCardEffects.removeInactiveEffects(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void incYourTurnNumPlayed(Game game) {
|
||||||
|
layeredEffects.incYourTurnNumPlayed(game);
|
||||||
|
continuousRuleModifyingEffects.incYourTurnNumPlayed(game);
|
||||||
|
replacementEffects.incYourTurnNumPlayed(game);
|
||||||
|
preventionEffects.incYourTurnNumPlayed(game);
|
||||||
|
requirementEffects.incYourTurnNumPlayed(game);
|
||||||
|
restrictionEffects.incYourTurnNumPlayed(game);
|
||||||
|
for (ContinuousEffectsList asThoughtlist : asThoughEffectsMap.values()) {
|
||||||
|
asThoughtlist.incYourTurnNumPlayed(game);
|
||||||
|
}
|
||||||
|
costModificationEffects.incYourTurnNumPlayed(game);
|
||||||
|
spliceCardEffects.incYourTurnNumPlayed(game);
|
||||||
|
}
|
||||||
|
|
||||||
public synchronized List<ContinuousEffect> getLayeredEffects(Game game) {
|
public synchronized List<ContinuousEffect> getLayeredEffects(Game game) {
|
||||||
List<ContinuousEffect> layerEffects = new ArrayList<>();
|
List<ContinuousEffect> layerEffects = new ArrayList<>();
|
||||||
for (ContinuousEffect effect : layeredEffects) {
|
for (ContinuousEffect effect : layeredEffects) {
|
||||||
|
|
@ -376,7 +391,7 @@ public class ContinuousEffects implements Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!applicableAbilities.isEmpty()) {
|
if (!applicableAbilities.isEmpty()) {
|
||||||
replaceEffects.put((ReplacementEffect) effect, applicableAbilities);
|
replaceEffects.put(effect, applicableAbilities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return replaceEffects;
|
return replaceEffects;
|
||||||
|
|
@ -478,7 +493,6 @@ public class ContinuousEffects implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @param objectId
|
* @param objectId
|
||||||
* @param type
|
* @param type
|
||||||
* @param affectedAbility
|
* @param affectedAbility
|
||||||
|
|
@ -1059,9 +1073,7 @@ public class ContinuousEffects implements Serializable {
|
||||||
final Card card = game.getPermanentOrLKIBattlefield(ability.getSourceId());
|
final Card card = game.getPermanentOrLKIBattlefield(ability.getSourceId());
|
||||||
if (!(effect instanceof BecomesFaceDownCreatureEffect)) {
|
if (!(effect instanceof BecomesFaceDownCreatureEffect)) {
|
||||||
if (card != null) {
|
if (card != null) {
|
||||||
if (!card.getAbilities(game).contains(ability)) {
|
return card.getAbilities(game).contains(ability);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,21 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
||||||
return new ContinuousEffectsList<>(this);
|
return new ContinuousEffectsList<>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeEndOfTurnEffects() {
|
public void removeEndOfTurnEffects(Game game) {
|
||||||
|
// calls every turn on cleanup step (only end of turn duration)
|
||||||
|
// rules 514.2
|
||||||
for (Iterator<T> i = this.iterator(); i.hasNext(); ) {
|
for (Iterator<T> i = this.iterator(); i.hasNext(); ) {
|
||||||
T entry = i.next();
|
T entry = i.next();
|
||||||
if (entry.getDuration() == Duration.EndOfTurn) {
|
boolean canRemove = false;
|
||||||
|
switch (entry.getDuration()) {
|
||||||
|
case EndOfTurn:
|
||||||
|
canRemove = true;
|
||||||
|
break;
|
||||||
|
case UntilEndOfYourNextTurn:
|
||||||
|
canRemove = entry.isYourNextTurn(game);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (canRemove) {
|
||||||
i.remove();
|
i.remove();
|
||||||
effectAbilityMap.remove(entry.getId());
|
effectAbilityMap.remove(entry.getId());
|
||||||
}
|
}
|
||||||
|
|
@ -72,6 +83,15 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void incYourTurnNumPlayed(Game game) {
|
||||||
|
for (Iterator<T> i = this.iterator(); i.hasNext(); ) {
|
||||||
|
T entry = i.next();
|
||||||
|
if (game.isActivePlayer(entry.getStartingController())) {
|
||||||
|
entry.incYourTurnNumPlayed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isInactive(T effect, Game game) {
|
private boolean isInactive(T effect, Game game) {
|
||||||
Set<Ability> set = effectAbilityMap.get(effect.getId());
|
Set<Ability> set = effectAbilityMap.get(effect.getId());
|
||||||
if (set == null) {
|
if (set == null) {
|
||||||
|
|
|
||||||
|
|
@ -569,18 +569,20 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
combat.checkForRemoveFromCombat(game);
|
combat.checkForRemoveFromCombat(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove End of Combat effects
|
// remove end of combat effects
|
||||||
public void removeEocEffects(Game game) {
|
public void removeEocEffects(Game game) {
|
||||||
effects.removeEndOfCombatEffects();
|
effects.removeEndOfCombatEffects();
|
||||||
delayed.removeEndOfCombatAbilities();
|
delayed.removeEndOfCombatAbilities();
|
||||||
game.applyEffects();
|
game.applyEffects();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove end of turn effects
|
||||||
public void removeEotEffects(Game game) {
|
public void removeEotEffects(Game game) {
|
||||||
effects.removeEndOfTurnEffects();
|
effects.removeEndOfTurnEffects(game);
|
||||||
delayed.removeEndOfTurnAbilities();
|
delayed.removeEndOfTurnAbilities(game);
|
||||||
exile.cleanupEndOfTurnZones(game);
|
exile.cleanupEndOfTurnZones(game);
|
||||||
game.applyEffects();
|
game.applyEffects();
|
||||||
|
effects.incYourTurnNumPlayed(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEffect(ContinuousEffect effect, Ability source) {
|
public void addEffect(ContinuousEffect effect, Ability source) {
|
||||||
|
|
@ -788,7 +790,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
public void addCard(Card card) {
|
public void addCard(Card card) {
|
||||||
setZone(card.getId(), Zone.OUTSIDE);
|
setZone(card.getId(), Zone.OUTSIDE);
|
||||||
for (Ability ability : card.getAbilities()) {
|
for (Ability ability : card.getAbilities()) {
|
||||||
addAbility(ability, card);
|
addAbility(ability, null, card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,5 @@
|
||||||
|
|
||||||
package mage.game.turn;
|
package mage.game.turn;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.TurnPhase;
|
import mage.constants.TurnPhase;
|
||||||
|
|
@ -18,8 +12,13 @@ import mage.game.stack.StackObject;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.util.ThreadLocalStringBuilder;
|
import mage.util.ThreadLocalStringBuilder;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
*/
|
*/
|
||||||
public class Turn implements Serializable {
|
public class Turn implements Serializable {
|
||||||
|
|
@ -93,7 +92,6 @@ public class Turn implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @param game
|
* @param game
|
||||||
* @param activePlayer
|
* @param activePlayer
|
||||||
* @return true if turn is skipped
|
* @return true if turn is skipped
|
||||||
|
|
@ -105,6 +103,7 @@ public class Turn implements Serializable {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (game.getState().getTurnMods().skipTurn(activePlayer.getId())) {
|
if (game.getState().getTurnMods().skipTurn(activePlayer.getId())) {
|
||||||
game.informPlayers(activePlayer.getLogName() + " skips their turn.");
|
game.informPlayers(activePlayer.getLogName() + " skips their turn.");
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -239,6 +238,7 @@ public class Turn implements Serializable {
|
||||||
this.play(game, activePlayerId);
|
this.play(game, activePlayerId);
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for some spells with end turn effect (e.g. Time Stop).
|
* Used for some spells with end turn effect (e.g. Time Stop).
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue