* Removed some data from player restoring to fix unintended draws after a player concedes game (#1205)

This commit is contained in:
LevelX2 2015-08-18 17:20:04 +02:00
parent 692148d3c2
commit aa1eb354ef
7 changed files with 65 additions and 29 deletions

View file

@ -53,6 +53,7 @@ import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.game.stack.StackAbility;
import mage.players.Player;
import mage.players.net.UserData;
import mage.target.Target;
import org.apache.log4j.Logger;
@ -75,6 +76,7 @@ public class SimulatedPlayer2 extends ComputerPlayer {
pass.setControllerId(playerId);
this.isSimulatedPlayer = isSimulatedPlayer;
this.suggested = suggested;
this.userData = UserData.getDefaultUserDataView();
}
public SimulatedPlayer2(final SimulatedPlayer2 player) {

View file

@ -50,6 +50,7 @@ import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreatureOrPlayer;
import mage.target.targetpointer.FixedTarget;
@ -68,8 +69,8 @@ public class OutpostSiege extends CardImpl {
this.expansionSetCode = "FRF";
// As Outpost Siege enters the battlefield, choose Khans or Dragons.
this.addAbility(new EntersBattlefieldAbility(new ChooseModeEffect("Khans or Dragons?","Khans", "Dragons"),null, true,
"As {this} enters the battlefield, choose Khans or Dragons.",""));
this.addAbility(new EntersBattlefieldAbility(new ChooseModeEffect("Khans or Dragons?", "Khans", "Dragons"), null, true,
"As {this} enters the battlefield, choose Khans or Dragons.", ""));
// * Khans - At the beginning of your upkeep, exile the top card of your library. Until end of turn, you may play that card.
this.addAbility(new ConditionalTriggeredAbility(
@ -80,10 +81,10 @@ public class OutpostSiege extends CardImpl {
// * Dragons - Whenever a creature you control leaves the battlefield, Outpost Siege deals 1 damage to target creature or player.
Ability ability2 = new ConditionalTriggeredAbility(
new ZoneChangeAllTriggeredAbility(Zone.BATTLEFIELD, Zone.BATTLEFIELD, null, new DamageTargetEffect(1),
new FilterControlledCreaturePermanent(), "", false),
new FilterControlledCreaturePermanent(), "", false),
new ModeChoiceSourceCondition("Dragons"),
ruleTrigger2);
ability2.addTarget(new TargetCreatureOrPlayer());
ability2.addTarget(new TargetCreatureOrPlayer());
this.addAbility(ability2);
}
@ -117,13 +118,15 @@ class OutpostSiegeExileEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (controller != null && sourcePermanent != null) {
Card card = controller.getLibrary().getFromTop(game);
if (card != null) {
controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.LIBRARY, true);
String exileName = sourcePermanent.getIdName() + " <this card may be played the turn it was exiled";
controller.moveCardsToExile(card, source, game, true, source.getSourceId(), exileName);
if (game.getState().getZone(card.getId()) == Zone.EXILED) {
ContinuousEffect effect = new CastFromNonHandZoneTargetEffect(Duration.EndOfTurn);
effect.setTargetPointer(new FixedTarget(card.getId()));
effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game)));
game.addEffect(effect, source);
}
}
@ -156,8 +159,8 @@ class CastFromNonHandZoneTargetEffect extends AsThoughEffectImpl {
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
if (getTargetPointer().getTargets(game, source).contains(objectId) &&
source.getControllerId().equals(affectedControllerId)) {
if (getTargetPointer().getTargets(game, source).contains(objectId)
&& source.getControllerId().equals(affectedControllerId)) {
Card card = game.getCard(objectId);
if (card != null) {
return true;

View file

@ -42,7 +42,6 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Library;
@ -65,7 +64,7 @@ public class AbbotOfKeralKeep extends CardImpl {
// Prowess
this.addAbility(new ProwessAbility());
// When Abbot of Keral Keep enters the battlefield, exile the top card of your library. Until end of turn, you may play that card.
this.addAbility(new EntersBattlefieldTriggeredAbility(new AbbotOfKeralKeepExileEffect()));
}
@ -104,10 +103,10 @@ class AbbotOfKeralKeepExileEffect extends OneShotEffect {
Library library = controller.getLibrary();
Card card = library.removeFromTop(game);
if (card != null) {
String exileName = new StringBuilder(sourcePermanent.getIdName()).append(" <this card may be played the turn it was exiled>").toString();
controller.moveCardToExileWithInfo(card, source.getSourceId(), exileName, source.getSourceId(), game, Zone.LIBRARY, true);
String exileName = sourcePermanent.getIdName() + " <this card may be played the turn it was exiled>";
controller.moveCardsToExile(card, source, game, true, source.getSourceId(), exileName);
ContinuousEffect effect = new AbbotOfKeralKeepCastFromExileEffect();
effect.setTargetPointer(new FixedTarget(card.getId()));
effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game)));
game.addEffect(effect, source);
}
return true;
@ -139,7 +138,7 @@ class AbbotOfKeralKeepCastFromExileEffect extends AsThoughEffectImpl {
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
return source.getControllerId().equals(affectedControllerId) &&
objectId.equals(getTargetPointer().getFirst(game, source));
return source.getControllerId().equals(affectedControllerId)
&& objectId.equals(getTargetPointer().getFirst(game, source));
}
}

View file

@ -1358,6 +1358,11 @@ public class TestPlayer implements Player {
computerPlayer.resetPassed();
}
@Override
public void resetPlayerPassedActions() {
computerPlayer.resetPlayerPassedActions();
}
@Override
public void quit(Game game) {
computerPlayer.quit(game);
@ -1701,6 +1706,11 @@ public class TestPlayer implements Player {
return computerPlayer.moveCardToHandWithInfo(card, sourceId, game, withName);
}
@Override
public boolean moveCardsToExile(Card card, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName) {
return computerPlayer.moveCardsToExile(card, source, game, withName, exileId, exileZoneName);
}
@Override
public boolean moveCardsToExile(Set<Card> cards, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName) {
return computerPlayer.moveCardsToExile(cards, source, game, withName, exileId, exileZoneName);

View file

@ -2657,6 +2657,7 @@ public abstract class GameImpl implements Game, Serializable {
for (Player playerObject : getPlayers().values()) {
if (playerObject.isHuman() && playerObject.isInGame()) {
playerObject.abort();
playerObject.resetPlayerPassedActions();
}
}
fireUpdatePlayersEvent();

View file

@ -179,6 +179,8 @@ public interface Player extends MageItem, Copyable<Player> {
void resetPassed();
void resetPlayerPassedActions();
boolean getPassedTurn();
boolean getPassedUntilEndOfTurn();
@ -620,13 +622,12 @@ public interface Player extends MageItem, Copyable<Player> {
*/
boolean moveCards(Cards cards, Zone fromZone, Zone toZone, Ability source, Game game);
// boolean moveCards(Cards cards, Zone fromZone, Zone toZone, Ability source, Game game, boolean withName);
boolean moveCards(Card card, Zone fromZone, Zone toZone, Ability source, Game game);
// boolean moveCards(Card card, Zone fromZone, Zone toZone, Ability source, Game game, boolean withName);
boolean moveCards(Set<Card> cards, Zone fromZone, Zone toZone, Ability source, Game game);
// boolean moveCards(Set<Card> cards, Zone fromZone, Zone toZone, Ability source, Game game, boolean withName);
boolean moveCardsToExile(Card card, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName);
boolean moveCardsToExile(Set<Card> cards, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName);
/**

View file

@ -330,9 +330,21 @@ public abstract class PlayerImpl implements Player, Serializable {
this.name = player.getName();
this.human = player.isHuman();
this.life = player.getLife();
this.wins = player.hasWon();
this.loses = player.hasLost();
// Don't restore more global states. If restored they are probably cause for unintended draws (https://github.com/magefree/mage/issues/1205).
// this.wins = player.hasWon();
// this.loses = player.hasLost();
// this.left = player.hasLeft();
// this.quit = player.hasQuit();
// Makes no sense to restore
// this.passed = player.isPassed();
// this.priorityTimeLeft = player.getPriorityTimeLeft();
// this.idleTimeout = player.hasIdleTimeout();
// this.timerTimeout = player.hasTimerTimeout();
// can't change so no need to restore
// this.isTestMode = player.isTestMode();
// This is meta data and should'nt be restored by rollback
// this.userData = player.getUserData();
this.library = player.getLibrary().copy();
this.sideboard = player.getSideboard().copy();
this.hand = player.getHand().copy();
@ -349,10 +361,6 @@ public abstract class PlayerImpl implements Player, Serializable {
this.manaPool = player.getManaPool().copy();
this.turns = player.getTurns();
this.left = player.hasLeft();
this.quit = player.hasQuit();
this.timerTimeout = player.hasTimerTimeout();
this.idleTimeout = player.hasIdleTimeout();
this.range = player.getRange();
this.canGainLife = player.isCanGainLife();
this.canLoseLife = player.isCanLoseLife();
@ -361,7 +369,6 @@ public abstract class PlayerImpl implements Player, Serializable {
this.inRange.clear();
this.inRange.addAll(player.getInRange());
this.userData = player.getUserData();
this.canPayLifeCost = player.canPayLifeCost();
this.canPaySacrificeCost = player.canPaySacrificeCost();
this.loseByZeroOrLessLife = player.canLoseByZeroOrLessLife();
@ -371,12 +378,9 @@ public abstract class PlayerImpl implements Player, Serializable {
this.topCardRevealed = player.isTopCardRevealed();
this.playersUnderYourControl.clear();
this.playersUnderYourControl.addAll(player.getPlayersUnderYourControl());
this.isTestMode = player.isTestMode();
this.isGameUnderControl = player.isGameUnderControl();
this.turnController = player.getTurnControlledBy();
this.passed = player.isPassed();
this.priorityTimeLeft = player.getPriorityTimeLeft();
this.reachedNextTurnAfterLeaving = player.hasReachedNextTurnAfterLeaving();
this.castSourceIdWithAlternateMana = player.getCastSourceIdWithAlternateMana();
this.castSourceIdManaCosts = player.getCastSourceIdManaCosts();
@ -1823,6 +1827,15 @@ public abstract class PlayerImpl implements Player, Serializable {
this.passed = this.loses || this.hasLeft();
}
@Override
public void resetPlayerPassedActions() {
this.passedAllTurns = false;
this.passedTurn = false;
this.passedUntilEndOfTurn = false;
this.passedUntilNextMain = false;
this.passedUntilStackResolved = false;
}
@Override
public void quit(Game game) {
quit = true;
@ -2949,6 +2962,13 @@ public abstract class PlayerImpl implements Player, Serializable {
}
}
@Override
public boolean moveCardsToExile(Card card, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName) {
Set<Card> cards = new HashSet<>();
cards.add(card);
return moveCardsToExile(cards, source, game, withName, exileId, exileZoneName);
}
@Override
public boolean moveCardsToExile(Set<Card> cards, Ability source, Game game, boolean withName, UUID exileId, String exileZoneName) {
if (cards.isEmpty()) {