Merge pull request #4101 from magefree/phasingFix

Fixed how phasing is implemented
This commit is contained in:
LevelX2 2017-11-02 11:00:33 +01:00 committed by GitHub
commit b4ee3ff1da
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 159 additions and 27 deletions

View file

@ -0,0 +1,85 @@
/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.abilities.effects.common;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
* This class should only be used within the application of another effect
*
* @author TheElk801
*/
public class PhaseOutAllEffect extends OneShotEffect {
private final List<UUID> idList;
public PhaseOutAllEffect(List<UUID> idList) {
super(Outcome.Neutral);
this.idList = idList;
}
public PhaseOutAllEffect(final PhaseOutAllEffect effect) {
super(effect);
this.idList = effect.idList;
}
@Override
public PhaseOutAllEffect copy() {
return new PhaseOutAllEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
// First we phase out everything that isn't attached to anything
// Anything attached to these permanents will phase out indirectly
for (UUID permanentId : idList) {
Permanent permanent = game.getPermanent(permanentId);
if (permanent != null) {
Permanent attachedTo = game.getPermanent(permanent.getAttachedTo());
if (attachedTo == null) {
permanent.phaseOut(game);
}
}
}
// Once this is done, we'll have permanents which are attached to something but haven't phased out
// These will be phased out directly
for (UUID permanentId : idList) {
Permanent permanent = game.getPermanent(permanentId);
if (permanent != null && permanent.isPhasedIn()) {
permanent.phaseOut(game);
}
}
return true;
}
}

View file

@ -78,10 +78,16 @@ public interface Permanent extends Card, Controllable {
boolean isPhasedIn();
boolean isPhasedOutIndirectly();
boolean phaseIn(Game game);
boolean phaseIn(Game game, boolean onlyDirect);
boolean phaseOut(Game game);
boolean phaseOut(Game game, boolean indirectPhase);
boolean isMonstrous();
void setMonstrous(boolean value);

View file

@ -89,6 +89,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
protected boolean controlledFromStartOfControllerTurn;
protected int turnsOnBattlefield;
protected boolean phasedIn = true;
protected boolean indirectPhase = false;
protected boolean faceDown;
protected boolean attacking;
protected int blocking;
@ -138,6 +139,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
this.controlledFromStartOfControllerTurn = permanent.controlledFromStartOfControllerTurn;
this.turnsOnBattlefield = permanent.turnsOnBattlefield;
this.phasedIn = permanent.phasedIn;
this.indirectPhase = permanent.indirectPhase;
this.faceDown = permanent.faceDown;
this.attacking = permanent.attacking;
this.blocking = permanent.blocking;
@ -461,14 +463,32 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
return phasedIn;
}
@Override
public boolean isPhasedOutIndirectly() {
return !phasedIn && indirectPhase;
}
@Override
public boolean phaseIn(Game game) {
return phaseIn(game, true);
}
@Override
public boolean phaseIn(Game game, boolean onlyDirect) {
if (!phasedIn) {
if (!replaceEvent(EventType.PHASE_IN, game)) {
if (!replaceEvent(EventType.PHASE_IN, game)
&& ((onlyDirect && !indirectPhase) || (!onlyDirect))) {
this.phasedIn = true;
this.indirectPhase = false;
if (!game.isSimulation()) {
game.informPlayers(getLogName() + " phased in");
}
for (UUID attachedId : this.getAttachments()) {
Permanent attachedPerm = game.getPermanent(attachedId);
if (attachedPerm != null) {
attachedPerm.phaseIn(game, false);
}
}
fireEvent(EventType.PHASED_IN, game);
return true;
}
@ -478,9 +498,21 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
@Override
public boolean phaseOut(Game game) {
return phaseOut(game, false);
}
@Override
public boolean phaseOut(Game game, boolean indirectPhase) {
if (phasedIn) {
if (!replaceEvent(EventType.PHASE_OUT, game)) {
for (UUID attachedId : this.getAttachments()) {
Permanent attachedPerm = game.getPermanent(attachedId);
if (attachedPerm != null) {
attachedPerm.phaseOut(game, true);
}
}
this.phasedIn = false;
this.indirectPhase = indirectPhase;
if (!game.isSimulation()) {
game.informPlayers(getLogName() + " phased out");
}

View file

@ -1484,16 +1484,15 @@ public abstract class PlayerImpl implements Player, Serializable {
// phasing out is known as phasing out "indirectly." An enchantment or Equipment
// that phased out indirectly won't phase in by itself, but instead phases in
// along with the card it's attached to.
for (UUID attachmentId : permanent.getAttachments()) {
Permanent attachment = game.getPermanent(attachmentId);
if (attachment != null) {
attachment.phaseOut(game);
}
Permanent attachedTo = game.getPermanent(permanent.getAttachedTo());
if (!(attachedTo != null && attachedTo.getControllerId().equals(this.getId()))) {
permanent.phaseOut(game, false);
}
permanent.phaseOut(game);
}
for (Permanent permanent : phasedOut) {
permanent.phaseIn(game);
if (!permanent.isPhasedOutIndirectly()) {
permanent.phaseIn(game);
}
}
}