mirror of
https://github.com/magefree/mage.git
synced 2026-01-23 11:49:56 -08:00
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:
parent
e724166569
commit
3d3358cd05
14 changed files with 279 additions and 149 deletions
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue