* No more continuous effects stay on battlefield after player leave the game;

Test framework: added real time check for player in game or not;
This commit is contained in:
Oleg Agafonov 2019-04-28 19:32:25 +04:00
parent 00633ce055
commit 9ef2e0bda7
5 changed files with 244 additions and 25 deletions

View file

@ -1,10 +1,13 @@
package mage.abilities.effects;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.MageSingleton;
import mage.cards.Card;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
import org.apache.log4j.Logger;
import java.util.*;
@ -93,6 +96,22 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
}
private boolean isInactive(T effect, Game game) {
// ends all inactive effects -- calls on player leave or apply new effect
if (game.getState().isGameOver()) {
// no need to remove effects after end -- users and tests must see last game state
return false;
}
/*
800.4a When a player leaves the game, all objects (see rule 109) owned by that player leave the game and any effects
which give that player control of any objects or players end. Then, if that player controlled any objects on the stack
not represented by cards, those objects cease to exist. Then, if there are any objects still controlled by that player,
those objects are exiled. This is not a state-based action. It happens as soon as the player leaves the game.
If the player who left the game had priority at the time he or she left, priority passes to the next player in turn
order whos still in the game.
*/
// objects removes doing in player.leave() call... effects removes is here
Set<Ability> set = effectAbilityMap.get(effect.getId());
if (set == null) {
logger.debug("No abilities for effect found: " + effect.toString());
@ -108,30 +127,62 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
} else if (effect.isDiscarded()) {
it.remove();
} else {
// 800.4k When a player leaves the game, any continuous effects with durations that last until that
// players 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.
MageObject object = game.getObject(ability.getSourceId());
boolean isObjectInGame = ability.getSourceId() == null || object != null; // Commander effects have no sourceId
boolean isOwnerLeaveGame = false;
if (object instanceof Card) {
Player owner = game.getPlayer(((Card) object).getOwnerId());
isOwnerLeaveGame = !owner.isInGame();
}
switch (effect.getDuration()) {
//
case WhileOnBattlefield:
case WhileInGraveyard:
case WhileOnStack:
if (ability.getSourceId() != null && game.getObject(ability.getSourceId()) == null) { // Commander effects have no sourceId
it.remove(); // if the related source object does no longer exist in game - the effect has to be removed
case EndOfStep:
case EndOfCombat:
case EndOfGame:
// if the related source object does no longer exist in game - the effect has to be removed
if (isOwnerLeaveGame || !isObjectInGame) {
it.remove();
}
break;
case OneUse:
if (effect.isUsed()) {
if (isOwnerLeaveGame || effect.isUsed()) {
it.remove();
}
break;
case Custom:
// custom effects must process it's own inactive method (override), but can'be missied by devs
if (isOwnerLeaveGame || effect.isInactive(ability, game)) {
it.remove();
}
break;
case EndOfTurn:
// end of turn discards on cleanup steps
// 514.2
break;
case UntilYourNextTurn:
case UntilEndOfYourNextTurn:
// until your turn effects continue until real turn reached, their used it's own inactive method
// 514.2 Second, the following actions happen simultaneously: all damage marked on permanents
// (including phased-out permanents) is removed and all "until end of turn" and "this turn" effects end.
// This turn-based action doesnt use the stack.
if (effect.isInactive(ability, game)) {
it.remove();
}
break;
case UntilSourceLeavesBattlefield:
if (Zone.BATTLEFIELD != game.getState().getZone(ability.getSourceId())) {
if (isOwnerLeaveGame || Zone.BATTLEFIELD != game.getState().getZone(ability.getSourceId())) {
it.remove();
}
break;
default:
throw new IllegalStateException("Effects gets unknown duration " + effect.getDuration() + ", effect: " + effect.toString());
}
}
}