mirror of
https://github.com/correl/mage.git
synced 2025-01-12 03:00:13 +00:00
Merge origin/master
This commit is contained in:
commit
d28a956754
22 changed files with 430 additions and 104 deletions
|
@ -51,7 +51,7 @@ public class JoinTableDialog extends MageDialog {
|
|||
public JoinTableDialog() {
|
||||
initComponents();
|
||||
newPlayerPanel.showLevel(false);
|
||||
txtPassword.setText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_PASSWORD, ""));
|
||||
txtPassword.setText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_PASSWORD_JOIN, ""));
|
||||
}
|
||||
|
||||
public void showDialog(UUID roomId, UUID tableId, boolean isTournament, boolean isLimited) {
|
||||
|
@ -148,7 +148,7 @@ public class JoinTableDialog extends MageDialog {
|
|||
private void btnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOKActionPerformed
|
||||
Session session = MageFrame.getSession();
|
||||
try {
|
||||
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_PASSWORD, txtPassword.getText());
|
||||
PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_PASSWORD_JOIN, txtPassword.getText());
|
||||
if (isTournament) {
|
||||
joined = session.joinTournamentTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), "Human", 1, DeckImporterUtil.importDeck(this.newPlayerPanel.getDeckFile()), this.txtPassword.getText());
|
||||
} else {
|
||||
|
|
|
@ -164,6 +164,7 @@ public class PreferencesDialog extends javax.swing.JDialog {
|
|||
// pref setting for new table dialog
|
||||
public static final String KEY_NEW_TABLE_NAME = "newTableName";
|
||||
public static final String KEY_NEW_TABLE_PASSWORD = "newTablePassword";
|
||||
public static final String KEY_NEW_TABLE_PASSWORD_JOIN = "newTablePasswordJoin";
|
||||
public static final String KEY_NEW_TABLE_DECK_TYPE = "newTableDeckType";
|
||||
public static final String KEY_NEW_TABLE_TIME_LIMIT = "newTableTimeLimit";
|
||||
public static final String KEY_NEW_TABLE_GAME_TYPE = "newTableGameType";
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
package mage.sets.conflux;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
|
@ -36,6 +37,7 @@ import mage.abilities.Ability;
|
|||
import mage.abilities.DelayedTriggeredAbility;
|
||||
import mage.abilities.SpecialAction;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.DamageTargetEffect;
|
||||
import mage.abilities.effects.common.RemoveDelayedTriggeredAbilityEffect;
|
||||
|
@ -78,7 +80,8 @@ class QuenchableFireEffect extends OneShotEffect {
|
|||
|
||||
public QuenchableFireEffect() {
|
||||
super(Outcome.Damage);
|
||||
staticText = "{this} deals an additional 3 damage to that player at the beginning of your next upkeep step unless he or she pays {U} before that step";
|
||||
staticText = "{this} deals an additional 3 damage to that player at the beginning of your next upkeep step unless he or she pays {U} before that step."
|
||||
+ "<br><i>Use the Special button to pay the {U} with a special action before the beginning of your next upkeep step.</i>";
|
||||
}
|
||||
|
||||
public QuenchableFireEffect(final QuenchableFireEffect effect) {
|
||||
|
@ -92,22 +95,34 @@ class QuenchableFireEffect extends OneShotEffect {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
//create delayed triggered ability
|
||||
QuenchableFireDelayedTriggeredAbility delayedAbility = new QuenchableFireDelayedTriggeredAbility();
|
||||
delayedAbility.setSourceId(source.getSourceId());
|
||||
delayedAbility.setControllerId(source.getControllerId());
|
||||
delayedAbility.setSourceObject(source.getSourceObject(game), game);
|
||||
delayedAbility.getTargets().addAll(source.getTargets());
|
||||
game.addDelayedTriggeredAbility(delayedAbility);
|
||||
MageObject sourceObject = source.getSourceObject(game);
|
||||
if (sourceObject != null) {
|
||||
|
||||
//create special action
|
||||
QuenchableFireSpecialAction newAction = new QuenchableFireSpecialAction();
|
||||
|
||||
//create special action
|
||||
QuenchableFireSpecialAction newAction = new QuenchableFireSpecialAction(delayedAbility.getId());
|
||||
delayedAbility.setSpecialActionId(newAction.getId());
|
||||
newAction.setSourceId(source.getSourceId());
|
||||
newAction.setControllerId(source.getFirstTarget());
|
||||
newAction.getTargets().addAll(source.getTargets());
|
||||
game.getState().getSpecialActions().add(newAction);
|
||||
return true;
|
||||
//create delayed triggered ability
|
||||
QuenchableFireDelayedTriggeredAbility delayedAbility = new QuenchableFireDelayedTriggeredAbility();
|
||||
delayedAbility.setSourceId(source.getSourceId());
|
||||
delayedAbility.setControllerId(source.getControllerId());
|
||||
delayedAbility.setSourceObject(sourceObject, game);
|
||||
delayedAbility.getTargets().addAll(source.getTargets());
|
||||
delayedAbility.setSpecialActionId(newAction.getId());
|
||||
UUID delayedAbilityId = game.addDelayedTriggeredAbility(delayedAbility);
|
||||
|
||||
// update special action
|
||||
newAction.addCost(new ManaCostsImpl("{U}"));
|
||||
Effect effect = new RemoveDelayedTriggeredAbilityEffect(delayedAbilityId);
|
||||
newAction.addEffect(effect);
|
||||
effect.setText(sourceObject.getIdName() + " - Pay {U} to remove the triggered ability that deals 3 damage to you at the beginning of your next upkeep step");
|
||||
newAction.addEffect(new RemoveSpecialActionEffect(newAction.getId()));
|
||||
newAction.setSourceId(source.getSourceId());
|
||||
newAction.setControllerId(source.getFirstTarget());
|
||||
newAction.getTargets().addAll(source.getTargets());
|
||||
game.getState().getSpecialActions().add(newAction);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -151,11 +166,8 @@ class QuenchableFireDelayedTriggeredAbility extends DelayedTriggeredAbility {
|
|||
|
||||
class QuenchableFireSpecialAction extends SpecialAction {
|
||||
|
||||
public QuenchableFireSpecialAction(UUID effectId) {
|
||||
public QuenchableFireSpecialAction() {
|
||||
super();
|
||||
this.addCost(new ManaCostsImpl("{U}"));
|
||||
this.addEffect(new RemoveDelayedTriggeredAbilityEffect(effectId));
|
||||
this.addEffect(new RemoveSpecialActionEffect(this.getId()));
|
||||
}
|
||||
|
||||
public QuenchableFireSpecialAction(final QuenchableFireSpecialAction ability) {
|
||||
|
|
|
@ -42,6 +42,7 @@ import mage.abilities.effects.ContinuousEffectImpl;
|
|||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.DoIfCostPaid;
|
||||
import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect;
|
||||
import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect;
|
||||
import mage.abilities.effects.common.UntapEnchantedEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
|
||||
|
@ -96,7 +97,7 @@ public class DanceOfTheDead extends CardImpl {
|
|||
|
||||
// Enchanted creature gets +1/+1 and doesn't untap during its controller's untap step.
|
||||
ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1, Duration.WhileOnBattlefield));
|
||||
Effect effect = new DontUntapInControllersUntapStepSourceEffect();
|
||||
Effect effect = new DontUntapInControllersUntapStepEnchantedEffect();
|
||||
effect.setText("and doesn't untap during its controller's untap step");
|
||||
ability.addEffect(effect);
|
||||
this.addAbility(ability);
|
||||
|
@ -144,7 +145,7 @@ class DanceOfTheDeadReAttachEffect extends OneShotEffect {
|
|||
}
|
||||
|
||||
// put card into play
|
||||
controller.putOntoBattlefieldWithInfo(cardInGraveyard, game, Zone.GRAVEYARD, source.getSourceId());
|
||||
controller.putOntoBattlefieldWithInfo(cardInGraveyard, game, Zone.GRAVEYARD, source.getSourceId(), true);
|
||||
Permanent enchantedCreature = game.getPermanent(cardInGraveyard.getId());
|
||||
|
||||
FilterCreaturePermanent filter = new FilterCreaturePermanent("enchant creature put onto the battlefield with Dance of the Dead");
|
||||
|
|
|
@ -110,7 +110,9 @@ class PhantasmalImageCopyEffect extends OneShotEffect {
|
|||
if (!permanent.getSubtype().contains("Illusion")) {
|
||||
permanent.getSubtype().add("Illusion");
|
||||
}
|
||||
permanent.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect()), game);
|
||||
// Add directly because the created permanent is only used to copy from, so there is no need to add the ability to e.g. TriggeredAbilities
|
||||
permanent.getAbilities().add(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect()));
|
||||
//permanent.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect()), game);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -36,8 +36,10 @@ import mage.constants.Zone;
|
|||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.CopyPermanentEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
|
@ -54,7 +56,15 @@ import mage.util.functions.ApplyToPermanent;
|
|||
* @author Loki
|
||||
*/
|
||||
public class PhyrexianMetamorph extends CardImpl {
|
||||
|
||||
private static final FilterPermanent filter = new FilterPermanent("artifact or creature");
|
||||
|
||||
static {
|
||||
filter.add(Predicates.or(
|
||||
new CardTypePredicate(CardType.ARTIFACT),
|
||||
new CardTypePredicate(CardType.CREATURE)));
|
||||
}
|
||||
|
||||
public PhyrexianMetamorph (UUID ownerId) {
|
||||
super(ownerId, 42, "Phyrexian Metamorph", Rarity.RARE, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{UP}");
|
||||
this.expansionSetCode = "NPH";
|
||||
|
@ -63,10 +73,21 @@ public class PhyrexianMetamorph extends CardImpl {
|
|||
this.power = new MageInt(0);
|
||||
this.toughness = new MageInt(0);
|
||||
|
||||
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect(
|
||||
new PhyrexianMetamorphEffect(),
|
||||
"You may have {this} enter the battlefield as a copy of any artifact or creature on the battlefield, except it's an artifact in addition to its other types",
|
||||
true));
|
||||
ApplyToPermanent phyrexianMetamorphApplier = new ApplyToPermanent() {
|
||||
@Override
|
||||
public Boolean apply(Game game, Permanent permanent) {
|
||||
if (!permanent.getCardType().contains(CardType.ARTIFACT)) {
|
||||
permanent.getCardType().add(CardType.ARTIFACT);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// {UP} ( can be paid with either {U} or 2 life.)
|
||||
// You may have Phyrexian Metamorph enter the battlefield as a copy of any artifact or creature on the battlefield, except it's an artifact in addition to its other types.
|
||||
Effect effect = new CopyPermanentEffect(filter, phyrexianMetamorphApplier);
|
||||
effect.setText("You may have {this} enter the battlefield as a copy of any artifact or creature on the battlefield, except it's an artifact in addition to its other types");
|
||||
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect(effect));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
|
@ -80,56 +101,3 @@ public class PhyrexianMetamorph extends CardImpl {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
class PhyrexianMetamorphEffect extends OneShotEffect {
|
||||
|
||||
private static final FilterPermanent filter = new FilterPermanent("artifact or creature");
|
||||
|
||||
static {
|
||||
filter.add(Predicates.or(
|
||||
new CardTypePredicate(CardType.ARTIFACT),
|
||||
new CardTypePredicate(CardType.CREATURE)));
|
||||
}
|
||||
|
||||
public PhyrexianMetamorphEffect() {
|
||||
super(Outcome.Copy);
|
||||
}
|
||||
|
||||
public PhyrexianMetamorphEffect(final PhyrexianMetamorphEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||
if (player != null && sourcePermanent != null) {
|
||||
Target target = new TargetPermanent(filter);
|
||||
target.setNotTarget(true);
|
||||
if (target.canChoose(source.getControllerId(), game)) {
|
||||
player.choose(Outcome.Copy, target, source.getSourceId(), game);
|
||||
Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget());
|
||||
if (copyFromPermanent != null) {
|
||||
game.copyPermanent(copyFromPermanent, sourcePermanent, source, new ApplyToPermanent() {
|
||||
@Override
|
||||
public Boolean apply(Game game, Permanent permanent) {
|
||||
if (!permanent.getCardType().contains(CardType.ARTIFACT)) {
|
||||
permanent.getCardType().add(CardType.ARTIFACT);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PhyrexianMetamorphEffect copy() {
|
||||
return new PhyrexianMetamorphEffect(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -54,9 +54,11 @@ public class WurmcoilEngine extends CardImpl {
|
|||
this.power = new MageInt(6);
|
||||
this.toughness = new MageInt(6);
|
||||
|
||||
|
||||
// Deathtouch, lifelink
|
||||
this.addAbility(DeathtouchAbility.getInstance());
|
||||
this.addAbility(LifelinkAbility.getInstance());
|
||||
|
||||
// When Wurmcoil Engine dies, put a 3/3 colorless Wurm artifact creature token with deathtouch and a 3/3 colorless Wurm artifact creature token with lifelink onto the battlefield.
|
||||
Ability ability = new DiesTriggeredAbility(new CreateTokenEffect(new Wurm1Token(expansionSetCode)), false);
|
||||
ability.addEffect(new CreateTokenEffect(new Wurm2Token(expansionSetCode)));
|
||||
this.addAbility(ability);
|
||||
|
|
|
@ -53,6 +53,7 @@ public class Clone extends CardImpl {
|
|||
this.power = new MageInt(0);
|
||||
this.toughness = new MageInt(0);
|
||||
|
||||
// You may have Clone enter the battlefield as a copy of any creature on the battlefield.
|
||||
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new EntersBattlefieldEffect(
|
||||
new CopyPermanentEffect(),
|
||||
"You may have {this} enter the battlefield as a copy of any creature on the battlefield",
|
||||
|
|
|
@ -61,7 +61,11 @@ public class Nightmare extends CardImpl {
|
|||
|
||||
this.power = new MageInt(0);
|
||||
this.toughness = new MageInt(0);
|
||||
|
||||
// Flying
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// Nightmare's power and toughness are each equal to the number of Swamps you control.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new PermanentsOnBattlefieldCount(filter), Duration.EndOfGame)));
|
||||
}
|
||||
|
||||
|
|
142
Mage.Sets/src/mage/sets/urzasdestiny/Repercussion.java
Normal file
142
Mage.Sets/src/mage/sets/urzasdestiny/Repercussion.java
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* 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.sets.urzasdestiny;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbility;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
|
||||
import mage.cards.CardImpl;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author cbrianhill
|
||||
*/
|
||||
public class Repercussion extends CardImpl {
|
||||
|
||||
public Repercussion(UUID ownerId) {
|
||||
super(ownerId, 95, "Repercussion", Rarity.RARE, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{R}");
|
||||
this.expansionSetCode = "UDS";
|
||||
|
||||
// Whenever a creature is dealt damage, Repercussion deals that much damage to that creature's controller.
|
||||
this.addAbility(new RepercussionTriggeredAbility(new RepercussionEffect()));
|
||||
}
|
||||
|
||||
public Repercussion(final Repercussion card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Repercussion copy() {
|
||||
return new Repercussion(this);
|
||||
}
|
||||
}
|
||||
|
||||
class RepercussionTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
static final String PLAYER_DAMAGE_AMOUNT_KEY = "playerDamage";
|
||||
static final String TRIGGERING_CREATURE_KEY = "triggeringCreature";
|
||||
|
||||
public RepercussionTriggeredAbility(Effect effect) {
|
||||
super(Zone.BATTLEFIELD, effect);
|
||||
}
|
||||
|
||||
public RepercussionTriggeredAbility(final RepercussionTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DAMAGED_CREATURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
for(Effect effect : getEffects()) {
|
||||
effect.setValue(PLAYER_DAMAGE_AMOUNT_KEY, event.getAmount());
|
||||
effect.setValue(TRIGGERING_CREATURE_KEY, new MageObjectReference(event.getTargetId(), game));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever a creature is dealt damage, {this} deals that much damage to that creature's controller.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public TriggeredAbility copy() {
|
||||
return new RepercussionTriggeredAbility(this);
|
||||
}
|
||||
}
|
||||
|
||||
class RepercussionEffect extends OneShotEffect {
|
||||
|
||||
public RepercussionEffect() {
|
||||
super(Outcome.Damage);
|
||||
}
|
||||
|
||||
public RepercussionEffect(final RepercussionEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Integer playerDamage = (Integer)this.getValue(RepercussionTriggeredAbility.PLAYER_DAMAGE_AMOUNT_KEY);
|
||||
MageObjectReference mor = (MageObjectReference)this.getValue(RepercussionTriggeredAbility.TRIGGERING_CREATURE_KEY);
|
||||
if (playerDamage != null && mor != null) {
|
||||
Permanent creature = mor.getPermanentOrLKIBattlefield(game);
|
||||
if (creature != null) {
|
||||
Player player = game.getPlayer(creature.getControllerId());
|
||||
if (player != null) {
|
||||
player.damage(playerDamage, source.getSourceId(), game, false, true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Effect copy() {
|
||||
return new RepercussionEffect(this);
|
||||
}
|
||||
|
||||
}
|
|
@ -40,7 +40,6 @@ import mage.constants.CardType;
|
|||
import mage.constants.Rarity;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterControlledPermanent;
|
||||
import mage.filter.common.FilterNonlandPermanent;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||
import mage.target.common.TargetControlledPermanent;
|
||||
|
|
|
@ -108,9 +108,11 @@ public class CloneTest extends CardTestPlayerBase {
|
|||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 6);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Forest", 1);
|
||||
// Target creature you control gets +1/+1 and gains hexproof until end of turn. (It can't be the target of spells or abilities your opponents control.)
|
||||
addCard(Zone.HAND, playerB, "Ranger's Guile");
|
||||
|
||||
addCard(Zone.HAND, playerA, "Clone");
|
||||
// Return target nonland permanent to its owner's hand.
|
||||
addCard(Zone.HAND, playerA, "Disperse");
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Nightmare", 1);
|
||||
|
|
|
@ -525,5 +525,50 @@ public class PhantasmalImageTest extends CardTestPlayerBase {
|
|||
assertPermanentCount(playerB, "Butcher Ghoul", 1);
|
||||
assertPowerToughness(playerB, "Butcher Ghoul", 2, 2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 12:29: Attacker: Wurmcoil Engine [466] (6/6) blocked by Wurmcoil Engine
|
||||
* [4ed] (6/6)
|
||||
* 12:29: yespair gains 6 life
|
||||
* 12:29: HipSomHap gains 6 life
|
||||
* 12:29: Wurmcoil Engine [4ed] died
|
||||
* 12:29: Ability triggers: Wurmcoil Engine [4ed] - When Wurmcoil Engine [4ed] dies, put a a 3/3 colorless
|
||||
* Wurm artifact creature token with deathtouch onto the battlefield. Put a
|
||||
* a 3/3 colorless Wurm artifact creature token with lifelink onto the
|
||||
* battlefield.
|
||||
* 12:29: Phantasmal Image [466] died
|
||||
* 12:29: HipSomHap puts a Wurm [7d0] token onto the battlefield
|
||||
* 12:29: HipSomHap puts a Wurm [186] token onto the battlefield
|
||||
*
|
||||
* To the best of my knowledge, the Phantasmal Image [466], which entered
|
||||
* the battlefield as a Wurmcoil Engine, should grant tokens through the
|
||||
* Dies-trigger as well, right?
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testDiesTriggered2() {
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Wurmcoil Engine");
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||
addCard(Zone.HAND, playerA, "Phantasmal Image");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image"); // not targeted
|
||||
setChoice(playerB, "Wurmcoil Engine");
|
||||
|
||||
attack(2, playerB, "Wurmcoil Engine");
|
||||
block(2, playerA, "Wurmcoil Engine", "Wurmcoil Engine");
|
||||
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertLife(playerB, 26);
|
||||
assertLife(playerA, 26);
|
||||
|
||||
assertGraveyardCount(playerA, "Phantasmal Image", 1);
|
||||
assertGraveyardCount(playerB, "Wurmcoil Engine", 1);
|
||||
|
||||
assertPermanentCount(playerA, "Wurm", 2);
|
||||
assertPermanentCount(playerB, "Wurm", 2);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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 org.mage.test.cards.copy;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class PhyrexianMetamorphTest extends CardTestPlayerBase {
|
||||
|
||||
|
||||
@Test
|
||||
public void testCopyCreature() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
|
||||
|
||||
// You may have Phyrexian Metamorph enter the battlefield as a copy of any artifact or creature on the battlefield, except it's an artifact in addition to its other types.
|
||||
addCard(Zone.HAND, playerA, "Phyrexian Metamorph"); // {3}{UP}
|
||||
addCard(Zone.HAND, playerA, "Cloudshift");
|
||||
|
||||
//Flying
|
||||
// Vanishing 3 (This permanent enters the battlefield with three time counters on it. At the beginning of your upkeep, remove a time counter from it. When the last is removed, sacrifice it.)
|
||||
// When Aven Riftwatcher enters the battlefield or leaves the battlefield, you gain 2 life.
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Aven Riftwatcher"); // 2/3
|
||||
|
||||
// When Ponyback Brigade enters the battlefield or is turned face up, put three 1/1 red Goblin creature tokens onto the battlefield.
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Ponyback Brigade"); // 2/2
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Metamorph");
|
||||
setChoice(playerA, "Aven Riftwatcher");
|
||||
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cloudshift", "Aven Riftwatcher");
|
||||
setChoice(playerA, "Ponyback Brigade");
|
||||
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 24);
|
||||
assertLife(playerB, 20);
|
||||
|
||||
assertGraveyardCount(playerA, "Cloudshift", 1);
|
||||
|
||||
assertPermanentCount(playerA, "Ponyback Brigade", 1);
|
||||
assertPermanentCount(playerA, "Goblin", 3);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* An opponent cast Phyrexian Metamorph and cloned another opponent's
|
||||
* Maelstrom Wanderer(his Commander). The first opponent then dealt combat
|
||||
* damage with Brago, King Eternal and chose to flicker several permanents,
|
||||
* including the Phyrexian Metamorph/Maelstrom Wanderer, but he was not able
|
||||
* to choose a new creature to clone when the Phyrexian Metamorph re-entered
|
||||
* the battlefield.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testFlickerWithBrago() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||
|
||||
// You may have Phyrexian Metamorph enter the battlefield as a copy of any artifact or creature on the battlefield, except it's an artifact in addition to its other types.
|
||||
addCard(Zone.HAND, playerA, "Phyrexian Metamorph"); // {3}{UP}
|
||||
|
||||
// Flying
|
||||
// When Brago, King Eternal deals combat damage to a player, exile any number of target nonland permanents you control, then return those cards to the battlefield under their owner's control.
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Brago, King Eternal"); // 2/4
|
||||
|
||||
// Creatures you control have haste.
|
||||
// Cascade, cascade
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Maelstrom Wanderer"); // 7/5
|
||||
// When Ponyback Brigade enters the battlefield or is turned face up, put three 1/1 red Goblin creature tokens onto the battlefield.
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Ponyback Brigade"); // 2/2
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Metamorph");
|
||||
setChoice(playerA, "Maelstrom Wanderer");
|
||||
|
||||
attack(3, playerA, "Brago, King Eternal");
|
||||
addTarget(playerA, "Maelstrom Wanderer");
|
||||
setChoice(playerA, "Ponyback Brigade");
|
||||
|
||||
setStopAt(3, PhaseStep.END_COMBAT);
|
||||
execute();
|
||||
|
||||
assertLife(playerA, 20);
|
||||
assertLife(playerB, 18);
|
||||
|
||||
assertPermanentCount(playerA, "Ponyback Brigade", 1);
|
||||
assertPermanentCount(playerA, "Goblin", 3);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -247,7 +247,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
return false;
|
||||
}
|
||||
game.applyEffects();
|
||||
|
||||
|
||||
/* 20130201 - 601.2b
|
||||
* If the spell is modal the player announces the mode choice (see rule 700.2).
|
||||
*/
|
||||
|
|
|
@ -61,4 +61,7 @@ public interface ContinuousEffect extends Effect {
|
|||
void newId();
|
||||
@Override
|
||||
ContinuousEffect copy();
|
||||
|
||||
boolean isTemporary();
|
||||
void setTemporary(boolean temporary);
|
||||
}
|
||||
|
|
|
@ -68,7 +68,8 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
protected boolean discarded = false; // for manual effect discard
|
||||
protected boolean affectedObjectsSet = false;
|
||||
protected List<MageObjectReference> affectedObjectList = new ArrayList<>();
|
||||
|
||||
protected boolean temporary = false;
|
||||
|
||||
// until your next turn
|
||||
protected int startingTurn;
|
||||
protected UUID startingControllerId;
|
||||
|
@ -96,6 +97,7 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
this.discarded = effect.discarded;
|
||||
this.affectedObjectsSet = effect.affectedObjectsSet;
|
||||
this.affectedObjectList.addAll(effect.affectedObjectList);
|
||||
this.temporary = effect.temporary;
|
||||
this.startingTurn = effect.startingTurn;
|
||||
this.startingControllerId = effect.startingControllerId;
|
||||
}
|
||||
|
@ -234,4 +236,18 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu
|
|||
return affectedObjectList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status if the effect is temporary added to the ContinuousEffects
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean isTemporary() {
|
||||
return temporary;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTemporary(boolean temporary) {
|
||||
this.temporary = temporary;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -939,6 +939,7 @@ public class ContinuousEffects implements Serializable {
|
|||
*/
|
||||
public void addEffect(ContinuousEffect effect, UUID sourceId, Ability source) {
|
||||
if (!(source instanceof MageSingleton)) { // because MageSingletons may never be removed by removing the temporary effecs they are not added to the temporaryEffects to prevent this
|
||||
effect.setTemporary(true);
|
||||
Set abilities = temporaryEffects.get(effect);
|
||||
if (abilities == null) {
|
||||
abilities = new HashSet<>();
|
||||
|
|
|
@ -40,6 +40,7 @@ import mage.constants.Duration;
|
|||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentCard;
|
||||
|
@ -56,6 +57,7 @@ public class CopyEffect extends ContinuousEffectImpl {
|
|||
* Object we copy from
|
||||
*/
|
||||
private MageObject target;
|
||||
|
||||
private UUID sourceId;
|
||||
private ApplyToPermanent applier;
|
||||
|
||||
|
@ -79,23 +81,21 @@ public class CopyEffect extends ContinuousEffectImpl {
|
|||
@Override
|
||||
public void init(Ability source, Game game) {
|
||||
super.init(source, game);
|
||||
if (affectedObjectsSet) {
|
||||
affectedObjectList.add(new MageObjectReference(sourceId, game));
|
||||
}
|
||||
affectedObjectList.add(new MageObjectReference(getSourceId(), game));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent;
|
||||
if (affectedObjectsSet) {
|
||||
permanent = affectedObjectList.get(0).getPermanent(game);
|
||||
} else {
|
||||
permanent = game.getPermanent(this.sourceId);
|
||||
}
|
||||
Permanent permanent = affectedObjectList.get(0).getPermanent(game);
|
||||
if (permanent == null) {
|
||||
discard();
|
||||
return false;
|
||||
permanent = (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD, source.getSourceObjectZoneChangeCounter());
|
||||
// As long as the permanent is still in the LKI continue to copy to get triggered abilities to TriggeredAbilites for dies events.
|
||||
if (permanent == null) {
|
||||
discard();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
permanent.setCopy(true);
|
||||
permanent.setName(target.getName());
|
||||
permanent.getColor(game).setColor(target.getColor(game));
|
||||
permanent.getManaCost().clear();
|
||||
|
@ -134,9 +134,7 @@ public class CopyEffect extends ContinuousEffectImpl {
|
|||
} else if (target instanceof PermanentToken || target instanceof Card) {
|
||||
permanent.setCardNumber(((Card) target).getCardNumber());
|
||||
permanent.setExpansionSetCode(((Card) target).getExpansionSetCode());
|
||||
}
|
||||
|
||||
permanent.setCopy(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,8 +36,8 @@ import mage.constants.Duration;
|
|||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -76,12 +76,16 @@ public class SetPowerToughnessSourceEffect extends ContinuousEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
MageObject mageObject = game.getObject(source.getSourceId());
|
||||
MageObject mageObject = game.getObject(source.getSourceId());
|
||||
if (mageObject == null) {
|
||||
if (duration.equals(Duration.Custom)) {
|
||||
discard();
|
||||
}
|
||||
return false;
|
||||
} else if (isTemporary()) { // it's somehow w
|
||||
if (!(mageObject instanceof Permanent)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (amount != null) {
|
||||
int value = amount.calculate(game, source, this);
|
||||
|
|
|
@ -253,7 +253,7 @@ public interface Game extends MageItem, Serializable {
|
|||
Card copyCard(Card cardToCopy, Ability source, UUID newController);
|
||||
|
||||
void addTriggeredAbility(TriggeredAbility ability);
|
||||
void addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility);
|
||||
UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility);
|
||||
void applyEffects();
|
||||
boolean checkStateAndTriggered();
|
||||
void playPriority(UUID activePlayerId, boolean resuming);
|
||||
|
|
|
@ -1383,11 +1383,12 @@ public abstract class GameImpl implements Game, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility) {
|
||||
public UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility) {
|
||||
DelayedTriggeredAbility newAbility = delayedAbility.copy();
|
||||
newAbility.newId();
|
||||
newAbility.init(this);
|
||||
state.addDelayedTriggeredAbility(newAbility);
|
||||
return newAbility.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue