* 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:
Oleg Agafonov 2019-04-28 11:27:08 +04:00
parent 4288e45c23
commit 534037e095
22 changed files with 758 additions and 137 deletions

View file

@ -130,7 +130,7 @@ class GideonBattleForgedAttacksIfAbleTargetEffect extends RequirementEffect {
if (targetPermanent == null) {
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

View file

@ -114,20 +114,21 @@ class GideonJuraEffect extends RequirementEffect {
public void init(Ability source, Game game) {
super.init(source, game);
creatingPermanent = new MageObjectReference(source.getSourceId(), game);
setStartingControllerAndTurnNum(game, source.getFirstTarget(), game.getActivePlayerId()); // setup startingController to calc isYourTurn calls
}
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
return permanent.isControlledBy(source.getFirstTarget());
return permanent.isControlledBy(source.getFirstTarget()) && this.isYourNextTurn(game);
}
@Override
public boolean isInactive(Ability source, Game game) {
return (getStartingTurnNum() != game.getTurnNum()
&& (game.getPhase().getType() == TurnPhase.END
&& game.isActivePlayer(source.getFirstTarget())))
|| // 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.
creatingPermanent.getPermanent(game) == null;
return (game.getPhase().getType() == TurnPhase.END && this.isYourNextTurn(game))
// 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.
|| creatingPermanent.getPermanent(game) == null;
}
@Override

View file

@ -42,7 +42,9 @@ public final class OracleEnVec extends CardImpl {
this.power = 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 players next turn, the chosen
// creatures attack if able, and other creatures cant attack. At the beginning of that turns end step,
// destroy each of the chosen creatures that didnt attack this turn. Activate this ability only during your turn.
Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new OracleEnVecEffect(), new TapSourceCost(), MyTurnCondition.instance);
ability.addTarget(new TargetOpponent());
this.addAbility(ability, new AttackedThisTurnWatcher());
@ -62,7 +64,9 @@ class OracleEnVecEffect extends OneShotEffect {
OracleEnVecEffect() {
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) {
@ -102,7 +106,7 @@ class OracleEnVecEffect extends OneShotEffect {
class OracleEnVecMustAttackRequirementEffect extends RequirementEffect {
OracleEnVecMustAttackRequirementEffect() {
super(Duration.Custom);
super(Duration.UntilEndOfYourNextTurn);
}
OracleEnVecMustAttackRequirementEffect(final OracleEnVecMustAttackRequirementEffect effect) {
@ -117,7 +121,8 @@ class OracleEnVecMustAttackRequirementEffect extends RequirementEffect {
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
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
@ -130,11 +135,20 @@ class OracleEnVecMustAttackRequirementEffect extends RequirementEffect {
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
public boolean isInactive(Ability source, Game game) {
return getStartingTurnNum() != game.getTurnNum()
&& (game.getPhase().getType() == TurnPhase.END
&& game.isActivePlayer(this.getTargetPointer().getFirst(game, source)));
return game.getPhase().getType() == TurnPhase.END && this.isYourNextTurn(game);
}
@Override
@ -169,11 +183,20 @@ class OracleEnVecCantAttackRestrictionEffect extends RestrictionEffect {
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
public boolean isInactive(Ability source, Game game) {
return getStartingTurnNum() != game.getTurnNum()
&& (game.getPhase().getType() == TurnPhase.END
&& game.isActivePlayer(this.getTargetPointer().getFirst(game, source)));
return game.getPhase().getType() == TurnPhase.END && this.isYourNextTurn(game);
}
@Override

View file

@ -71,13 +71,22 @@ class PeaceTalksEffect extends OneShotEffect {
class PeaceTalksCantAttackEffect extends RestrictionEffect {
int startedTurnNum = 0;
public PeaceTalksCantAttackEffect() {
super(Duration.Custom);
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) {
super(effect);
this.startedTurnNum = effect.startedTurnNum;
}
@Override
@ -97,7 +106,7 @@ class PeaceTalksCantAttackEffect extends RestrictionEffect {
@Override
public boolean isInactive(Ability source, Game game) {
if (getStartingTurnNum() + 2 <= game.getTurnNum()) {
if (game.getTurnNum() > (startedTurnNum + 1)) {
this.discard();
return true;
}
@ -107,6 +116,8 @@ class PeaceTalksCantAttackEffect extends RestrictionEffect {
class PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities extends ContinuousRuleModifyingEffectImpl {
int startedTurnNum = 0;
public PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities() {
super(Duration.Custom, Outcome.Neutral);
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) {
super(effect);
this.startedTurnNum = effect.startedTurnNum;
}
@Override
public void init(Ability source, Game game) {
super.init(source, game);
startedTurnNum = game.getTurnNum();
}
@Override
@ -149,7 +167,7 @@ class PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities ex
@Override
public boolean isInactive(Ability source, Game game) {
if (getStartingTurnNum() + 2 <= game.getTurnNum()) {
if (game.getTurnNum() > (startedTurnNum + 1)) {
this.discard();
return true;
}

View file

@ -92,20 +92,21 @@ class RowanKenrithAttackEffect extends RequirementEffect {
public void init(Ability source, Game game) {
super.init(source, game);
creatingPermanent = new MageObjectReference(source.getSourceId(), game);
setStartingControllerAndTurnNum(game, source.getFirstTarget(), game.getActivePlayerId()); // setup startingController to calc isYourTurn calls
}
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
return permanent.isControlledBy(source.getFirstTarget());
return permanent.isControlledBy(source.getFirstTarget()) && this.isYourNextTurn(game);
}
@Override
public boolean isInactive(Ability source, Game game) {
return (getStartingTurnNum() != game.getTurnNum()
&& (game.getPhase().getType() == TurnPhase.END
&& game.isActivePlayer(source.getFirstTarget())))
|| // 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.
creatingPermanent.getPermanent(game) == null;
return (game.getPhase().getType() == TurnPhase.END && this.isYourNextTurn(game))
// 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.
|| creatingPermanent.getPermanent(game) == null;
}
@Override

View file

@ -59,9 +59,7 @@ class TauntEffect extends RequirementEffect {
@Override
public boolean isInactive(Ability source, Game game) {
return getStartingTurnNum() != game.getTurnNum() &&
(game.getPhase().getType() == TurnPhase.END &&
game.isActivePlayer(this.getTargetPointer().getFirst(game, source)));
return game.getPhase().getType() == TurnPhase.END && this.isYourNextTurn(game);
}
@Override

View file

@ -94,10 +94,7 @@ class VraskaTheUnseenGainAbilityEffect extends ContinuousEffectImpl {
@Override
public boolean isInactive(Ability source, Game game) {
if (getStartingTurnNum() != 0 && game.getTurnNum() != getStartingTurnNum()) {
return game.isActivePlayer(source.getControllerId());
}
return false;
return game.getPhase().getType() == TurnPhase.END && this.isYourNextTurn(game);
}
}

View file

@ -47,7 +47,6 @@ public final class WallOfDust extends CardImpl {
class WallOfDustRestrictionEffect extends RestrictionEffect {
int nextTurnTargetController = 0;
protected MageObjectReference targetPermanentReference;
public WallOfDustRestrictionEffect() {
@ -57,7 +56,6 @@ class WallOfDustRestrictionEffect extends RestrictionEffect {
public WallOfDustRestrictionEffect(final WallOfDustRestrictionEffect effect) {
super(effect);
this.nextTurnTargetController = effect.nextTurnTargetController;
this.targetPermanentReference = effect.targetPermanentReference;
}
@ -68,26 +66,22 @@ class WallOfDustRestrictionEffect extends RestrictionEffect {
@Override
public boolean isInactive(Ability source, Game game) {
if (targetPermanentReference == null) {
if (targetPermanentReference == null || targetPermanentReference.getPermanent(game) == null) {
return true;
}
Permanent targetPermanent = targetPermanentReference.getPermanent(game);
if (targetPermanent == null) {
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;
return game.getPhase().getType() == TurnPhase.END && this.isYourNextTurn(game);
}
@Override
public void init(Ability source, Game game) {
super.init(source, game);
if (getTargetPointer().getFirst(game, source) == null) {
discard();
Permanent perm = game.getPermanent(getTargetPointer().getFirst(game, source));
if (perm != null) {
targetPermanentReference = new MageObjectReference(perm, game);
setStartingControllerAndTurnNum(game, perm.getControllerId(), game.getActivePlayerId());
} else {
targetPermanentReference = new MageObjectReference(getTargetPointer().getFirst(game, source), game);
discard();
}
}