mirror of
https://github.com/correl/mage.git
synced 2024-12-26 03:00:11 +00:00
Fix handling of multiple simultaneous control changing effects
This commit is contained in:
parent
c519814f03
commit
bba23e05cb
5 changed files with 53 additions and 39 deletions
|
@ -701,11 +701,22 @@ public class ContinuousEffects implements Serializable {
|
|||
}
|
||||
|
||||
layer = filterLayeredEffects(layerEffects, Layer.ControlChangingEffects_2);
|
||||
for (ContinuousEffect effect: layer) {
|
||||
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
effect.apply(Layer.ControlChangingEffects_2, SubLayer.NA, ability, game);
|
||||
// apply control changing effects multiple times if it's needed
|
||||
// for cases when control over permanents with change control abilities is changed
|
||||
// e.g. Mind Control is controlled by Steal Enchantment
|
||||
while (true) {
|
||||
for (ContinuousEffect effect: layer) {
|
||||
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
effect.apply(Layer.ControlChangingEffects_2, SubLayer.NA, ability, game);
|
||||
}
|
||||
}
|
||||
// if control over all permanent has not changed, we can no longer reapply control changing effects
|
||||
if (!game.getBattlefield().fireControlChangeEvents(game)) {
|
||||
break;
|
||||
}
|
||||
// reset control before reapplying control changing effects
|
||||
game.getBattlefield().resetPermanentsControl();
|
||||
}
|
||||
layer = filterLayeredEffects(layerEffects, Layer.TextChangingEffects_3);
|
||||
for (ContinuousEffect effect: layer) {
|
||||
|
|
|
@ -403,7 +403,6 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
combat.reset();
|
||||
this.reset();
|
||||
effects.apply(game);
|
||||
battlefield.fireControlChangeEvents(game);
|
||||
}
|
||||
|
||||
// Remove End of Combat effects
|
||||
|
|
|
@ -412,18 +412,28 @@ public class Battlefield implements Serializable {
|
|||
return phasedOut;
|
||||
}
|
||||
|
||||
public void resetPermanentsControl() {
|
||||
for (Permanent perm: field.values()) {
|
||||
if (perm.isPhasedIn()) {
|
||||
perm.resetControl();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* since control could change several times during applyEvents we only want to fire
|
||||
* control changed events after all control change effects have been applied
|
||||
*
|
||||
* @param game
|
||||
*/
|
||||
public void fireControlChangeEvents(Game game) {
|
||||
public boolean fireControlChangeEvents(Game game) {
|
||||
boolean controlChanged = false;
|
||||
for (Permanent perm: field.values()) {
|
||||
if (perm.isPhasedIn()) {
|
||||
perm.checkControlChanged(game);
|
||||
controlChanged |= perm.checkControlChanged(game);
|
||||
}
|
||||
}
|
||||
return controlChanged;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -76,7 +76,6 @@ public interface Permanent extends Card, Controllable {
|
|||
boolean addAttachment(UUID permanentId, Game game);
|
||||
boolean removeAttachment(UUID permanentId, Game game);
|
||||
|
||||
boolean changeControllerId(UUID controllerId, Game game);
|
||||
boolean canBeTargetedBy(MageObject source, UUID controllerId, Game game);
|
||||
boolean hasProtectionFrom(MageObject source, Game game);
|
||||
boolean hasSummoningSickness();
|
||||
|
@ -119,9 +118,12 @@ public interface Permanent extends Card, Controllable {
|
|||
void setLoyaltyUsed(boolean used);
|
||||
boolean isLoyaltyUsed();
|
||||
|
||||
public void resetControl();
|
||||
boolean changeControllerId(UUID controllerId, Game game);
|
||||
boolean checkControlChanged(Game game);
|
||||
|
||||
void beginningOfTurn(Game game);
|
||||
void endOfTurn(Game game);
|
||||
void checkControlChanged(Game game);
|
||||
int getTurnsOnBattlefield();
|
||||
|
||||
void addPower(int power);
|
||||
|
|
|
@ -80,7 +80,6 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
protected UUID originalControllerId;
|
||||
protected UUID controllerId;
|
||||
protected UUID beforeResetControllerId;
|
||||
protected boolean controllerChanged;
|
||||
protected int damage;
|
||||
protected boolean controlledFromStartOfControllerTurn;
|
||||
protected int turnsOnBattlefield;
|
||||
|
@ -169,9 +168,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
*/
|
||||
@Override
|
||||
public void reset(Game game) {
|
||||
this.beforeResetControllerId = this.controllerId;
|
||||
this.controllerId = originalControllerId;
|
||||
controllerChanged = !controllerId.equals(beforeResetControllerId);
|
||||
this.resetControl();
|
||||
this.maxBlocks = 1;
|
||||
this.minBlockedBy = 1;
|
||||
this.maxBlockedBy = 0;
|
||||
|
@ -448,42 +445,37 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
|||
return this.controllerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetControl() {
|
||||
this.beforeResetControllerId = this.controllerId;
|
||||
this.controllerId = this.originalControllerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean changeControllerId(UUID controllerId, Game game) {
|
||||
if (!controllerId.equals(this.controllerId)) {
|
||||
Player newController = game.getPlayer(controllerId);
|
||||
if (newController != null && (!newController.hasLeft() || !newController.hasLost())) {
|
||||
// changeControllerId can be called by continuous effect
|
||||
// so it will lead to this.controlledFromStartOfControllerTurn set to false over and over
|
||||
// because of reset(game) method called before applying effect as state-based action
|
||||
// that changes this.controllerId to original one (actually owner)
|
||||
if (!controllerId.equals(beforeResetControllerId)) {
|
||||
this.removeFromCombat(game);
|
||||
this.controlledFromStartOfControllerTurn = false;
|
||||
this.controllerChanged = true;
|
||||
} else {
|
||||
this.controllerChanged = false;
|
||||
}
|
||||
this.controllerId = controllerId;
|
||||
this.abilities.setControllerId(controllerId);
|
||||
game.getContinuousEffects().setController(this.objectId, controllerId);
|
||||
return true;
|
||||
}
|
||||
Player newController = game.getPlayer(controllerId);
|
||||
if (newController != null && (!newController.hasLeft() || !newController.hasLost())) {
|
||||
this.controllerId = controllerId;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkControlChanged(Game game) {
|
||||
if (this.controllerChanged) {
|
||||
public boolean checkControlChanged(Game game) {
|
||||
if (!controllerId.equals(beforeResetControllerId)) {
|
||||
this.removeFromCombat(game);
|
||||
this.controlledFromStartOfControllerTurn = false;
|
||||
|
||||
this.abilities.setControllerId(controllerId);
|
||||
game.getContinuousEffects().setController(objectId, controllerId);
|
||||
|
||||
game.fireEvent(new GameEvent(EventType.LOST_CONTROL, objectId, objectId, beforeResetControllerId));
|
||||
// reset the original controller to abilities and ContinuousEffects
|
||||
if (controllerId.equals(originalControllerId)) {
|
||||
this.abilities.setControllerId(controllerId);
|
||||
game.getContinuousEffects().setController(this.objectId, controllerId);
|
||||
}
|
||||
game.fireEvent(new GameEvent(EventType.GAINED_CONTROL, objectId, objectId, controllerId));
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in a new issue