Merge pull request #4734 from spjspj/master

Beginning of implementation of Planechase.
This commit is contained in:
LevelX2 2018-04-10 10:45:26 +02:00 committed by GitHub
commit 8bee825d5c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 2239 additions and 23 deletions

View file

@ -112,7 +112,7 @@ public class DialogContainer extends JPanel {
backgroundColor = new Color(0, 0, 50, 110); backgroundColor = new Color(0, 0, 50, 110);
alpha = 0; alpha = 0;
ChoiceDialog dlg = new ChoiceDialog(params, "Command Zone (Commander and Emblems)"); ChoiceDialog dlg = new ChoiceDialog(params, "Command Zone (Commander, Emblems and Planes)");
add(dlg); add(dlg);
dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10);
dlg.updateSize(params.rect.width - 80, params.rect.height - 80); dlg.updateSize(params.rect.width - 80, params.rect.height - 80);

View file

@ -46,7 +46,6 @@ import mage.game.Game;
import mage.game.command.Emblem; import mage.game.command.Emblem;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentToken; import mage.game.permanent.PermanentToken;
import mage.game.permanent.token.TokenImpl;
import mage.game.permanent.token.Token; import mage.game.permanent.token.Token;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.game.stack.StackAbility; import mage.game.stack.StackAbility;
@ -55,6 +54,7 @@ import mage.target.Targets;
import mage.util.SubTypeList; import mage.util.SubTypeList;
import com.google.gson.annotations.Expose; import com.google.gson.annotations.Expose;
import mage.game.command.Plane;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
@ -521,6 +521,13 @@ public class CardView extends SimpleCardView {
Emblem emblem = (Emblem) object; Emblem emblem = (Emblem) object;
this.rarity = Rarity.SPECIAL; this.rarity = Rarity.SPECIAL;
this.rules = emblem.getAbilities().getRules(emblem.getName()); this.rules = emblem.getAbilities().getRules(emblem.getName());
} else if (object instanceof Plane) {
this.mageObjectType = MageObjectType.PLANE;
Plane plane = (Plane) object;
this.rarity = Rarity.SPECIAL;
// Display in landscape/rotated/on its side
this.rotate = true;
this.rules = plane.getAbilities().getRules(plane.getName());
} }
if (this.rarity == null && object instanceof StackAbility) { if (this.rarity == null && object instanceof StackAbility) {
StackAbility stackAbility = (StackAbility) object; StackAbility stackAbility = (StackAbility) object;
@ -557,6 +564,21 @@ public class CardView extends SimpleCardView {
this.rarity = Rarity.COMMON; this.rarity = Rarity.COMMON;
} }
public CardView(PlaneView plane) {
this(true);
this.gameObject = true;
this.id = plane.getId();
this.mageObjectType = MageObjectType.EMBLEM;
this.name = plane.getName();
this.displayName = name;
this.rules = plane.getRules();
// Display the plane in landscape (similar to Fused cards)
this.rotate = true;
this.frameStyle = FrameStyle.MPRP_FULL_ART_BASIC;
this.expansionSetCode = plane.getExpansionSetCode();
this.rarity = Rarity.COMMON;
}
public CardView(Designation designation, StackAbility stackAbility) { public CardView(Designation designation, StackAbility stackAbility) {
this(true); this(true);
this.gameObject = true; this.gameObject = true;

View file

@ -40,6 +40,7 @@ import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.GameState; import mage.game.GameState;
import mage.game.command.Emblem; import mage.game.command.Emblem;
import mage.game.command.Plane;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentToken; import mage.game.permanent.PermanentToken;
import mage.target.targetpointer.TargetPointer; import mage.target.targetpointer.TargetPointer;
@ -118,6 +119,9 @@ public class CardsView extends LinkedHashMap<UUID, CardView> {
abilityView = new AbilityView(ability, sourceObject.getName(), new CardView(new EmblemView((Emblem) sourceObject))); abilityView = new AbilityView(ability, sourceObject.getName(), new CardView(new EmblemView((Emblem) sourceObject)));
abilityView.setName(((Emblem) sourceObject).getName()); abilityView.setName(((Emblem) sourceObject).getName());
// abilityView.setExpansionSetCode(sourceCard.getExpansionSetCode()); // abilityView.setExpansionSetCode(sourceCard.getExpansionSetCode());
} else if (sourceObject instanceof Plane) {
abilityView = new AbilityView(ability, sourceObject.getName(), new CardView(new PlaneView((Plane) sourceObject)));
abilityView.setName(((Plane) sourceObject).getName());
} }
break; break;
} }

View file

@ -47,6 +47,7 @@ import mage.game.Game;
import mage.game.GameState; import mage.game.GameState;
import mage.game.combat.CombatGroup; import mage.game.combat.CombatGroup;
import mage.game.command.Emblem; import mage.game.command.Emblem;
import mage.game.command.Plane;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentCard; import mage.game.permanent.PermanentCard;
import mage.game.permanent.PermanentToken; import mage.game.permanent.PermanentToken;
@ -139,6 +140,12 @@ public class GameView implements Serializable {
stack.put(stackObject.getId(), stack.put(stackObject.getId(),
new StackAbilityView(game, (StackAbility) stackObject, object.getName(), cardView)); new StackAbilityView(game, (StackAbility) stackObject, object.getName(), cardView));
checkPaid(stackObject.getId(), ((StackAbility) stackObject)); checkPaid(stackObject.getId(), ((StackAbility) stackObject));
} else if (object instanceof Plane) {
CardView cardView = new CardView(new PlaneView((Plane) object));
((StackAbility) stackObject).setName(((Plane) object).getName());
stack.put(stackObject.getId(),
new StackAbilityView(game, (StackAbility) stackObject, object.getName(), cardView));
checkPaid(stackObject.getId(), ((StackAbility) stackObject));
} else if (object instanceof Designation) { } else if (object instanceof Designation) {
Designation designation = (Designation) game.getObject(object.getId()); Designation designation = (Designation) game.getObject(object.getId());
if (designation != null) { if (designation != null) {

View file

@ -0,0 +1,57 @@
package mage.view;
import java.io.Serializable;
import java.util.List;
import java.util.UUID;
import mage.cards.Card;
import mage.game.command.Plane;
/**
* @author spjspj
*/
public class PlaneView implements CommandObjectView, Serializable {
protected UUID id;
protected String name;
protected String expansionSetCode;
protected List<String> rules;
public PlaneView(Plane plane, Card sourceCard) {
id = plane.getId();
name = "Plane " + sourceCard.getName();
if (plane.getExpansionSetCodeForImage() == null) {
expansionSetCode = sourceCard.getExpansionSetCode();
} else {
expansionSetCode = plane.getExpansionSetCodeForImage();
}
rules = plane.getAbilities().getRules(sourceCard.getName());
}
public PlaneView(Plane plane) {
id = plane.getId();
name = plane.getName();
expansionSetCode = plane.getExpansionSetCodeForImage();
rules = plane.getAbilities().getRules(plane.getName());
}
@Override
public String getExpansionSetCode() {
return expansionSetCode;
}
@Override
public String getName() {
return name;
}
@Override
public UUID getId() {
return id;
}
@Override
public List<String> getRules() {
return rules;
}
}

View file

@ -43,6 +43,7 @@ import mage.game.GameState;
import mage.game.command.CommandObject; import mage.game.command.CommandObject;
import mage.game.command.Commander; import mage.game.command.Commander;
import mage.game.command.Emblem; import mage.game.command.Emblem;
import mage.game.command.Plane;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.players.net.UserData; import mage.players.net.UserData;
@ -141,6 +142,10 @@ public class PlayerView implements Serializable {
if (emblem.getControllerId().equals(this.playerId)) { if (emblem.getControllerId().equals(this.playerId)) {
commandList.add(new EmblemView(emblem)); commandList.add(new EmblemView(emblem));
} }
} else if (commandObject instanceof Plane) {
Plane plane = (Plane) commandObject;
// Planes are universal and all players can see them.
commandList.add(new PlaneView(plane));
} else if (commandObject instanceof Commander) { } else if (commandObject instanceof Commander) {
Commander commander = (Commander) commandObject; Commander commander = (Commander) commandObject;
if (commander.getControllerId().equals(this.playerId)) { if (commander.getControllerId().equals(this.playerId)) {

View file

@ -2379,4 +2379,19 @@ public class TestPlayer implements Player {
return computerPlayer.getHistory(); return computerPlayer.getHistory();
} }
@Override
public PlanarDieRoll rollPlanarDie(Game game) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public PlanarDieRoll rollPlanarDie(Game game, ArrayList<UUID> appliedEffects) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public PlanarDieRoll rollPlanarDie(Game game, ArrayList<UUID> appliedEffects, int numberChaosSides, int numberPlanarSides) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
} }

View file

@ -1268,4 +1268,19 @@ public class PlayerStub implements Player {
return null; return null;
} }
@Override
public PlanarDieRoll rollPlanarDie(Game game) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public PlanarDieRoll rollPlanarDie(Game game, ArrayList<UUID> appliedEffects) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public PlanarDieRoll rollPlanarDie(Game game, ArrayList<UUID> appliedEffects, int numberChaosSides, int numberPlanarSides) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
} }

View file

@ -63,6 +63,7 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import mage.game.command.Plane;
/** /**
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
@ -923,8 +924,8 @@ public abstract class AbilityImpl implements Ability {
return true; return true;
} }
MageObject object = game.getObject(this.getSourceId()); MageObject object = game.getObject(this.getSourceId());
// emblem are always actual // emblem/planes are always actual
if (object != null && object instanceof Emblem) { if (object != null && (object instanceof Emblem || object instanceof Plane)) {
return true; return true;
} }
} }

View file

@ -45,6 +45,7 @@ import mage.constants.TimingRule;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.command.Emblem; import mage.game.command.Emblem;
import mage.game.command.Plane;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.util.CardUtil; import mage.util.CardUtil;
@ -240,12 +241,12 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
MageObject mageObject = game.getObject(this.sourceId); MageObject mageObject = game.getObject(this.sourceId);
if (mageObject instanceof Emblem) { if (mageObject instanceof Emblem) {
return ((Emblem) mageObject).getControllerId().equals(playerId); return ((Emblem) mageObject).getControllerId().equals(playerId);
} else { } else if (mageObject instanceof Plane) {
if (game.getState().getZone(this.sourceId) != Zone.BATTLEFIELD) { return ((Plane) mageObject).getControllerId().equals(playerId);
} else if (game.getState().getZone(this.sourceId) != Zone.BATTLEFIELD) {
return ((Card) mageObject).getOwnerId().equals(playerId); return ((Card) mageObject).getOwnerId().equals(playerId);
} }
} }
}
return false; return false;
} }

View file

@ -0,0 +1,56 @@
/*
* 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.condition.common;
import java.util.EnumSet;
import java.util.Set;
import mage.constants.TurnPhase;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.game.Game;
/**
* @author spjspj
*/
public enum MainPhaseStackEmptyCondition implements Condition {
instance;
private static final Set<TurnPhase> turnPhases = EnumSet.of(TurnPhase.PRECOMBAT_MAIN, TurnPhase.POSTCOMBAT_MAIN);
@Override
public boolean apply(Game game, Ability source) {
return game.getStack().isEmpty()
&& turnPhases.contains(game.getTurn().getPhase().getType());
}
@Override
public String toString() {
return "during the main phase and the stack is empty";
}
}

View file

@ -104,6 +104,9 @@ public class ConditionalContinuousEffect extends ContinuousEffectImpl {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
if (condition == null && baseCondition != null) {
condition = baseCondition;
}
boolean conditionState = condition.apply(game, source); boolean conditionState = condition.apply(game, source);
if (conditionState) { if (conditionState) {
effect.setTargetPointer(this.targetPointer); effect.setTargetPointer(this.targetPointer);

View file

@ -0,0 +1,187 @@
/*
* 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.logging.Logger;
import java.util.stream.Collectors;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.constants.PlanarDieRoll;
import mage.constants.Planes;
import mage.game.Game;
import mage.game.command.CommandObject;
import mage.game.command.Plane;
import mage.players.Player;
import mage.target.Target;
import mage.target.targetpointer.FixedTarget;
/**
*
* @author spjspj
*/
public class RollPlanarDieEffect extends OneShotEffect {
private static final Logger log = Logger.getLogger("Roll Planar Die");
protected List<Effect> chaosEffects = null;
protected List<Target> chaosTargets = null;
public RollPlanarDieEffect(List<Effect> chaosEffects, List<Target> chaosTargets) {
this(chaosEffects, chaosTargets, Outcome.Neutral);
}
public RollPlanarDieEffect(List<Effect> chaosEffects, List<Target> chaosTargets, Outcome outcome) {
super(outcome);
addChaosEffects(chaosEffects);
addChaosTargets(chaosTargets);
}
public RollPlanarDieEffect(final RollPlanarDieEffect effect) {
super(effect);
this.chaosEffects = effect.chaosEffects.stream().collect(Collectors.toList());
this.chaosTargets = effect.chaosTargets.stream().collect(Collectors.toList());
}
public void addChaosEffects(List<Effect> chaosEffects) {
if (chaosEffects != null) {
this.chaosEffects = chaosEffects;
}
}
public void addChaosTargets(List<Target> chaosTargets) {
if (chaosTargets != null) {
this.chaosTargets = chaosTargets;
}
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject mageObject = game.getObject(source.getSourceId());
if (controller != null && mageObject != null) {
PlanarDieRoll planarRoll = controller.rollPlanarDie(game);
if (planarRoll == PlanarDieRoll.CHAOS_ROLL && chaosEffects != null && chaosTargets != null) {
for (int i = 0; i < chaosTargets.size(); i++) {
Target target = chaosTargets.get(i);
if (target != null) {
target.clearChosen();
}
}
for (int i = 0; i < chaosEffects.size(); i++) {
Effect effect = chaosEffects.get(i);
Target target = null;
if (chaosTargets != null && chaosTargets.size() > i) {
target = chaosTargets.get(i);
}
boolean done = false;
while (controller.canRespond() && effect != null && !done) {
if (target != null && !target.isChosen() && target.canChoose(controller.getId(), game)) {
controller.chooseTarget(Outcome.Benefit, target, source, game);
source.addTarget(target);
}
if (target != null) {
effect.setTargetPointer(new FixedTarget(target.getFirstTarget()));
}
try {
effect.apply(game, source);
} catch (UnsupportedOperationException exception) {
}
if (effect instanceof ContinuousEffect) {
game.addEffect((ContinuousEffect) effect, source);
}
done = true;
}
}
} else if (planarRoll == PlanarDieRoll.PLANAR_ROLL) {
// Steps: 1) Remove the last plane and set its effects to discarded
for (CommandObject cobject : game.getState().getCommand()) {
if (cobject instanceof Plane) {
game.getState().addSeenPlane((Plane) cobject, game, id);
if (((Plane) cobject).getAbilities() != null) {
for (Ability ability : ((Plane) cobject).getAbilities()) {
for (Effect effect : ability.getEffects()) {
if (effect instanceof ContinuousEffect) {
((ContinuousEffect) effect).discard();
}
}
}
}
game.getState().removeTriggersOfSourceId(((Plane) cobject).getId());
game.getState().getCommand().remove(cobject);
break;
}
}
// 2) Choose a new random plane we haven't been to, or reset if we've been everywhere
List<String> planesVisited = game.getState().getSeenPlanes();
if (game.getState().getSeenPlanes() != null) {
if (planesVisited.size() == Planes.values().length) {
game.getState().resetSeenPlanes();
}
}
boolean foundNextPlane = false;
while (!foundNextPlane) {
Plane plane = Plane.getRandomPlane();
try {
if (plane != null && !planesVisited.contains(plane.getName())) {
foundNextPlane = true;
plane.setControllerId(controller.getId());
game.addPlane(plane, null, controller.getId());
game.informPlayers("You have planeswalked to " + plane.getLogName());
}
} catch (Exception ex) {
}
}
}
return true;
}
return false;
}
@Override
public String getText(Mode mode) {
if (!staticText.isEmpty()) {
return staticText;
}
StringBuilder sb = new StringBuilder("Roll the planar die");
return sb.toString();
}
@Override
public RollPlanarDieEffect copy() {
return new RollPlanarDieEffect(this);
}
}

View file

@ -24,8 +24,7 @@
* The views and conclusions contained in the software and documentation are those of the * 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 * authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com. * or implied, of BetaSteward_at_googlemail.com.
*/ */
package mage.abilities.effects.common.continuous; package mage.abilities.effects.common.continuous;
import mage.abilities.Ability; import mage.abilities.Ability;
@ -44,13 +43,28 @@ import mage.players.Player;
*/ */
public class PlayAdditionalLandsAllEffect extends ContinuousEffectImpl { public class PlayAdditionalLandsAllEffect extends ContinuousEffectImpl {
private int numExtraLands = 1;
public PlayAdditionalLandsAllEffect() { public PlayAdditionalLandsAllEffect() {
super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit); super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit);
staticText = "Each player may play an additional land on each of their turns"; staticText = "Each player may play an additional land on each of their turns";
numExtraLands = 1;
}
public PlayAdditionalLandsAllEffect(int numExtraLands) {
super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit);
this.numExtraLands = numExtraLands;
if (numExtraLands == Integer.MAX_VALUE) {
staticText = "Each player may play any number of additional lands on each of their turns";
} else {
staticText = "Each player may play an additional " + numExtraLands + " lands on each of their turns";
}
} }
public PlayAdditionalLandsAllEffect(final PlayAdditionalLandsAllEffect effect) { public PlayAdditionalLandsAllEffect(final PlayAdditionalLandsAllEffect effect) {
super(effect); super(effect);
this.numExtraLands = effect.numExtraLands;
this.staticText = effect.staticText;
} }
@Override @Override
@ -62,10 +76,13 @@ public class PlayAdditionalLandsAllEffect extends ContinuousEffectImpl {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(game.getActivePlayerId()); Player player = game.getPlayer(game.getActivePlayerId());
if (player != null) { if (player != null) {
player.setLandsPerTurn(player.getLandsPerTurn() + 1); if (numExtraLands == Integer.MAX_VALUE) {
player.setLandsPerTurn(Integer.MAX_VALUE);
} else {
player.setLandsPerTurn(player.getLandsPerTurn() + numExtraLands);
}
return true; return true;
} }
return true; return true;
} }
} }

View file

@ -33,6 +33,7 @@ public enum MageObjectType {
PERMANENT ("Permanent", true, true), PERMANENT ("Permanent", true, true),
EMBLEM ("Emblem", false, false), EMBLEM ("Emblem", false, false),
COMMANDER ("Commander", false, false), COMMANDER ("Commander", false, false),
PLANE ("Plane", false, false),
NULL("NullObject", false, false); NULL("NullObject", false, false);
private final String text; private final String text;

View file

@ -0,0 +1,51 @@
/*
* 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.constants;
/**
*
* @author spjspj
*/
public enum PlanarDieRoll {
NIL_ROLL ("Nil Roll"),
CHAOS_ROLL("Chaos Roll"),
PLANAR_ROLL ("Planar Roll");
private final String text;
PlanarDieRoll(String text) {
this.text = text;
}
@Override
public String toString() {
return text;
}
}

View file

@ -0,0 +1,57 @@
/*
* 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.constants;
/**
*
* @author spjspj
*/
public enum Planes {
PLANE_ACADEMY_AT_TOLARIA_WEST("AcademyAtTolariaWestPlane"),
PLANE_AGYREM("AgyremPlane"),
PLANE_BANT("BantPlane"),
PLANE_EDGE_OF_MALACOL("EdgeOfMalacolPlane"),
PLANE_FEEDING_GROUNDS("FeedingGroundsPlane"),
PLANE_FIELDS_OF_SUMMER("FieldsOfSummerPlane"),
PLANE_LETHE_LAKE("LetheLakePlane"),
PLANE_NAYA("NayaPlane"),
PLANE_THE_DARK_BARONY("TheDarkBaronyPlane"),
PLANE_THE_EON_FOG("TheEonFogPlane"),
PLANE_TURRI_ISLAND("TurriIslandPlane");
private final String text;
Planes(String text) {
this.text = text;
}
@Override
public String toString() {
return text;
}
}

View file

@ -49,6 +49,7 @@ import mage.counters.Counters;
import mage.game.combat.Combat; import mage.game.combat.Combat;
import mage.game.command.Commander; import mage.game.command.Commander;
import mage.game.command.Emblem; import mage.game.command.Emblem;
import mage.game.command.Plane;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.events.Listener; import mage.game.events.Listener;
import mage.game.events.PlayerQueryEvent; import mage.game.events.PlayerQueryEvent;
@ -365,6 +366,8 @@ public interface Game extends MageItem, Serializable {
void addEmblem(Emblem emblem, MageObject sourceObject, UUID toPlayerId); void addEmblem(Emblem emblem, MageObject sourceObject, UUID toPlayerId);
boolean addPlane(Plane plane, MageObject sourceObject, UUID toPlayerId);
void addCommander(Commander commander); void addCommander(Commander commander);
void addPermanent(Permanent permanent); void addPermanent(Permanent permanent);

View file

@ -67,6 +67,7 @@ import mage.game.combat.Combat;
import mage.game.command.CommandObject; import mage.game.command.CommandObject;
import mage.game.command.Commander; import mage.game.command.Commander;
import mage.game.command.Emblem; import mage.game.command.Emblem;
import mage.game.command.Plane;
import mage.game.events.*; import mage.game.events.*;
import mage.game.events.TableEvent.EventType; import mage.game.events.TableEvent.EventType;
import mage.game.permanent.Battlefield; import mage.game.permanent.Battlefield;
@ -1032,6 +1033,7 @@ public abstract class GameImpl implements Game, Serializable {
watchers.add(new PlayerLostLifeWatcher()); watchers.add(new PlayerLostLifeWatcher());
watchers.add(new BlockedAttackerWatcher()); watchers.add(new BlockedAttackerWatcher());
watchers.add(new DamageDoneWatcher()); watchers.add(new DamageDoneWatcher());
watchers.add(new PlanarRollWatcher());
//20100716 - 103.5 //20100716 - 103.5
for (UUID playerId : state.getPlayerList(startingPlayerId)) { for (UUID playerId : state.getPlayerList(startingPlayerId)) {
@ -1071,6 +1073,10 @@ public abstract class GameImpl implements Game, Serializable {
} }
} }
// 20180408 - 901.5
if (state.isPlaneChase()) {
addPlane(Plane.getRandomPlane(), null, getActivePlayerId());
}
} }
protected void sendStartMessage(Player choosingPlayer, Player startingPlayer) { protected void sendStartMessage(Player choosingPlayer, Player startingPlayer) {
@ -1526,6 +1532,37 @@ public abstract class GameImpl implements Game, Serializable {
state.addCommandObject(newEmblem); state.addCommandObject(newEmblem);
} }
/**
*
* @param plane
* @param sourceObject
* @param toPlayerId controller and owner of the plane (may only be one per
* game..)
* @return boolean - whether the plane was added successfully or not
*/
@Override
public boolean addPlane(Plane plane, MageObject sourceObject, UUID toPlayerId) {
// Implementing planechase as if it were 901.15. Single Planar Deck Option
// Here, can enforce the world plane restriction (the Grand Melee format may have some impact on this implementation)
// Enforce 'world' rule for planes
for (CommandObject cobject : state.getCommand()) {
if (cobject instanceof Plane) {
return false;
}
}
Plane newPlane = plane.copy();
newPlane.setSourceObject(sourceObject);
newPlane.setControllerId(toPlayerId);
newPlane.assignNewId();
newPlane.getAbilities().newId();
for (Ability ability : newPlane.getAbilities()) {
ability.setSourceId(newPlane.getId());
}
state.addCommandObject(newPlane);
return true;
}
@Override @Override
public void addCommander(Commander commander) { public void addCommander(Commander commander) {
state.addCommandObject(commander); state.addCommandObject(commander);
@ -2466,7 +2503,7 @@ public abstract class GameImpl implements Game, Serializable {
//Remove all emblems the player controls //Remove all emblems the player controls
for (Iterator<CommandObject> it = this.getState().getCommand().iterator(); it.hasNext();) { for (Iterator<CommandObject> it = this.getState().getCommand().iterator(); it.hasNext();) {
CommandObject obj = it.next(); CommandObject obj = it.next();
if (obj instanceof Emblem && obj.getControllerId().equals(playerId)) { if ((obj instanceof Emblem || obj instanceof Plane) && obj.getControllerId().equals(playerId)) {
((Emblem) obj).discardEffects();// This may not be the best fix but it works ((Emblem) obj).discardEffects();// This may not be the best fix but it works
it.remove(); it.remove();
} }

View file

@ -44,6 +44,7 @@ import mage.game.combat.Combat;
import mage.game.combat.CombatGroup; import mage.game.combat.CombatGroup;
import mage.game.command.Command; import mage.game.command.Command;
import mage.game.command.CommandObject; import mage.game.command.CommandObject;
import mage.game.command.Plane;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent; import mage.game.events.ZoneChangeEvent;
import mage.game.events.ZoneChangeGroupEvent; import mage.game.events.ZoneChangeGroupEvent;
@ -95,6 +96,8 @@ public class GameState implements Serializable, Copyable<GameState> {
private UUID monarchId; // player that is the monarch private UUID monarchId; // player that is the monarch
private SpellStack stack; private SpellStack stack;
private Command command; private Command command;
private boolean isPlaneChase;
private List<String> seenPlanes = new ArrayList<>();
private List<Designation> designations = new ArrayList<>(); private List<Designation> designations = new ArrayList<>();
private Exile exile; private Exile exile;
private Battlefield battlefield; private Battlefield battlefield;
@ -153,6 +156,8 @@ public class GameState implements Serializable, Copyable<GameState> {
this.stack = state.stack.copy(); this.stack = state.stack.copy();
this.command = state.command.copy(); this.command = state.command.copy();
this.isPlaneChase = state.isPlaneChase;
this.seenPlanes.addAll(state.seenPlanes);
this.designations.addAll(state.designations); this.designations.addAll(state.designations);
this.exile = state.exile.copy(); this.exile = state.exile.copy();
this.battlefield = state.battlefield.copy(); this.battlefield = state.battlefield.copy();
@ -203,6 +208,8 @@ public class GameState implements Serializable, Copyable<GameState> {
this.monarchId = state.monarchId; this.monarchId = state.monarchId;
this.stack = state.stack; this.stack = state.stack;
this.command = state.command; this.command = state.command;
this.isPlaneChase = state.isPlaneChase;
this.seenPlanes = state.seenPlanes;
this.designations = state.designations; this.designations = state.designations;
this.exile = state.exile; this.exile = state.exile;
this.battlefield = state.battlefield; this.battlefield = state.battlefield;
@ -450,6 +457,14 @@ public class GameState implements Serializable, Copyable<GameState> {
return designations; return designations;
} }
public List<String> getSeenPlanes() {
return seenPlanes;
}
public boolean isPlaneChase() {
return isPlaneChase;
}
public Command getCommand() { public Command getCommand() {
return command; return command;
} }
@ -856,6 +871,20 @@ public class GameState implements Serializable, Copyable<GameState> {
} }
} }
public void addSeenPlane(Plane plane, Game game, UUID controllerId) {
if (plane != null) {
getSeenPlanes().add(plane.getName());
}
}
public void resetSeenPlanes() {
getSeenPlanes().clear();
}
public void setPlaneChase(Game game, boolean isPlaneChase) {
this.isPlaneChase = isPlaneChase;
}
public void addCommandObject(CommandObject commandObject) { public void addCommandObject(CommandObject commandObject) {
getCommand().add(commandObject); getCommand().add(commandObject);
setZone(commandObject.getId(), Zone.COMMAND); setZone(commandObject.getId(), Zone.COMMAND);
@ -1014,6 +1043,8 @@ public class GameState implements Serializable, Copyable<GameState> {
exile.clear(); exile.clear();
command.clear(); command.clear();
designations.clear(); designations.clear();
seenPlanes.clear();
isPlaneChase = false;
revealed.clear(); revealed.clear();
lookedAt.clear(); lookedAt.clear();
turnNum = 0; turnNum = 0;

View file

@ -0,0 +1,321 @@
/*
* 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.game.command;
import static java.lang.Math.log;
import java.lang.reflect.Constructor;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.ObjectColor;
import mage.abilities.Abilities;
import mage.abilities.AbilitiesImpl;
import mage.abilities.Ability;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.text.TextPart;
import mage.cards.Card;
import mage.cards.FrameStyle;
import mage.constants.CardType;
import mage.constants.Planes;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.game.Game;
import mage.game.events.ZoneChangeEvent;
import mage.util.GameLog;
import mage.util.SubTypeList;
/**
* @author spjspj
*/
public class Plane implements CommandObject {
private static EnumSet<CardType> emptySet = EnumSet.noneOf(CardType.class);
private static ObjectColor emptyColor = new ObjectColor();
private static ManaCosts emptyCost = new ManaCostsImpl();
private String name = "";
private UUID id;
private UUID controllerId;
private MageObject sourceObject;
private FrameStyle frameStyle;
private Abilities<Ability> abilites = new AbilitiesImpl<>();
private String expansionSetCodeForImage = "";
public Plane() {
this.id = UUID.randomUUID();
}
public Plane(final Plane plane) {
this.id = plane.id;
this.name = plane.name;
this.frameStyle = plane.frameStyle;
this.controllerId = plane.controllerId;
this.sourceObject = plane.sourceObject;
this.abilites = plane.abilites.copy();
this.expansionSetCodeForImage = plane.expansionSetCodeForImage;
}
@Override
public FrameStyle getFrameStyle() {
return frameStyle;
}
@Override
public void assignNewId() {
this.id = UUID.randomUUID();
}
public void setSourceObject(MageObject sourceObject) {
this.sourceObject = sourceObject;
if (sourceObject instanceof Card) {
if (name.isEmpty()) {
name = sourceObject.getSubtype(null).toString();
}
if (expansionSetCodeForImage.isEmpty()) {
expansionSetCodeForImage = ((Card) sourceObject).getExpansionSetCode();
}
}
}
@Override
public MageObject getSourceObject() {
return sourceObject;
}
@Override
public UUID getSourceId() {
if (sourceObject != null) {
return sourceObject.getId();
}
return null;
}
@Override
public UUID getControllerId() {
return this.controllerId;
}
public void setControllerId(UUID controllerId) {
this.controllerId = controllerId;
this.abilites.setControllerId(controllerId);
}
@Override
public String getName() {
return name;
}
@Override
public String getIdName() {
return getName() + " [" + getId().toString().substring(0, 3) + ']';
}
@Override
public String getLogName() {
return GameLog.getColoredObjectIdName(this);
}
@Override
public String getImageName() {
return this.name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public EnumSet<CardType> getCardType() {
return emptySet;
}
@Override
public SubTypeList getSubtype(Game game) {
return new SubTypeList();
}
@Override
public boolean hasSubtype(SubType subtype, Game game) {
return false;
}
@Override
public EnumSet<SuperType> getSuperType() {
return EnumSet.noneOf(SuperType.class);
}
@Override
public Abilities<Ability> getAbilities() {
return abilites;
}
@Override
public boolean hasAbility(UUID abilityId, Game game) {
return abilites.containsKey(abilityId);
}
@Override
public ObjectColor getColor(Game game) {
return emptyColor;
}
@Override
public ObjectColor getFrameColor(Game game) {
return emptyColor;
}
@Override
public ManaCosts<ManaCost> getManaCost() {
return emptyCost;
}
@Override
public int getConvertedManaCost() {
return 0;
}
@Override
public MageInt getPower() {
return MageInt.EmptyMageInt;
}
@Override
public MageInt getToughness() {
return MageInt.EmptyMageInt;
}
@Override
public int getStartingLoyalty() {
return 0;
}
@Override
public void adjustCosts(Ability ability, Game game) {
}
@Override
public void adjustTargets(Ability ability, Game game) {
}
@Override
public UUID getId() {
return this.id;
}
@Override
public void setCopy(boolean isCopy) {
}
@Override
public boolean isCopy() {
return false;
}
@Override
public Plane copy() {
return new Plane(this);
}
public void setExpansionSetCodeForImage(String expansionSetCodeForImage) {
this.expansionSetCodeForImage = expansionSetCodeForImage;
}
public String getExpansionSetCodeForImage() {
return expansionSetCodeForImage;
}
@Override
public int getZoneChangeCounter(Game game) {
return 1; // Emblems can't move zones until now so return always 1
}
@Override
public void updateZoneChangeCounter(Game game, ZoneChangeEvent event) {
throw new UnsupportedOperationException("Unsupported operation");
}
@Override
public void setZoneChangeCounter(int value, Game game) {
throw new UnsupportedOperationException("Unsupported operation");
}
public boolean isAllCreatureTypes() {
return false;
}
public void setIsAllCreatureTypes(boolean value) {
}
public void discardEffects() {
for (Ability ability : abilites) {
for (Effect effect : ability.getEffects()) {
if (effect instanceof ContinuousEffect) {
((ContinuousEffect) effect).discard();
}
}
}
}
@Override
public List<TextPart> getTextParts() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public TextPart addTextPart(TextPart textPart) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
@Override
public void removePTCDA() {
}
public static Plane getRandomPlane() {
int pick = new Random().nextInt(Planes.values().length);
String planeName = Planes.values()[pick].toString();
planeName = "mage.game.command.planes." + planeName;
try {
Class<?> c = Class.forName(planeName);
Constructor<?> cons = c.getConstructor();
Object plane = cons.newInstance();
if (plane != null && plane instanceof mage.game.command.Plane) {
return (Plane) plane;
}
} catch (Exception ex) {
}
return null;
}
}

View file

@ -0,0 +1,79 @@
/*
* 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.game.command.planes;
import java.util.ArrayList;
import java.util.List;
import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.BeginningOfEndStepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.HellbentCondition;
import mage.abilities.condition.common.MainPhaseStackEmptyCondition;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.RollPlanarDieEffect;
import mage.abilities.effects.common.discard.DiscardHandControllerEffect;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.game.command.Plane;
import mage.target.Target;
import mage.watchers.common.PlanarRollWatcher;
/**
*
* @author spjspj
*/
public class AcademyAtTolariaWestPlane extends Plane {
public AcademyAtTolariaWestPlane() {
this.setName("Plane - Academy at Tolaria West");
this.setExpansionSetCodeForImage("PCA");
// At the beginning of your end step, if you have 0 cards in hand, draw seven cards
Ability ability = new BeginningOfEndStepTriggeredAbility(Zone.COMMAND, new DrawCardSourceControllerEffect(7), TargetController.ANY, HellbentCondition.instance, false);
this.getAbilities().add(ability);
// Active player can roll the planar die: Whenever you roll {CHAOS}, discard your hand
Effect chaosEffect = new DiscardHandControllerEffect();
Target chaosTarget = null;
List<Effect> chaosEffects = new ArrayList<Effect>();
chaosEffects.add(chaosEffect);
List<Target> chaosTargets = new ArrayList<Target>();
chaosTargets.add(chaosTarget);
ActivateIfConditionActivatedAbility chaosAbility = new ActivateIfConditionActivatedAbility(Zone.COMMAND, new RollPlanarDieEffect(chaosEffects, chaosTargets), new GenericManaCost(0), MainPhaseStackEmptyCondition.instance);
chaosAbility.addWatcher(new PlanarRollWatcher());
this.getAbilities().add(chaosAbility);
chaosAbility.setMayActivate(TargetController.ANY);
this.getAbilities().add(new SimpleStaticAbility(Zone.ALL, new PlanarDieRollCostIncreasingEffect(chaosAbility.getOriginalId())));
}
}

View file

@ -0,0 +1,188 @@
/*
* 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.game.command.planes;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.DiesCreatureTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.condition.common.MainPhaseStackEmptyCondition;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.RestrictionEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect;
import mage.abilities.effects.common.RollPlanarDieEffect;
import mage.cards.Card;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import mage.game.command.Plane;
import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.target.targetpointer.FixedTarget;
import mage.watchers.common.PlanarRollWatcher;
/**
*
* @author spjspj
*/
public class AgyremPlane extends Plane {
private static final FilterControlledCreaturePermanent filterWhite = new FilterControlledCreaturePermanent("a white creature");
private static final FilterControlledCreaturePermanent filterNonWhite = new FilterControlledCreaturePermanent("a nonwhite creature");
static {
filterWhite.add(new ColorPredicate(ObjectColor.WHITE));
filterNonWhite.add(Predicates.not(new ColorPredicate(ObjectColor.WHITE)));
}
public AgyremPlane() {
this.setName("Plane - Agyrem");
this.setExpansionSetCodeForImage("PCA");
// Whenever a white creature dies, return it to the battlefield under its owner's control at the beginning of the next end step
DiesCreatureTriggeredAbility ability = new DiesCreatureTriggeredAbility(Zone.COMMAND, new AgyremEffect(), false, filterWhite, true);
this.getAbilities().add(ability);
DiesCreatureTriggeredAbility ability2 = new DiesCreatureTriggeredAbility(Zone.COMMAND, new AgyremEffect2(), false, filterNonWhite, true);
this.getAbilities().add(ability2);
// Active player can roll the planar die: Whenever you roll {CHAOS}, creatures can't attack you until a player planeswalks
Effect chaosEffect = new AgyremRestrictionEffect();
Target chaosTarget = null;
List<Effect> chaosEffects = new ArrayList<Effect>();
chaosEffects.add(chaosEffect);
List<Target> chaosTargets = new ArrayList<Target>();
chaosTargets.add(chaosTarget);
ActivateIfConditionActivatedAbility chaosAbility = new ActivateIfConditionActivatedAbility(Zone.COMMAND, new RollPlanarDieEffect(chaosEffects, chaosTargets), new GenericManaCost(0), MainPhaseStackEmptyCondition.instance);
chaosAbility.addWatcher(new PlanarRollWatcher());
this.getAbilities().add(chaosAbility);
chaosAbility.setMayActivate(TargetController.ANY);
this.getAbilities().add(new SimpleStaticAbility(Zone.ALL, new PlanarDieRollCostIncreasingEffect(chaosAbility.getOriginalId())));
}
}
class AgyremEffect extends OneShotEffect {
public AgyremEffect() {
super(Outcome.PutCardInPlay);
this.staticText = "return that card to the battlefield under its owner's control at the beginning of the next end step";
}
public AgyremEffect(final AgyremEffect effect) {
super(effect);
}
@Override
public AgyremEffect copy() {
return new AgyremEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Card card = game.getCard(getTargetPointer().getFirst(game, source));
if (card != null) {
Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect();
effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game)));
effect.setText("return that card to the battlefield under its owner's control at the beginning of the next end step");
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone.BATTLEFIELD, effect, TargetController.ANY), source);
return true;
}
return false;
}
}
class AgyremEffect2 extends OneShotEffect {
public AgyremEffect2() {
super(Outcome.PutCardInPlay);
this.staticText = "return it to its owner's hand at the beginning of the next end step";
}
public AgyremEffect2(final AgyremEffect2 effect) {
super(effect);
}
@Override
public AgyremEffect2 copy() {
return new AgyremEffect2(this);
}
@Override
public boolean apply(Game game, Ability source) {
Card card = game.getCard(getTargetPointer().getFirst(game, source));
if (card != null) {
Effect effect = new ReturnFromGraveyardToHandTargetEffect();
effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game)));
effect.setText("return it to its owner's hand at the beginning of the next end step");
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone.HAND, effect, TargetController.ANY), source);
return true;
}
return false;
}
}
class AgyremRestrictionEffect extends RestrictionEffect {
AgyremRestrictionEffect() {
super(Duration.Custom, Outcome.Benefit);
staticText = "Creatures can't attack you";
}
AgyremRestrictionEffect(final AgyremRestrictionEffect effect) {
super(effect);
}
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
return permanent.isCreature();
}
@Override
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) {
return !defenderId.equals(source.getControllerId());
}
@Override
public AgyremRestrictionEffect copy() {
return new AgyremRestrictionEffect(this);
}
}

View file

@ -0,0 +1,148 @@
/*
* 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.game.command.planes;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.MainPhaseStackEmptyCondition;
import mage.abilities.condition.common.TargetHasCounterCondition;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.RollPlanarDieEffect;
import mage.abilities.effects.common.continuous.GainAbilityAllEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.abilities.keyword.ExaltedAbility;
import mage.abilities.keyword.IndestructibleAbility;
import mage.constants.CostModificationType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import mage.game.command.Plane;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetCreaturePermanent;
import mage.util.CardUtil;
import mage.watchers.common.PlanarRollWatcher;
/**
*
* @author spjspj
*/
public class BantPlane extends Plane {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures");
private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("Green, White or Blue creatures");
static {
filter2.add(Predicates.or(new ColorPredicate(ObjectColor.GREEN), new ColorPredicate(ObjectColor.WHITE), new ColorPredicate(ObjectColor.BLUE)));
}
private static final String rule = "{this} has indestructible as long as it has a divinity counter on it";
public BantPlane() {
this.setName("Plane - Bant");
this.setExpansionSetCodeForImage("PCA");
// All creatures have exalted
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new GainAbilityAllEffect(new ExaltedAbility(), Duration.Custom, StaticFilters.FILTER_PERMANENT_CREATURE));
this.getAbilities().add(ability);
// Active player can roll the planar die: Whenever you roll {CHAOS}, put a divinity counter on target green, white, or blue creature. That creature gains indestructible for as long as it has a divinity counter on it.
Effect chaosEffect = new ConditionalContinuousEffect(new GainAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.Custom), new TargetHasCounterCondition(CounterType.DIVINITY), rule);
Target chaosTarget = new TargetCreaturePermanent(1, 1, filter2, false);
Effect chaosEffect2 = new AddCountersTargetEffect(CounterType.DIVINITY.createInstance());
List<Effect> chaosEffects = new ArrayList<Effect>();
chaosEffects.add(chaosEffect2);
chaosEffects.add(chaosEffect);
List<Target> chaosTargets = new ArrayList<Target>();
chaosTargets.add(chaosTarget);
chaosTargets.add(chaosTarget);
ActivateIfConditionActivatedAbility chaosAbility = new ActivateIfConditionActivatedAbility(Zone.COMMAND, new RollPlanarDieEffect(chaosEffects, chaosTargets), new GenericManaCost(0), MainPhaseStackEmptyCondition.instance);
chaosAbility.addWatcher(new PlanarRollWatcher());
this.getAbilities().add(chaosAbility);
chaosAbility.setMayActivate(TargetController.ANY);
this.getAbilities().add(new SimpleStaticAbility(Zone.ALL, new PlanarDieRollCostIncreasingEffect(chaosAbility.getOriginalId())));
}
}
class PlanarDieRollCostIncreasingEffect extends CostModificationEffectImpl {
private final UUID originalId;
PlanarDieRollCostIncreasingEffect(UUID originalId) {
super(Duration.EndOfGame, Outcome.Benefit, CostModificationType.INCREASE_COST);
this.originalId = originalId;
}
PlanarDieRollCostIncreasingEffect(final PlanarDieRollCostIncreasingEffect effect) {
super(effect);
this.originalId = effect.originalId;
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
Player activePlayer = game.getPlayer(game.getActivePlayerId());
if (activePlayer != null) {
PlanarRollWatcher watcher = (PlanarRollWatcher) game.getState().getWatchers().get(PlanarRollWatcher.class.getSimpleName());
int rolledCounter = 0;
if (watcher != null) {
rolledCounter = watcher.getNumberTimesPlanarDieRolled(activePlayer.getId());
}
CardUtil.increaseCost(abilityToModify, rolledCounter);
}
return true;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
return abilityToModify.getOriginalId().equals(originalId);
}
@Override
public PlanarDieRollCostIncreasingEffect copy() {
return new PlanarDieRollCostIncreasingEffect(this);
}
}

View file

@ -0,0 +1,131 @@
/*
* 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.game.command.planes;
import java.util.ArrayList;
import java.util.List;
import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.MainPhaseStackEmptyCondition;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.RollPlanarDieEffect;
import mage.abilities.effects.common.UntapAllControllerEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.PhaseStep;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.command.Plane;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.target.targetpointer.FixedTarget;
import mage.watchers.common.PlanarRollWatcher;
/**
*
* @author spjspj
*/
public class EdgeOfMalacolPlane extends Plane {
public EdgeOfMalacolPlane() {
this.setName("Plane - Edge Of Malacol");
this.setExpansionSetCodeForImage("PCA");
// If a creature you control would untap during your untap step, put two +1/+1 counters on it instead.
SimpleStaticAbility ability = new SimpleStaticAbility(Zone.COMMAND, new EdgeOfMalacolEffect());
this.getAbilities().add(ability);
// Active player can roll the planar die: Whenever you roll {CHAOS}, untap each creature you control
Effect chaosEffect = new UntapAllControllerEffect(new FilterControlledCreaturePermanent(), "untap each creature you control");
Target chaosTarget = null;
List<Effect> chaosEffects = new ArrayList<Effect>();
chaosEffects.add(chaosEffect);
List<Target> chaosTargets = new ArrayList<Target>();
chaosTargets.add(chaosTarget);
ActivateIfConditionActivatedAbility chaosAbility = new ActivateIfConditionActivatedAbility(Zone.COMMAND, new RollPlanarDieEffect(chaosEffects, chaosTargets), new GenericManaCost(0), MainPhaseStackEmptyCondition.instance);
chaosAbility.addWatcher(new PlanarRollWatcher());
this.getAbilities().add(chaosAbility);
chaosAbility.setMayActivate(TargetController.ANY);
this.getAbilities().add(new SimpleStaticAbility(Zone.ALL, new PlanarDieRollCostIncreasingEffect(chaosAbility.getOriginalId())));
}
}
class EdgeOfMalacolEffect extends ContinuousRuleModifyingEffectImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
public EdgeOfMalacolEffect() {
super(Duration.Custom, Outcome.Detriment);
}
public EdgeOfMalacolEffect(final EdgeOfMalacolEffect effect) {
super(effect);
}
@Override
public EdgeOfMalacolEffect copy() {
return new EdgeOfMalacolEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == EventType.UNTAP;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
// Prevent untap event of creatures of target player
if (game.getTurn().getStepType() == PhaseStep.UNTAP) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null && filter.match(permanent, game)) {
Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(2));
effect.setTargetPointer(new FixedTarget(permanent, game));
effect.apply(game, source);
return true;
}
}
return false;
}
}

View file

@ -0,0 +1,97 @@
/*
* 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.game.command.planes;
import java.util.ArrayList;
import java.util.List;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.MainPhaseStackEmptyCondition;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.dynamicvalue.common.TargetConvertedManaCost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.RollPlanarDieEffect;
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.FilterCard;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.command.Plane;
import mage.target.Target;
import mage.target.common.TargetCreaturePermanent;
import mage.watchers.common.PlanarRollWatcher;
/**
*
* @author spjspj
*/
public class FeedingGroundsPlane extends Plane {
private static final FilterCard filter = new FilterCard("Red spells or Green spells");
private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("Red or Green creature");
static {
filter.add(Predicates.or(
new ColorPredicate(ObjectColor.RED),
new ColorPredicate(ObjectColor.GREEN)));
filter2.add(Predicates.or(new ColorPredicate(ObjectColor.RED), new ColorPredicate(ObjectColor.GREEN)));
}
private static final String rule = "put X +1/+1 counters on target creature, where X is that creature's converted mana cost";
public FeedingGroundsPlane() {
this.setName("Plane - Feeding Grounds");
this.setExpansionSetCodeForImage("PCA");
// Red spells cost {1} less to cast. Green spells cost {1} less to cast
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new SpellsCostReductionControllerEffect(filter, 1));
this.getAbilities().add(ability);
// Active player can roll the planar die: Whenever you roll {CHAOS}, target red or green creature gets X +1/+1 counters
Effect chaosEffect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(), new TargetConvertedManaCost());
Target chaosTarget = new TargetCreaturePermanent(1, 1, filter2, false);
List<Effect> chaosEffects = new ArrayList<Effect>();
chaosEffects.add(chaosEffect);
List<Target> chaosTargets = new ArrayList<Target>();
chaosTargets.add(chaosTarget);
ActivateIfConditionActivatedAbility chaosAbility = new ActivateIfConditionActivatedAbility(Zone.COMMAND, new RollPlanarDieEffect(chaosEffects, chaosTargets), new GenericManaCost(0), MainPhaseStackEmptyCondition.instance);
chaosAbility.addWatcher(new PlanarRollWatcher());
this.getAbilities().add(chaosAbility);
chaosAbility.setMayActivate(TargetController.ANY);
this.getAbilities().add(new SimpleStaticAbility(Zone.ALL, new PlanarDieRollCostIncreasingEffect(chaosAbility.getOriginalId())));
}
}

View file

@ -0,0 +1,115 @@
/*
* 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.game.command.planes;
import java.util.ArrayList;
import java.util.List;
import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.SpellCastAllTriggeredAbility;
import mage.abilities.condition.common.MainPhaseStackEmptyCondition;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.GainLifeTargetEffect;
import mage.abilities.effects.common.RollPlanarDieEffect;
import mage.constants.Outcome;
import mage.constants.SetTargetPointer;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.FilterSpell;
import mage.game.Game;
import mage.game.command.Plane;
import mage.players.Player;
import mage.target.Target;
import mage.target.targetpointer.FixedTarget;
import mage.watchers.common.PlanarRollWatcher;
/**
*
* @author spjspj
*/
public class FieldsOfSummerPlane extends Plane {
private final static FilterSpell filter = new FilterSpell("a spell");
public FieldsOfSummerPlane() {
this.setName("Plane - Fields of Summer");
this.setExpansionSetCodeForImage("PCA");
// Whenever a player casts a spell, that player may gain 2 life
SpellCastAllTriggeredAbility ability = new SpellCastAllTriggeredAbility(Zone.COMMAND, new FieldsOfSummerEffect(), filter, false, SetTargetPointer.PLAYER);
this.getAbilities().add(ability);
// Active player can roll the planar die: Whenever you roll {CHAOS}, you may gain 10 life
Effect chaosEffect = new GainLifeEffect(10);
Target chaosTarget = null;
List<Effect> chaosEffects = new ArrayList<Effect>();
chaosEffects.add(chaosEffect);
List<Target> chaosTargets = new ArrayList<Target>();
chaosTargets.add(chaosTarget);
ActivateIfConditionActivatedAbility chaosAbility = new ActivateIfConditionActivatedAbility(Zone.COMMAND, new RollPlanarDieEffect(chaosEffects, chaosTargets), new GenericManaCost(0), MainPhaseStackEmptyCondition.instance);
chaosAbility.addWatcher(new PlanarRollWatcher());
this.getAbilities().add(chaosAbility);
chaosAbility.setMayActivate(TargetController.ANY);
this.getAbilities().add(new SimpleStaticAbility(Zone.ALL, new PlanarDieRollCostIncreasingEffect(chaosAbility.getOriginalId())));
}
}
class FieldsOfSummerEffect extends OneShotEffect {
public FieldsOfSummerEffect() {
super(Outcome.GainLife);
this.staticText = "that player may gain 2 life";
}
public FieldsOfSummerEffect(final FieldsOfSummerEffect effect) {
super(effect);
}
@Override
public FieldsOfSummerEffect copy() {
return new FieldsOfSummerEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Player owner = game.getPlayer(this.getTargetPointer().getFirst(game, source));
if (owner != null && owner.canRespond() && owner.chooseUse(Outcome.Benefit, "Gain 2 life?", source, game)) {
Effect effect = new GainLifeTargetEffect(2);
effect.setTargetPointer(new FixedTarget(owner.getId())).apply(game, source);
return true;
}
return false;
}
}

View file

@ -0,0 +1,79 @@
/*
* 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.game.command.planes;
import java.util.ArrayList;
import java.util.List;
import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.MainPhaseStackEmptyCondition;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect;
import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveTargetEffect;
import mage.abilities.effects.common.RollPlanarDieEffect;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.game.command.Plane;
import mage.target.Target;
import mage.target.TargetPlayer;
import mage.watchers.common.PlanarRollWatcher;
/**
*
* @author spjspj
*/
public class LetheLakePlane extends Plane {
public LetheLakePlane() {
this.setName("Plane - Lethe Lake");
this.setExpansionSetCodeForImage("PCA");
// At the beginning of your upkeep, put the top ten cards of your libary into your graveyard
Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.COMMAND, new PutLibraryIntoGraveTargetEffect(10).setText("that player puts the top 10 cards of their library into their graveyard"), TargetController.ANY, false, true);
this.getAbilities().add(ability);
// Active player can roll the planar die: Whenever you roll {CHAOS}, target player puts the top ten cards of his or her library into his or her graveyard
Effect chaosEffect = new PutTopCardOfLibraryIntoGraveTargetEffect(10);
Target chaosTarget = new TargetPlayer();
List<Effect> chaosEffects = new ArrayList<Effect>();
chaosEffects.add(chaosEffect);
List<Target> chaosTargets = new ArrayList<Target>();
chaosTargets.add(chaosTarget);
ActivateIfConditionActivatedAbility chaosAbility = new ActivateIfConditionActivatedAbility(Zone.COMMAND, new RollPlanarDieEffect(chaosEffects, chaosTargets), new GenericManaCost(0), MainPhaseStackEmptyCondition.instance);
chaosAbility.addWatcher(new PlanarRollWatcher());
this.getAbilities().add(chaosAbility);
chaosAbility.setMayActivate(TargetController.ANY);
this.getAbilities().add(new SimpleStaticAbility(Zone.ALL, new PlanarDieRollCostIncreasingEffect(chaosAbility.getOriginalId())));
}
}

View file

@ -0,0 +1,94 @@
/*
* 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.game.command.planes;
import java.util.ArrayList;
import java.util.List;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.MainPhaseStackEmptyCondition;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.RollPlanarDieEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.continuous.PlayAdditionalLandsAllEffect;
import mage.constants.Duration;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterControlledLandPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.command.Plane;
import mage.target.Target;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetCreaturePermanent;
import mage.watchers.common.PlanarRollWatcher;
/**
*
* @author spjspj
*/
public class NayaPlane extends Plane {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Red, Green or White creature");
private static final FilterControlledLandPermanent filter2 = new FilterControlledLandPermanent("lands you control");
static {
filter.add(Predicates.or(new ColorPredicate(ObjectColor.RED), new ColorPredicate(ObjectColor.GREEN), new ColorPredicate(ObjectColor.WHITE)));
}
private static final String rule = "{this} gets +1/+1 until end of of turn for each land you control";
public NayaPlane() {
this.setName("Plane - Naya");
this.setExpansionSetCodeForImage("PCA");
// You may play any number of lands on each of your turns
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new PlayAdditionalLandsAllEffect(Integer.MAX_VALUE));
this.getAbilities().add(ability);
// Active player can roll the planar die: Whenever you roll {CHAOS}, target red, green or white creature gets +1/+1 until end of turn for each land you control
Effect chaosEffect = new BoostTargetEffect(new PermanentsOnBattlefieldCount(filter2), new PermanentsOnBattlefieldCount(filter2), Duration.EndOfTurn);
Target chaosTarget = new TargetControlledCreaturePermanent(1, 1, filter, false);
List<Effect> chaosEffects = new ArrayList<Effect>();
chaosEffects.add(chaosEffect);
List<Target> chaosTargets = new ArrayList<Target>();
chaosTargets.add(chaosTarget);
ActivateIfConditionActivatedAbility chaosAbility = new ActivateIfConditionActivatedAbility(Zone.COMMAND, new RollPlanarDieEffect(chaosEffects, chaosTargets), new GenericManaCost(0), MainPhaseStackEmptyCondition.instance);
chaosAbility.addWatcher(new PlanarRollWatcher());
this.getAbilities().add(chaosAbility);
chaosAbility.setMayActivate(TargetController.ANY);
this.getAbilities().add(new SimpleStaticAbility(Zone.ALL, new PlanarDieRollCostIncreasingEffect(chaosAbility.getOriginalId())));
}
}

View file

@ -0,0 +1,89 @@
/*
* 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.game.command.planes;
import java.util.ArrayList;
import java.util.List;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.PutCardIntoGraveFromAnywhereAllTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.MainPhaseStackEmptyCondition;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.LoseLifeTargetEffect;
import mage.abilities.effects.common.RollPlanarDieEffect;
import mage.abilities.effects.common.discard.DiscardEachPlayerEffect;
import mage.constants.SetTargetPointer;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.command.Plane;
import mage.target.Target;
import mage.watchers.common.PlanarRollWatcher;
/**
*
* @author spjspj
*/
public class TheDarkBaronyPlane extends Plane {
private static final FilterCard filter = new FilterCard("a nonblack card");
static {
filter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK)));
}
public TheDarkBaronyPlane() {
this.setName("Plane - The Dark Barony");
this.setExpansionSetCodeForImage("PCA");
// Whenever a nonblack card is put into a player's graveyard from anywhere, that player loses 2 life
Ability ability = new PutCardIntoGraveFromAnywhereAllTriggeredAbility(Zone.COMMAND,
new LoseLifeTargetEffect(2), false, filter, TargetController.ANY, SetTargetPointer.PLAYER);
this.getAbilities().add(ability);
// Active player can roll the planar die: Whenever you roll {CHAOS}, each player dicards a card
Effect chaosEffect = new DiscardEachPlayerEffect(TargetController.OPPONENT);
Target chaosTarget = null;
List<Effect> chaosEffects = new ArrayList<Effect>();
chaosEffects.add(chaosEffect);
List<Target> chaosTargets = new ArrayList<Target>();
chaosTargets.add(chaosTarget);
ActivateIfConditionActivatedAbility chaosAbility = new ActivateIfConditionActivatedAbility(Zone.COMMAND, new RollPlanarDieEffect(chaosEffects, chaosTargets), new GenericManaCost(0), MainPhaseStackEmptyCondition.instance);
chaosAbility.addWatcher(new PlanarRollWatcher());
this.getAbilities().add(chaosAbility);
chaosAbility.setMayActivate(TargetController.ANY);
this.getAbilities().add(new SimpleStaticAbility(Zone.ALL, new PlanarDieRollCostIncreasingEffect(chaosAbility.getOriginalId())));
}
}

View file

@ -0,0 +1,78 @@
/*
* 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.game.command.planes;
import java.util.ArrayList;
import java.util.List;
import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.MainPhaseStackEmptyCondition;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.RollPlanarDieEffect;
import mage.abilities.effects.common.SkipUntapStepEffect;
import mage.abilities.effects.common.UntapAllControllerEffect;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.common.FilterControlledPermanent;
import mage.game.command.Plane;
import mage.target.Target;
import mage.watchers.common.PlanarRollWatcher;
/**
*
* @author spjspj
*/
public class TheEonFogPlane extends Plane {
public TheEonFogPlane() {
this.setName("Plane - The Eon Fog");
this.setExpansionSetCodeForImage("PCA");
// All players miss their untap step
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new SkipUntapStepEffect());
this.getAbilities().add(ability);
// Active player can roll the planar die: Whenever you roll {CHAOS}, untap all permanents you control
Effect chaosEffect = new UntapAllControllerEffect(new FilterControlledPermanent());
Target chaosTarget = null;
List<Effect> chaosEffects = new ArrayList<Effect>();
chaosEffects.add(chaosEffect);
List<Target> chaosTargets = new ArrayList<Target>();
chaosTargets.add(chaosTarget);
ActivateIfConditionActivatedAbility chaosAbility = new ActivateIfConditionActivatedAbility(Zone.COMMAND, new RollPlanarDieEffect(chaosEffects, chaosTargets), new GenericManaCost(0), MainPhaseStackEmptyCondition.instance);
chaosAbility.addWatcher(new PlanarRollWatcher());
this.getAbilities().add(chaosAbility);
chaosAbility.setMayActivate(TargetController.ANY);
this.getAbilities().add(new SimpleStaticAbility(Zone.ALL, new PlanarDieRollCostIncreasingEffect(chaosAbility.getOriginalId())));
}
}

View file

@ -0,0 +1,87 @@
/*
* 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.game.command.planes;
import java.util.ArrayList;
import java.util.List;
import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.MainPhaseStackEmptyCondition;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.RevealLibraryPutIntoHandEffect;
import mage.abilities.effects.common.RollPlanarDieEffect;
import mage.abilities.effects.common.cost.SpellsCostReductionAllEffect;
import mage.constants.CardType;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.common.FilterCreatureCard;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.game.command.Plane;
import mage.target.Target;
import mage.watchers.common.PlanarRollWatcher;
/**
*
* @author spjspj
*/
public class TurriIslandPlane extends Plane {
private static final FilterCard filter = new FilterCard("creature spells");
static {
filter.add(new CardTypePredicate(CardType.CREATURE));
}
public TurriIslandPlane() {
this.setName("Plane - Turri Island");
this.setExpansionSetCodeForImage("PCA");
// Creature spells cost {2} less to cast.
Ability ability = new SimpleStaticAbility(Zone.COMMAND, new SpellsCostReductionAllEffect(filter, 2));
this.getAbilities().add(ability);
// Active player can roll the planar die: Whenever you roll {CHAOS}, reveal the top three cards of your library. Put all creature cards revealed this way into your hand and the rest into your graveyard.
Effect chaosEffect = new RevealLibraryPutIntoHandEffect(3, new FilterCreatureCard("creature cards"), Zone.GRAVEYARD);
Target chaosTarget = null;
List<Effect> chaosEffects = new ArrayList<Effect>();
chaosEffects.add(chaosEffect);
List<Target> chaosTargets = new ArrayList<Target>();
chaosTargets.add(chaosTarget);
ActivateIfConditionActivatedAbility chaosAbility = new ActivateIfConditionActivatedAbility(Zone.COMMAND, new RollPlanarDieEffect(chaosEffects, chaosTargets), new GenericManaCost(0), MainPhaseStackEmptyCondition.instance);
chaosAbility.addWatcher(new PlanarRollWatcher());
this.getAbilities().add(chaosAbility);
chaosAbility.setMayActivate(TargetController.ANY);
this.getAbilities().add(new SimpleStaticAbility(Zone.ALL, new PlanarDieRollCostIncreasingEffect(chaosAbility.getOriginalId())));
}
}

View file

@ -231,6 +231,7 @@ public class GameEvent implements Serializable {
CAN_TAKE_MULLIGAN, CAN_TAKE_MULLIGAN,
FLIP_COIN, COIN_FLIPPED, SCRY, FATESEAL, FLIP_COIN, COIN_FLIPPED, SCRY, FATESEAL,
ROLL_DICE, DICE_ROLLED, ROLL_DICE, DICE_ROLLED,
ROLL_PLANAR_DIE, PLANAR_DIE_ROLLED,
PAID_CUMULATIVE_UPKEEP, PAID_CUMULATIVE_UPKEEP,
DIDNT_PAY_CUMULATIVE_UPKEEP, DIDNT_PAY_CUMULATIVE_UPKEEP,
//permanent events //permanent events

View file

@ -57,6 +57,7 @@ import mage.choices.Choice;
import mage.constants.AbilityType; import mage.constants.AbilityType;
import mage.constants.ManaType; import mage.constants.ManaType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.PlanarDieRoll;
import mage.constants.PlayerAction; import mage.constants.PlayerAction;
import mage.constants.RangeOfInfluence; import mage.constants.RangeOfInfluence;
import mage.constants.Zone; import mage.constants.Zone;
@ -423,6 +424,11 @@ public interface Player extends MageItem, Copyable<Player> {
int rollDice(Game game, ArrayList<UUID> appliedEffects, int numSides); int rollDice(Game game, ArrayList<UUID> appliedEffects, int numSides);
PlanarDieRoll rollPlanarDie(Game game);
PlanarDieRoll rollPlanarDie(Game game, ArrayList<UUID> appliedEffects);
PlanarDieRoll rollPlanarDie(Game game, ArrayList<UUID> appliedEffects, int numberChaosSides, int numberPlanarSides);
@Deprecated @Deprecated
void discard(int amount, Ability source, Game game); void discard(int amount, Ability source, Game game);

View file

@ -2482,6 +2482,50 @@ public abstract class PlayerImpl implements Player, Serializable {
return event.getAmount(); return event.getAmount();
} }
@Override
public PlanarDieRoll rollPlanarDie(Game game) {
return this.rollPlanarDie(game, null);
}
@Override
public PlanarDieRoll rollPlanarDie(Game game, ArrayList<UUID> appliedEffects) {
return rollPlanarDie(game, appliedEffects, 1, 1);
}
/**
* @param game
* @param appliedEffects
* @param numberChaosSides The number of chaos sides the planar die currently has (normally 1 but can be 5)
* @param numberPlanarSides The number of chaos sides the planar die currently has (normally 1)
* @return the outcome that the player rolled. Either ChaosRoll, PlanarRoll or NilRoll
*/
@Override
public PlanarDieRoll rollPlanarDie(Game game, ArrayList<UUID> appliedEffects, int numberChaosSides, int numberPlanarSides) {
int result = RandomUtil.nextInt(6) + 1;
PlanarDieRoll roll = PlanarDieRoll.NIL_ROLL;
if (numberChaosSides + numberPlanarSides > 6) {
numberChaosSides = 1;
numberPlanarSides = 1;
}
if (result <= numberChaosSides) {
roll = PlanarDieRoll.CHAOS_ROLL;
}
else if (result > 6 - numberPlanarSides) {
roll = PlanarDieRoll.PLANAR_ROLL;
}
if (!game.isSimulation()) {
game.informPlayers("[Roll the planar die] " + getLogName() + " rolled a " + roll + " on the planar die");
}
GameEvent event = new GameEvent(GameEvent.EventType.ROLL_PLANAR_DIE, playerId, null, playerId, result, true);
event.setAppliedEffects(appliedEffects);
event.setData(roll + "");
if (!game.replaceEvent(event)) {
GameEvent ge = new GameEvent(GameEvent.EventType.PLANAR_DIE_ROLLED, playerId, null, playerId, event.getAmount(), event.getFlag());
ge.setData(roll + "");
game.fireEvent(ge);
}
return roll;
}
@Override @Override
public List<Permanent> getAvailableAttackers(Game game) { public List<Permanent> getAvailableAttackers(Game game) {
// TODO: get available opponents and their planeswalkers, check for each if permanent can attack one // TODO: get available opponents and their planeswalkers, check for each if permanent can attack one

View file

@ -0,0 +1,89 @@
/*
* 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.watchers.common;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import mage.constants.WatcherScope;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.watchers.Watcher;
/*
* Counts the number of times the planar die has been rolled per player per turn
* This watcher is automatically started in gameImpl.init for each game
*
* @author spjspj
*/
public class PlanarRollWatcher extends Watcher {
private final Map<UUID, Integer> numberTimesPlanarDieRolled = new HashMap<>();
public PlanarRollWatcher() {
super(PlanarRollWatcher.class.getSimpleName(), WatcherScope.GAME);
}
public PlanarRollWatcher(final PlanarRollWatcher watcher) {
super(watcher);
for (Entry<UUID, Integer> entry : watcher.numberTimesPlanarDieRolled.entrySet()) {
numberTimesPlanarDieRolled.put(entry.getKey(), entry.getValue());
}
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.PLANAR_DIE_ROLLED) {
UUID playerId = event.getPlayerId();
if (playerId != null) {
Integer amount = numberTimesPlanarDieRolled.get(playerId);
if (amount == null) {
amount = 1;
} else {
amount ++;
}
numberTimesPlanarDieRolled.put(playerId, amount);
}
}
}
public int getNumberTimesPlanarDieRolled(UUID playerId) {
return numberTimesPlanarDieRolled.getOrDefault(playerId, 0);
}
@Override
public void reset() {
numberTimesPlanarDieRolled.clear();
}
@Override
public PlanarRollWatcher copy() {
return new PlanarRollWatcher(this);
}
}