mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 10:40:06 -08:00
Player under control - fixed that it doesn't hide opponent's hand after control lost (part of #13353);
This commit is contained in:
parent
71b0613355
commit
8d7bd60061
9 changed files with 114 additions and 55 deletions
|
|
@ -0,0 +1,83 @@
|
||||||
|
package org.mage.test.cards.control;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.view.GameView;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test Framework do not support under control commands, so check only game related info and data
|
||||||
|
*
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public class PlayerUnderControlTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_ClientSideDataMustBeHidden() {
|
||||||
|
// possible bug: after control ends - player still able to view opponent's hands
|
||||||
|
|
||||||
|
// When you cast Emrakul, you gain control of target opponent during that player's next turn.
|
||||||
|
// After that turn, that player takes an extra turn.
|
||||||
|
addCard(Zone.HAND, playerA, "Emrakul, the Promised End"); // {13}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 13);
|
||||||
|
//
|
||||||
|
addCard(Zone.HAND, playerB, "Lightning Bolt");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
|
||||||
|
|
||||||
|
// prepare control effect
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Emrakul, the Promised End");
|
||||||
|
addTarget(playerA, playerB);
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
|
checkUnderControl("turn 1 - A, B normal", 1, PhaseStep.PRECOMBAT_MAIN, false);
|
||||||
|
checkUnderControl("turn 2 - B under A", 2, PhaseStep.PRECOMBAT_MAIN, true);
|
||||||
|
checkUnderControl("turn 3 - A, B normal", 3, PhaseStep.PRECOMBAT_MAIN, false);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(3, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkUnderControl(String info, int turnNum, PhaseStep step, boolean mustHaveControl) {
|
||||||
|
runCode(info, turnNum, step, playerA, (info1, player, game) -> {
|
||||||
|
GameView viewA = getGameView(playerA);
|
||||||
|
GameView viewB = getGameView(playerB);
|
||||||
|
if (mustHaveControl) {
|
||||||
|
Assert.assertTrue(info, playerA.isGameUnderControl());
|
||||||
|
Assert.assertFalse(info, playerB.isGameUnderControl());
|
||||||
|
|
||||||
|
Assert.assertTrue(info, playerA.getPlayersUnderYourControl().contains(playerB.getId()));
|
||||||
|
Assert.assertTrue(info, playerB.getPlayersUnderYourControl().isEmpty());
|
||||||
|
|
||||||
|
Assert.assertTrue(info, playerA.getTurnControllers().isEmpty());
|
||||||
|
Assert.assertTrue(info, playerB.getTurnControllers().contains(playerA.getId()));
|
||||||
|
|
||||||
|
Assert.assertEquals(info, playerA.getTurnControlledBy(), playerA.getId());
|
||||||
|
Assert.assertEquals(info, playerB.getTurnControlledBy(), playerA.getId());
|
||||||
|
|
||||||
|
// client side
|
||||||
|
Assert.assertFalse(info, viewA.getOpponentHands().isEmpty());
|
||||||
|
Assert.assertTrue(info, viewB.getOpponentHands().isEmpty());
|
||||||
|
} else {
|
||||||
|
// A,B normal
|
||||||
|
Assert.assertTrue(info, playerA.isGameUnderControl());
|
||||||
|
Assert.assertTrue(info, playerB.isGameUnderControl());
|
||||||
|
|
||||||
|
Assert.assertTrue(info, playerA.getPlayersUnderYourControl().isEmpty());
|
||||||
|
Assert.assertTrue(info, playerB.getPlayersUnderYourControl().isEmpty());
|
||||||
|
|
||||||
|
Assert.assertTrue(info, playerA.getTurnControllers().isEmpty());
|
||||||
|
Assert.assertTrue(info, playerB.getTurnControllers().isEmpty());
|
||||||
|
|
||||||
|
Assert.assertEquals(info, playerA.getTurnControlledBy(), playerA.getId());
|
||||||
|
Assert.assertEquals(info, playerB.getTurnControlledBy(), playerB.getId());
|
||||||
|
|
||||||
|
// client side
|
||||||
|
Assert.assertTrue(info, viewA.getOpponentHands().isEmpty());
|
||||||
|
Assert.assertTrue(info, viewB.getOpponentHands().isEmpty());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3134,13 +3134,13 @@ public class TestPlayer implements Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setGameUnderYourControl(boolean value) {
|
public void setGameUnderYourControl(Game game, boolean value) {
|
||||||
computerPlayer.setGameUnderYourControl(value);
|
computerPlayer.setGameUnderYourControl(game, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setGameUnderYourControl(boolean value, boolean fullRestore) {
|
public void setGameUnderYourControl(Game game, boolean value, boolean fullRestore) {
|
||||||
computerPlayer.setGameUnderYourControl(value, fullRestore);
|
computerPlayer.setGameUnderYourControl(game, value, fullRestore);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -378,7 +378,7 @@ public abstract class AbilityImpl implements Ability {
|
||||||
|
|
||||||
// unit tests only: it allows to add targets/choices by two ways:
|
// unit tests only: it allows to add targets/choices by two ways:
|
||||||
// 1. From cast/activate command params (process it here)
|
// 1. From cast/activate command params (process it here)
|
||||||
// 2. From single addTarget/setChoice, it's a preffered method for tests (process it in normal choose dialogs like human player)
|
// 2. From single addTarget/setChoice, it's a preferred method for tests (process it in normal choose dialogs like human player)
|
||||||
if (controller.isTestsMode()) {
|
if (controller.isTestsMode()) {
|
||||||
if (!controller.addTargets(this, game)) {
|
if (!controller.addTargets(this, game)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
package mage.abilities.effects.common;
|
|
||||||
|
|
||||||
import mage.constants.Outcome;
|
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.effects.OneShotEffect;
|
|
||||||
import mage.game.Game;
|
|
||||||
import mage.players.Player;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: delete, there are already end turn code with control reset
|
|
||||||
* @author nantuko
|
|
||||||
*/
|
|
||||||
public class LoseControlOnOtherPlayersControllerEffect extends OneShotEffect {
|
|
||||||
|
|
||||||
public LoseControlOnOtherPlayersControllerEffect(String controllingPlayerName, String controlledPlayerName) {
|
|
||||||
super(Outcome.Detriment);
|
|
||||||
staticText = controllingPlayerName + " lost control over " + controlledPlayerName;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected LoseControlOnOtherPlayersControllerEffect(final LoseControlOnOtherPlayersControllerEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LoseControlOnOtherPlayersControllerEffect copy() {
|
|
||||||
return new LoseControlOnOtherPlayersControllerEffect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
|
||||||
if (player != null) {
|
|
||||||
player.resetOtherTurnsControlled();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1852,7 +1852,7 @@ public abstract class GameImpl implements Game {
|
||||||
if (turnController != null) {
|
if (turnController != null) {
|
||||||
Player targetPlayer = getPlayer(spellControllerId);
|
Player targetPlayer = getPlayer(spellControllerId);
|
||||||
if (targetPlayer != null) {
|
if (targetPlayer != null) {
|
||||||
targetPlayer.setGameUnderYourControl(true, false);
|
targetPlayer.setGameUnderYourControl(this, true, false);
|
||||||
informPlayers(turnController.getLogName() + " lost control over " + targetPlayer.getLogName());
|
informPlayers(turnController.getLogName() + " lost control over " + targetPlayer.getLogName());
|
||||||
if (targetPlayer.getTurnControlledBy().equals(turnController.getId())) {
|
if (targetPlayer.getTurnControlledBy().equals(turnController.getId())) {
|
||||||
turnController.getPlayersUnderYourControl().remove(targetPlayer.getId());
|
turnController.getPlayersUnderYourControl().remove(targetPlayer.getId());
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ public class Turn implements Serializable {
|
||||||
if (player != controllingPlayer && controllingPlayer != null) {
|
if (player != controllingPlayer && controllingPlayer != null) {
|
||||||
game.informPlayers(controllingPlayer.getLogName() + " lost control over " + player.getLogName());
|
game.informPlayers(controllingPlayer.getLogName() + " lost control over " + player.getLogName());
|
||||||
}
|
}
|
||||||
player.setGameUnderYourControl(true);
|
player.setGameUnderYourControl(game, true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -388,7 +388,7 @@ public interface Player extends MageItem, Copyable<Player> {
|
||||||
*
|
*
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
void setGameUnderYourControl(boolean value);
|
void setGameUnderYourControl(Game game, boolean value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return player's turn control to prev player
|
* Return player's turn control to prev player
|
||||||
|
|
@ -396,7 +396,7 @@ public interface Player extends MageItem, Copyable<Player> {
|
||||||
* @param value
|
* @param value
|
||||||
* @param fullRestore return turn control to own
|
* @param fullRestore return turn control to own
|
||||||
*/
|
*/
|
||||||
void setGameUnderYourControl(boolean value, boolean fullRestore);
|
void setGameUnderYourControl(Game game, boolean value, boolean fullRestore);
|
||||||
|
|
||||||
void setTestMode(boolean value);
|
void setTestMode(boolean value);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -160,6 +160,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
protected List<AlternativeSourceCosts> alternativeSourceCosts = new ArrayList<>();
|
protected List<AlternativeSourceCosts> alternativeSourceCosts = new ArrayList<>();
|
||||||
|
|
||||||
// TODO: rework turn controller to use single list (see other todos)
|
// TODO: rework turn controller to use single list (see other todos)
|
||||||
|
// see PlayerUnderControlTest
|
||||||
//protected Stack<UUID> allTurnControllers = new Stack<>();
|
//protected Stack<UUID> allTurnControllers = new Stack<>();
|
||||||
protected boolean isGameUnderControl = true; // TODO: replace with allTurnControllers.isEmpty
|
protected boolean isGameUnderControl = true; // TODO: replace with allTurnControllers.isEmpty
|
||||||
protected UUID turnController; // null on own control TODO: replace with allTurnControllers.last
|
protected UUID turnController; // null on own control TODO: replace with allTurnControllers.last
|
||||||
|
|
@ -619,7 +620,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
if (!playerUnderControlId.equals(this.getId())) {
|
if (!playerUnderControlId.equals(this.getId())) {
|
||||||
this.playersUnderYourControl.add(playerUnderControlId);
|
this.playersUnderYourControl.add(playerUnderControlId);
|
||||||
if (!playerUnderControl.hasLeft() && !playerUnderControl.hasLost()) {
|
if (!playerUnderControl.hasLeft() && !playerUnderControl.hasLost()) {
|
||||||
playerUnderControl.setGameUnderYourControl(false);
|
playerUnderControl.setGameUnderYourControl(game, false);
|
||||||
}
|
}
|
||||||
// control will reset on start of the turn
|
// control will reset on start of the turn
|
||||||
}
|
}
|
||||||
|
|
@ -663,14 +664,15 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setGameUnderYourControl(boolean value) {
|
public void setGameUnderYourControl(Game game, boolean value) {
|
||||||
setGameUnderYourControl(value, true);
|
setGameUnderYourControl(game, value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setGameUnderYourControl(boolean value, boolean fullRestore) {
|
public void setGameUnderYourControl(Game game, boolean value, boolean fullRestore) {
|
||||||
this.isGameUnderControl = value;
|
this.isGameUnderControl = value;
|
||||||
if (isGameUnderControl) {
|
if (isGameUnderControl) {
|
||||||
|
removeMeFromPlayersUnderControl(game);
|
||||||
if (fullRestore) {
|
if (fullRestore) {
|
||||||
// to own
|
// to own
|
||||||
this.turnControllers.clear();
|
this.turnControllers.clear();
|
||||||
|
|
@ -687,11 +689,26 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
} else {
|
} else {
|
||||||
this.turnController = turnControllers.get(turnControllers.size() - 1);
|
this.turnController = turnControllers.get(turnControllers.size() - 1);
|
||||||
isGameUnderControl = false;
|
isGameUnderControl = false;
|
||||||
|
addMeToPlayersUnderControl(game, this.turnController);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void removeMeFromPlayersUnderControl(Game game) {
|
||||||
|
game.getPlayers().values().forEach(p -> {
|
||||||
|
p.getPlayersUnderYourControl().remove(this.getId());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addMeToPlayersUnderControl(Game game, UUID newTurnController) {
|
||||||
|
game.getPlayers().values().forEach(p -> {
|
||||||
|
if (p.getId().equals(newTurnController)) {
|
||||||
|
p.getPlayersUnderYourControl().add(this.getId());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endOfTurn(Game game) {
|
public void endOfTurn(Game game) {
|
||||||
this.passedTurn = false;
|
this.passedTurn = false;
|
||||||
|
|
|
||||||
|
|
@ -1434,7 +1434,7 @@ public final class CardUtil {
|
||||||
* @param playerUnderControl
|
* @param playerUnderControl
|
||||||
*/
|
*/
|
||||||
public static void takeControlUnderPlayerEnd(Game game, Ability source, Player controller, Player playerUnderControl) {
|
public static void takeControlUnderPlayerEnd(Game game, Ability source, Player controller, Player playerUnderControl) {
|
||||||
playerUnderControl.setGameUnderYourControl(true, false);
|
playerUnderControl.setGameUnderYourControl(game, true, false);
|
||||||
if (!playerUnderControl.getTurnControlledBy().equals(controller.getId())) {
|
if (!playerUnderControl.getTurnControlledBy().equals(controller.getId())) {
|
||||||
game.informPlayers(controller.getLogName() + " return control of the turn to " + playerUnderControl.getLogName() + CardUtil.getSourceLogName(game, source));
|
game.informPlayers(controller.getLogName() + " return control of the turn to " + playerUnderControl.getLogName() + CardUtil.getSourceLogName(game, source));
|
||||||
controller.getPlayersUnderYourControl().remove(playerUnderControl.getId());
|
controller.getPlayersUnderYourControl().remove(playerUnderControl.getId());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue