mirror of
https://github.com/correl/mage.git
synced 2024-11-15 11:09:30 +00:00
* Added a simple check for infinite loops so that if players confirm the game ends in a draw (#3329).
This commit is contained in:
parent
7b61ad7455
commit
5ce813ad87
2 changed files with 75 additions and 0 deletions
|
@ -7,6 +7,7 @@ package org.mage.test.game.ends;
|
||||||
|
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
@ -77,4 +78,45 @@ public class GameIsADrawTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* So here I made a simple infinite loop with Stuffy Doll and Pariah's
|
||||||
|
* Shield, which should make the game a draw. But instead, it just keeps
|
||||||
|
* going...
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void GameDrawByInfiniteLoop() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
|
||||||
|
|
||||||
|
// All damage that would be dealt to you is dealt to equipped creature instead.
|
||||||
|
// Equip {3}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Pariah's Shield", 1); // Artifact Equipment {5}
|
||||||
|
|
||||||
|
// As Stuffy Doll enters the battlefield, choose a player.
|
||||||
|
// Stuffy Doll is indestructible.
|
||||||
|
// Whenever Stuffy Doll is dealt damage, it deals that much damage to the chosen player.
|
||||||
|
// {T}: Stuffy Doll deals 1 damage to itself.
|
||||||
|
addCard(Zone.HAND, playerA, "Stuffy Doll", 1); // Artifact Creature {5} 0/1
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Stuffy Doll");
|
||||||
|
setChoice(playerA, "PlayerA");
|
||||||
|
setChoice(playerA, "PlayerA");
|
||||||
|
|
||||||
|
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip", "Stuffy Doll");
|
||||||
|
activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "{T}");
|
||||||
|
setStopAt(3, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, "Stuffy Doll", 1);
|
||||||
|
Permanent shield = getPermanent("Pariah's Shield");
|
||||||
|
Assert.assertTrue("Pariah's Shield is attached", shield.getAttachedTo() != null);
|
||||||
|
|
||||||
|
Assert.assertFalse("Player A has not won.", playerA.hasWon());
|
||||||
|
Assert.assertFalse("Player B has not won.", playerB.hasWon());
|
||||||
|
|
||||||
|
Assert.assertTrue("Game has ended.", currentGame.hasEnded());
|
||||||
|
|
||||||
|
Assert.assertTrue("Inifinite loop detected, game has be de a draw.", currentGame.isADraw());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1233,6 +1233,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
@Override
|
@Override
|
||||||
public void playPriority(UUID activePlayerId, boolean resuming) {
|
public void playPriority(UUID activePlayerId, boolean resuming) {
|
||||||
int errorContinueCounter = 0;
|
int errorContinueCounter = 0;
|
||||||
|
int infiniteLoopCounter = 0;
|
||||||
int bookmark = 0;
|
int bookmark = 0;
|
||||||
clearAllBookmarks();
|
clearAllBookmarks();
|
||||||
try {
|
try {
|
||||||
|
@ -1286,6 +1287,13 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
}
|
}
|
||||||
if (allPassed()) {
|
if (allPassed()) {
|
||||||
if (!state.getStack().isEmpty()) {
|
if (!state.getStack().isEmpty()) {
|
||||||
|
if (getStack().size() < 4) {
|
||||||
|
infiniteLoopCounter++;
|
||||||
|
if (infiniteLoopCounter > 15) {
|
||||||
|
isInfiniteLoop();
|
||||||
|
infiniteLoopCounter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
//20091005 - 115.4
|
//20091005 - 115.4
|
||||||
resolve();
|
resolve();
|
||||||
applyEffects();
|
applyEffects();
|
||||||
|
@ -1294,6 +1302,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
resetShortLivingLKI();
|
resetShortLivingLKI();
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
infiniteLoopCounter = 0;
|
||||||
resetLKI();
|
resetLKI();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1350,6 +1359,30 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void isInfiniteLoop() {
|
||||||
|
StackObject stackObject = getStack().getFirst();
|
||||||
|
if (stackObject != null) {
|
||||||
|
Player controller = getPlayer(stackObject.getControllerId());
|
||||||
|
if (controller != null) {
|
||||||
|
for (UUID playerId : getState().getPlayersInRange(controller.getId(), this)) {
|
||||||
|
Player player = getPlayer(playerId);
|
||||||
|
if (!player.chooseUse(Outcome.Detriment, "Draw game because of infinite looping?", null, this)) {
|
||||||
|
informPlayers(controller.getLogName() + " has NOT confirmed that the game is a draw because of infinite looping.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
informPlayers(controller.getLogName() + " has confirmed that the game is a draw because of infinite looping.");
|
||||||
|
}
|
||||||
|
for (UUID playerId : getState().getPlayersInRange(controller.getId(), this)) {
|
||||||
|
Player player = getPlayer(playerId);
|
||||||
|
if (player != null) {
|
||||||
|
player.drew(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean allPassed() {
|
protected boolean allPassed() {
|
||||||
for (Player player : state.getPlayers().values()) {
|
for (Player player : state.getPlayers().values()) {
|
||||||
if (!player.isPassed() && player.canRespond()) {
|
if (!player.isPassed() && player.canRespond()) {
|
||||||
|
|
Loading…
Reference in a new issue