game: turn modification improves:

- fixed miss phase changed events and logs in some use cases;
 - added source info in turn modification logs;
 - added game logs for take and lost control of the spell (example: Word of Command)
 - added game logs for skip step;
 - added game logs for extra step;
 - added game logs for skip phase;
This commit is contained in:
Oleg Agafonov 2023-08-01 16:20:12 +04:00
parent e724166569
commit 3d3358cd05
14 changed files with 279 additions and 149 deletions

View file

@ -1049,7 +1049,10 @@ public abstract class GameImpl implements Game {
Player extraPlayer = this.getPlayer(extraTurn.getPlayerId());
if (extraPlayer != null && extraPlayer.canRespond()) {
state.setExtraTurnId(extraTurn.getId());
informPlayers(extraPlayer.getLogName() + " takes an extra turn");
informPlayers(String.format("%s takes an extra turn%s",
extraPlayer.getLogName(),
extraTurn.getInfo()
));
if (!playTurn(extraPlayer)) {
return false;
}
@ -1066,7 +1069,8 @@ public abstract class GameImpl implements Game {
private TurnMod useNextExtraTurn() {
boolean checkForExtraTurn = true;
while (checkForExtraTurn) {
TurnMod extraTurn = getState().getTurnMods().getNextExtraTurn();
// user's logs generated in parent method
TurnMod extraTurn = getState().getTurnMods().useNextExtraTurn();
if (extraTurn != null) {
GameEvent event = new GameEvent(GameEvent.EventType.EXTRA_TURN, extraTurn.getId(), null, extraTurn.getPlayerId());
if (!replaceEvent(event)) {
@ -1715,8 +1719,8 @@ public abstract class GameImpl implements Game {
// for Word of Command
Spell spell = getSpellOrLKIStack(topId);
if (spell != null) {
if (spell.getCommandedBy() != null) {
UUID commandedBy = spell.getCommandedBy();
if (spell.getCommandedByPlayerId() != null) {
UUID commandedBy = spell.getCommandedByPlayerId();
UUID spellControllerId;
if (commandedBy.equals(spell.getControllerId())) {
spellControllerId = spell.getSpellAbility().getFirstTarget(); // i.e. resolved spell is Word of Command
@ -1736,7 +1740,7 @@ public abstract class GameImpl implements Game {
}
}
}
spell.setCommandedBy(null);
spell.setCommandedBy(null, null);
}
}
}

View file

@ -61,7 +61,8 @@ public class Spell extends StackObjectImpl implements Card {
private boolean faceDown;
private boolean countered;
private boolean resolving = false;
private UUID commandedBy = null; // for Word of Command
private UUID commandedByPlayerId = null; // controller of the spell resolve, example: Word of Command
private String commandedByInfo; // info about spell commanded, e.g. source
private int startingLoyalty;
private int startingDefense;
@ -132,7 +133,8 @@ public class Spell extends StackObjectImpl implements Card {
this.faceDown = spell.faceDown;
this.countered = spell.countered;
this.resolving = spell.resolving;
this.commandedBy = spell.commandedBy;
this.commandedByPlayerId = spell.commandedByPlayerId;
this.commandedByInfo = spell.commandedByInfo;
this.currentActivatingManaAbilitiesStep = spell.currentActivatingManaAbilitiesStep;
this.targetChanged = spell.targetChanged;
@ -240,12 +242,16 @@ public class Spell extends StackObjectImpl implements Card {
return false;
}
this.resolving = true;
if (commandedBy != null && !commandedBy.equals(getControllerId())) {
Player turnController = game.getPlayer(commandedBy);
if (turnController != null) {
turnController.controlPlayersTurn(game, controller.getId());
// setup new turn controller for spell's resolve, example: Word of Command
// original controller will be reset after spell's resolve
if (commandedByPlayerId != null && !commandedByPlayerId.equals(getControllerId())) {
Player newTurnController = game.getPlayer(commandedByPlayerId);
if (newTurnController != null) {
newTurnController.controlPlayersTurn(game, controller.getId(), commandedByInfo);
}
}
if (this.isInstantOrSorcery(game)) {
int index = 0;
result = false;
@ -1122,12 +1128,23 @@ public class Spell extends StackObjectImpl implements Card {
throw new UnsupportedOperationException("Not supported."); //To change body of generated methods, choose Tools | Templates.
}
public void setCommandedBy(UUID playerId) {
this.commandedBy = playerId;
/**
* Add temporary turn controller while resolving (e.g. all choices will be made by another player)
* Example: Word of Command
* @param newTurnControllerId
* @param info additional info for game logs
*/
public void setCommandedBy(UUID newTurnControllerId, String info) {
this.commandedByPlayerId = newTurnControllerId;
this.commandedByInfo = info;
}
public UUID getCommandedBy() {
return commandedBy;
public UUID getCommandedByPlayerId() {
return commandedByPlayerId;
}
public String getCommandedByInfo() {
return commandedByInfo == null ? "" : commandedByInfo;
}
@Override

View file

@ -1,19 +1,19 @@
package mage.game.turn;
import mage.constants.PhaseStep;
import mage.constants.TurnPhase;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.players.Player;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import mage.constants.PhaseStep;
import mage.constants.TurnPhase;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public abstract class Phase implements Serializable {
@ -81,15 +81,25 @@ public abstract class Phase implements Serializable {
if (game.isPaused() || game.checkIfGameIsOver()) {
return false;
}
if (game.getTurn().isEndTurnRequested() && step.getType()!=PhaseStep.CLEANUP) {
if (game.getTurn().isEndTurnRequested() && step.getType() != PhaseStep.CLEANUP) {
continue;
}
currentStep = step;
if (!game.getState().getTurnMods().skipStep(activePlayerId, getStep().getType())) {
TurnMod skipStepMod = game.getState().getTurnMods().useNextSkipStep(activePlayerId, getStep().getType());
if (skipStepMod == null) {
playStep(game);
if (game.executingRollback()) {
return true;
}
} else {
Player player = game.getPlayer(skipStepMod.getPlayerId());
if (player != null) {
game.informPlayers(String.format("%s skips %s step%s",
player.getLogName(),
skipStepMod.getSkipStep().toString(),
skipStepMod.getInfo()
));
}
}
if (!game.isSimulation() && checkStopOnStepOption(game)) {
return false;
@ -135,11 +145,21 @@ public abstract class Phase implements Serializable {
return false;
}
currentStep = step;
if (!game.getState().getTurnMods().skipStep(activePlayerId, currentStep.getType())) {
TurnMod skipStepMod = game.getState().getTurnMods().useNextSkipStep(activePlayerId, currentStep.getType());
if (skipStepMod == null) {
playStep(game);
if (game.executingRollback()) {
return true;
}
} else {
Player player = game.getPlayer(skipStepMod.getPlayerId());
if (player != null) {
game.informPlayers(String.format("%s skips %s step%s",
player.getLogName(),
skipStepMod.getSkipStep().toString(),
skipStepMod.getInfo()
));
}
}
}
@ -219,12 +239,22 @@ public abstract class Phase implements Serializable {
private void playExtraSteps(Game game, PhaseStep afterStep) {
while (true) {
Step extraStep = game.getState().getTurnMods().extraStep(activePlayerId, afterStep);
if (extraStep == null) {
TurnMod extraStepMod = game.getState().getTurnMods().useNextExtraStep(activePlayerId, afterStep);
if (extraStepMod == null) {
return;
}
currentStep = extraStepMod.getExtraStep();
Player player = game.getPlayer(extraStepMod.getPlayerId());
if (player != null && player.canRespond()) {
game.informPlayers(String.format("%s takes an extra %s step%s",
player.getLogName(),
extraStepMod.getExtraStep().toString(),
extraStepMod.getInfo()
));
playStep(game);
} else {
return;
}
currentStep = extraStep;
playStep(game);
}
}

View file

@ -99,9 +99,12 @@ public class Turn implements Serializable {
return false;
}
if (game.getState().getTurnMods().skipTurn(activePlayer.getId())) {
game.informPlayers(activePlayer.getLogName() + " skips their turn.");
TurnMod skipTurnMod = game.getState().getTurnMods().useNextSkipTurn(activePlayer.getId());
if (skipTurnMod != null) {
game.informPlayers(String.format("%s skips their turn%s",
activePlayer.getLogName(),
skipTurnMod.getInfo()
));
return true;
}
logStartOfTurn(game, activePlayer);
@ -119,15 +122,25 @@ public class Turn implements Serializable {
continue;
}
currentPhase = phase;
TurnMod skipPhaseMod = game.getState().getTurnMods().useNextSkipPhase(activePlayer.getId(), currentPhase.getType());
if (skipPhaseMod != null) {
game.informPlayers(String.format("%s skips %s phase%s",
activePlayer.getLogName(),
currentPhase.getType(),
skipPhaseMod.getInfo()
));
continue;
}
game.fireEvent(new PhaseChangedEvent(activePlayer.getId(), null));
if (game.getState().getTurnMods().skipPhase(
activePlayer.getId(), currentPhase.getType()
) || !phase.play(game, activePlayer.getId())) {
if (!phase.play(game, activePlayer.getId())) {
continue;
}
if (game.executingRollback()) {
return false;
}
//20091005 - 500.4/703.4n
game.emptyManaPools(null);
game.saveState(false);
@ -140,39 +153,66 @@ public class Turn implements Serializable {
public void resumePlay(Game game, boolean wasPaused) {
activePlayerId = game.getActivePlayerId();
Player activePlayer = game.getPlayer(activePlayerId);
UUID priorityPlayerId = game.getPriorityPlayerId();
TurnPhase phaseType = game.getTurnPhaseType();
PhaseStep stepType = game.getTurnStepType();
TurnPhase needPhaseType = game.getTurnPhaseType();
PhaseStep needStepType = game.getTurnStepType();
Iterator<Phase> it = phases.iterator();
Phase phase;
Phase nextPhase;
do {
phase = it.next();
currentPhase = phase;
} while (phase.type != phaseType);
if (phase.resumePlay(game, stepType, wasPaused)) {
//20091005 - 500.4/703.4n
game.emptyManaPools(null);
//game.saveState();
//20091005 - 500.8
playExtraPhases(game, phase.getType());
}
while (it.hasNext()) {
phase = it.next();
nextPhase = it.next();
} while (nextPhase.type != needPhaseType);
// play first phase
TurnMod skipPhaseMod = game.getState().getTurnMods().useNextSkipPhase(activePlayerId, nextPhase.getType());
if (skipPhaseMod != null && activePlayer != null) {
game.informPlayers(String.format("%s skips %s phase%s",
activePlayer.getLogName(),
nextPhase.getType(),
skipPhaseMod.getInfo()
));
} else {
if (game.isPaused() || game.checkIfGameIsOver()) {
return;
}
currentPhase = phase;
if (!game.getState().getTurnMods().skipPhase(activePlayerId, currentPhase.getType())) {
if (phase.play(game, activePlayerId)) {
currentPhase = nextPhase;
game.fireEvent(new PhaseChangedEvent(activePlayerId, null));
if (nextPhase.resumePlay(game, needStepType, wasPaused)) {
//20091005 - 500.4/703.4n
game.emptyManaPools(null);
//20091005 - 500.8
playExtraPhases(game, nextPhase.getType());
}
}
// play all other phases
while (it.hasNext()) {
nextPhase = it.next();
if (game.isPaused() || game.checkIfGameIsOver()) {
return;
}
skipPhaseMod = game.getState().getTurnMods().useNextSkipPhase(activePlayerId, nextPhase.getType());
if (skipPhaseMod != null && activePlayer != null) {
game.informPlayers(String.format("%s skips %s phase%s",
activePlayer.getLogName(),
nextPhase.getType(),
skipPhaseMod.getInfo()
));
} else {
currentPhase = nextPhase;
game.fireEvent(new PhaseChangedEvent(activePlayerId, null));
if (nextPhase.play(game, activePlayerId)) {
//20091005 - 500.4/703.4n
game.emptyManaPools(null);
//game.saveState();
//20091005 - 500.8
playExtraPhases(game, phase.getType());
playExtraPhases(game, nextPhase.getType());
}
}
if (!currentPhase.equals(phase)) { // phase was changed from the card
// TODO: old code, can't find any usage of turn's phase change by events/cards
// so it must be research and removed as outdated (maybe rollback or playExtraPhases related?)
if (!currentPhase.equals(nextPhase)) { // phase was changed from the card
game.fireEvent(new PhaseChangedEvent(activePlayerId, null));
break;
}
@ -180,9 +220,10 @@ public class Turn implements Serializable {
}
private void checkTurnIsControlledByOtherPlayer(Game game, UUID activePlayerId) {
UUID newControllerId = game.getState().getTurnMods().controlsTurn(activePlayerId);
if (newControllerId != null && !newControllerId.equals(activePlayerId)) {
game.getPlayer(newControllerId).controlPlayersTurn(game, activePlayerId);
TurnMod newControllerMod = game.getState().getTurnMods().useNextNewController(activePlayerId);
if (newControllerMod != null && !newControllerMod.getNewControllerId().equals(activePlayerId)) {
// game logs added in child's call (controlPlayersTurn)
game.getPlayer(newControllerMod.getNewControllerId()).controlPlayersTurn(game, activePlayerId, newControllerMod.getInfo());
}
}
@ -194,13 +235,13 @@ public class Turn implements Serializable {
private boolean playExtraPhases(Game game, TurnPhase afterPhase) {
while (true) {
TurnMod extraPhaseTurnMod = game.getState().getTurnMods().extraPhase(activePlayerId, afterPhase);
if (extraPhaseTurnMod == null) {
TurnMod extraPhaseMod = game.getState().getTurnMods().useNextExtraPhase(activePlayerId, afterPhase);
if (extraPhaseMod == null) {
return false;
}
TurnPhase extraPhase = extraPhaseTurnMod.getExtraPhase();
TurnPhase extraPhase = extraPhaseMod.getExtraPhase();
if (extraPhase == null) {
return false;
throw new IllegalStateException("Wrong code usage: miss data in turn mod's extra phase - " + extraPhaseMod.getInfo());
}
Phase phase;
switch (extraPhase) {
@ -216,26 +257,33 @@ public class Turn implements Serializable {
case POSTCOMBAT_MAIN:
phase = new PostCombatMainPhase();
break;
default:
case END:
phase = new EndPhase();
break;
default:
throw new IllegalArgumentException("Unknown phase type: " + extraPhase);
}
currentPhase = phase;
game.fireEvent(new PhaseChangedEvent(activePlayerId, extraPhaseTurnMod));
game.fireEvent(new PhaseChangedEvent(activePlayerId, extraPhaseMod));
Player activePlayer = game.getPlayer(activePlayerId);
if (activePlayer != null && !game.isSimulation()) {
game.informPlayers(activePlayer.getLogName() + " starts an additional " + phase.getType().toString() + " phase");
if (activePlayer != null) {
game.informPlayers(String.format("%s starts an additional %s phase%s",
activePlayer.getLogName(),
phase.getType().toString(),
extraPhaseMod.getInfo()
));
}
phase.play(game, activePlayerId);
// TODO: is it lost extra phase on multiple phases here?
// example:
// - mods contains 2 mods for same main phases
// - one played and afterPhase take main phase value
// - so it can't find a second mod
afterPhase = extraPhase;
}
}
/*protected void playExtraTurns(Game game) {
while (game.getState().getTurnMods().extraTurn(activePlayerId)) {
this.play(game, activePlayerId);
}
}*/
/**
* Used for some spells with end turn effect (e.g. Time Stop).
*

View file

@ -1,7 +1,10 @@
package mage.game.turn;
import mage.abilities.Ability;
import mage.constants.PhaseStep;
import mage.constants.TurnPhase;
import mage.game.Game;
import mage.util.CardUtil;
import mage.util.Copyable;
import java.io.Serializable;
@ -11,12 +14,13 @@ import java.util.UUID;
* Creates a signle turn modification for turn, phase or step
* <p>
* For one time usage only
* For current turn only
* <p>
* If you need it in continuous effect then use ContinuousRuleModifyingEffectImpl
* with game events like UNTAP_STEP (example: Sands of Time)
* <p>
* Supports:
* - new controller
* - new turn controller
* - turn: extra and skip
* - phase: extra and skip
* - step: extra and skip
@ -43,7 +47,8 @@ public class TurnMod implements Serializable, Copyable<TurnMod> {
private PhaseStep afterStep;
private boolean locked = false; // locked for modification, used for wrong code usage protection
private String note;
private String tag; // for inner usage like enable/disable mod in effects
private String info; // for GUI usage like additional info in logs
// Turn mod that should be applied after current turn mod
// Implemented only for new controller turn mod
@ -66,7 +71,8 @@ public class TurnMod implements Serializable, Copyable<TurnMod> {
if (mod.subsequentTurnMod != null) {
this.subsequentTurnMod = mod.subsequentTurnMod.copy();
}
this.note = mod.note;
this.tag = mod.tag;
this.info = mod.info;
this.locked = mod.locked;
}
@ -144,11 +150,24 @@ public class TurnMod implements Serializable, Copyable<TurnMod> {
return this;
}
public TurnMod withNote(String note) {
this.note = note;
public TurnMod withTag(String tag) {
this.tag = tag;
return this;
}
public String getTag() {
return tag;
}
public TurnMod withInfo(String info) {
this.info = info;
return this;
}
public String getInfo() {
return info == null ? "" : info;
}
public UUID getPlayerId() {
return playerId;
}
@ -197,11 +216,11 @@ public class TurnMod implements Serializable, Copyable<TurnMod> {
return subsequentTurnMod;
}
public String getNote() {
return note;
}
public boolean isLocked() {
return locked;
}
private void addSourceAsInfo(Game game, Ability source) {
this.info = CardUtil.getSourceLogName(game, source);
}
}

View file

@ -1,12 +1,13 @@
package mage.game.turn;
import mage.constants.PhaseStep;
import mage.constants.TurnPhase;
import mage.util.Copyable;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.ListIterator;
import java.util.UUID;
import mage.constants.PhaseStep;
import mage.constants.TurnPhase;
import mage.util.Copyable;
/**
* Turn, phase and step modification for extra/skip (use it for one time mod only)
@ -36,7 +37,7 @@ public class TurnMods extends ArrayList<TurnMod> implements Serializable, Copyab
return super.add(turnMod);
}
public TurnMod getNextExtraTurn() {
public TurnMod useNextExtraTurn() {
ListIterator<TurnMod> it = this.listIterator(this.size());
while (it.hasPrevious()) {
TurnMod turnMod = it.previous();
@ -48,29 +49,32 @@ public class TurnMods extends ArrayList<TurnMod> implements Serializable, Copyab
return null;
}
public boolean skipTurn(UUID playerId) {
public TurnMod useNextSkipTurn(UUID playerId) {
ListIterator<TurnMod> it = this.listIterator(this.size());
while (it.hasPrevious()) {
TurnMod turnMod = it.previous();
if (turnMod.isSkipTurn() && turnMod.getPlayerId().equals(playerId)) {
it.remove();
return true;
return turnMod;
}
}
return false;
return null;
}
public UUID controlsTurn(UUID playerId) {
public TurnMod useNextNewController(UUID playerId) {
TurnMod lastNewControllerMod = null;
// find last/actual mod
ListIterator<TurnMod> it = this.listIterator(this.size());
TurnMod controlPlayerTurnMod = null;
while (it.hasPrevious()) {
TurnMod turnMod = it.previous();
if (turnMod.getNewControllerId() != null && turnMod.getPlayerId().equals(playerId)) {
controlPlayerTurnMod = turnMod;
lastNewControllerMod = turnMod;
it.remove();
}
}
// now delete all other effects that control current active player - control next turn of player effects are not cumulative
// delete all other outdated mods
it = this.listIterator(this.size());
while (it.hasPrevious()) {
TurnMod turnMod = it.previous();
@ -78,26 +82,28 @@ public class TurnMods extends ArrayList<TurnMod> implements Serializable, Copyab
it.remove();
}
}
// apply subsequent turn mod
if (controlPlayerTurnMod != null && controlPlayerTurnMod.getSubsequentTurnMod() != null) {
this.add(controlPlayerTurnMod.getSubsequentTurnMod());
// add subsequent turn mod to execute after current
if (lastNewControllerMod != null && lastNewControllerMod.getSubsequentTurnMod() != null) {
this.add(lastNewControllerMod.getSubsequentTurnMod());
}
return controlPlayerTurnMod != null ? controlPlayerTurnMod.getNewControllerId() : null;
return lastNewControllerMod;
}
public Step extraStep(UUID playerId, PhaseStep afterStep) {
public TurnMod useNextExtraStep(UUID playerId, PhaseStep afterStep) {
ListIterator<TurnMod> it = this.listIterator(this.size());
while (it.hasPrevious()) {
TurnMod turnMod = it.previous();
if (turnMod.getExtraStep() != null && turnMod.getPlayerId().equals(playerId) && (turnMod.getAfterStep() == null || turnMod.getAfterStep() == afterStep)) {
it.remove();
return turnMod.getExtraStep();
return turnMod;
}
}
return null;
}
public boolean skipStep(UUID playerId, PhaseStep step) {
public TurnMod useNextSkipStep(UUID playerId, PhaseStep step) {
if (step != null) {
ListIterator<TurnMod> it = this.listIterator(this.size());
while (it.hasPrevious()) {
@ -106,20 +112,22 @@ public class TurnMods extends ArrayList<TurnMod> implements Serializable, Copyab
if (turnMod.getPlayerId() != null && turnMod.getPlayerId().equals(playerId)) {
if (turnMod.getSkipStep() == step) {
it.remove();
return true;
return turnMod;
}
}
}
}
}
return false;
return null;
}
public TurnMod extraPhase(UUID playerId, TurnPhase afterPhase) {
public TurnMod useNextExtraPhase(UUID playerId, TurnPhase afterPhase) {
ListIterator<TurnMod> it = this.listIterator(this.size());
while (it.hasPrevious()) {
TurnMod turnMod = it.previous();
if (turnMod.getExtraPhase() != null && turnMod.getPlayerId().equals(playerId) && (turnMod.getAfterPhase() == null || turnMod.getAfterPhase() == afterPhase)) {
if (turnMod.getExtraPhase() != null
&& turnMod.getPlayerId().equals(playerId)
&& (turnMod.getAfterPhase() == null || turnMod.getAfterPhase() == afterPhase)) {
it.remove();
return turnMod;
}
@ -127,15 +135,15 @@ public class TurnMods extends ArrayList<TurnMod> implements Serializable, Copyab
return null;
}
public boolean skipPhase(UUID playerId, TurnPhase phase) {
public TurnMod useNextSkipPhase(UUID playerId, TurnPhase phase) {
ListIterator<TurnMod> it = this.listIterator(this.size());
while (it.hasPrevious()) {
TurnMod turnMod = it.previous();
if (turnMod.getSkipPhase() != null && turnMod.getPlayerId().equals(playerId) && turnMod.getSkipPhase() == phase) {
it.remove();
return true;
return turnMod;
}
}
return false;
return null;
}
}

View file

@ -321,9 +321,10 @@ public interface Player extends MageItem, Copyable<Player> {
* Defines player whose turn this player controls at the moment.
*
* @param game
* @param playerId
* @param playerUnderControlId
* @param info additional info to show in game logs like source
*/
void controlPlayersTurn(Game game, UUID playerId);
void controlPlayersTurn(Game game, UUID playerUnderControlId, String info);
/**
* Sets player {@link UUID} who controls this player's turn.

View file

@ -547,17 +547,17 @@ public abstract class PlayerImpl implements Player, Serializable {
}
@Override
public void controlPlayersTurn(Game game, UUID playerId) {
Player player = game.getPlayer(playerId);
player.setTurnControlledBy(this.getId());
game.informPlayers(getLogName() + " controls the turn of " + player.getLogName());
if (!playerId.equals(this.getId())) {
this.playersUnderYourControl.add(playerId);
if (!player.hasLeft() && !player.hasLost()) {
player.setGameUnderYourControl(false);
public void controlPlayersTurn(Game game, UUID playerUnderControlId, String info) {
Player playerUnderControl = game.getPlayer(playerUnderControlId);
playerUnderControl.setTurnControlledBy(this.getId());
game.informPlayers(getLogName() + " taken turn control of " + playerUnderControl.getLogName() + info);
if (!playerUnderControlId.equals(this.getId())) {
this.playersUnderYourControl.add(playerUnderControlId);
if (!playerUnderControl.hasLeft() && !playerUnderControl.hasLost()) {
playerUnderControl.setGameUnderYourControl(false);
}
DelayedTriggeredAbility ability = new AtTheEndOfTurnStepPostDelayedTriggeredAbility(
new LoseControlOnOtherPlayersControllerEffect(this.getLogName(), player.getLogName()));
new LoseControlOnOtherPlayersControllerEffect(this.getLogName(), playerUnderControl.getLogName()));
ability.setSourceId(getId());
ability.setControllerId(getId());
game.addDelayedTriggeredAbility(ability, null);
@ -2666,7 +2666,8 @@ public abstract class PlayerImpl implements Player, Serializable {
// P.S. no needs in searchingController, but it helps with unit tests, see TakeControlWhileSearchingLibraryTest
boolean takeControl = false;
if (!searchingPlayer.getId().equals(searchingController.getId())) {
CardUtil.takeControlUnderPlayerStart(game, searchingController, searchingPlayer, true);
// game logs added in child's call
CardUtil.takeControlUnderPlayerStart(game, source, searchingController, searchingPlayer, true);
takeControl = true;
}
@ -2711,8 +2712,8 @@ public abstract class PlayerImpl implements Player, Serializable {
// END SEARCH
if (takeControl) {
CardUtil.takeControlUnderPlayerEnd(game, searchingController, searchingPlayer);
game.informPlayers("Control of " + searchingPlayer.getLogName() + " is back" + CardUtil.getSourceLogName(game, source));
// game logs added in child's call
CardUtil.takeControlUnderPlayerEnd(game, source, searchingController, searchingPlayer);
}
LibrarySearchedEvent searchedEvent = new LibrarySearchedEvent(targetPlayer.getId(), source, searchingPlayer.getId(), target);

View file

@ -1157,14 +1157,15 @@ public final class CardUtil {
*
* @param game
* @param controller
* @param targetPlayer
* @param playerUnderControl
* @param givePauseForResponse if you want to give controller time to watch opponent's hand (if you remove control effect in the end of code)
*/
public static void takeControlUnderPlayerStart(Game game, Player controller, Player targetPlayer, boolean givePauseForResponse) {
controller.controlPlayersTurn(game, targetPlayer.getId());
public static void takeControlUnderPlayerStart(Game game, Ability source, Player controller, Player playerUnderControl, boolean givePauseForResponse) {
// game logs added in child's call
controller.controlPlayersTurn(game, playerUnderControl.getId(), CardUtil.getSourceLogName(game, source));
if (givePauseForResponse) {
while (controller.canRespond()) {
if (controller.chooseUse(Outcome.Benefit, "You got control of " + targetPlayer.getLogName()
if (controller.chooseUse(Outcome.Benefit, "You got control of " + playerUnderControl.getLogName()
+ ". Use switch hands button to view opponent's hand.", null,
"Continue", "Wait", null, game)) {
break;
@ -1178,12 +1179,13 @@ public final class CardUtil {
*
* @param game
* @param controller
* @param targetPlayer
* @param playerUnderControl
*/
public static void takeControlUnderPlayerEnd(Game game, Player controller, Player targetPlayer) {
targetPlayer.setGameUnderYourControl(true, false);
if (!targetPlayer.getTurnControlledBy().equals(controller.getId())) {
controller.getPlayersUnderYourControl().remove(targetPlayer.getId());
public static void takeControlUnderPlayerEnd(Game game, Ability source, Player controller, Player playerUnderControl) {
playerUnderControl.setGameUnderYourControl(true, false);
if (!playerUnderControl.getTurnControlledBy().equals(controller.getId())) {
game.informPlayers(controller + " return control of the turn to " + playerUnderControl.getLogName() + CardUtil.getSourceLogName(game, source));
controller.getPlayersUnderYourControl().remove(playerUnderControl.getId());
}
}