* Soulbond - Reworked to two triggerd abilities (fixes #1882).

This commit is contained in:
LevelX2 2016-04-16 02:43:52 +02:00
parent 3b98d0714d
commit 1dbba3f7a9
32 changed files with 374 additions and 285 deletions

View file

@ -186,16 +186,14 @@ public class CardView extends SimpleCardView {
this.rules.add("You may cast this card as a 2/2 face-down creature, with no text," this.rules.add("You may cast this card as a 2/2 face-down creature, with no text,"
+ " no name, no subtypes, and no mana cost by paying {3} rather than paying its mana cost."); + " no name, no subtypes, and no mana cost by paying {3} rather than paying its mana cost.");
return; return;
} else if (card instanceof Permanent) {
this.power = Integer.toString(card.getPower().getValue());
this.toughness = Integer.toString(card.getToughness().getValue());
this.cardTypes = card.getCardType();
this.faceDown = ((Permanent) card).isFaceDown(game);
} else { } else {
if (card instanceof Permanent) { // this.hideInfo = true;
this.power = Integer.toString(card.getPower().getValue()); return;
this.toughness = Integer.toString(card.getToughness().getValue());
this.cardTypes = card.getCardType();
this.faceDown = ((Permanent) card).isFaceDown(game);
} else {
// this.hideInfo = true;
return;
}
} }
} }
@ -203,18 +201,16 @@ public class CardView extends SimpleCardView {
if (card.isSplitCard()) { if (card.isSplitCard()) {
splitCard = (SplitCard) card; splitCard = (SplitCard) card;
rotate = true; rotate = true;
} else { } else if (card instanceof Spell) {
if (card instanceof Spell) { switch (((Spell) card).getSpellAbility().getSpellAbilityType()) {
switch (((Spell) card).getSpellAbility().getSpellAbilityType()) { case SPLIT_FUSED:
case SPLIT_FUSED: splitCard = (SplitCard) ((Spell) card).getCard();
splitCard = (SplitCard) ((Spell) card).getCard(); rotate = true;
rotate = true; break;
break; case SPLIT_LEFT:
case SPLIT_LEFT: case SPLIT_RIGHT:
case SPLIT_RIGHT: rotate = true;
rotate = true; break;
break;
}
} }
} }
if (splitCard != null) { if (splitCard != null) {
@ -241,7 +237,7 @@ public class CardView extends SimpleCardView {
this.mageObjectType = MageObjectType.PERMANENT; this.mageObjectType = MageObjectType.PERMANENT;
Permanent permanent = (Permanent) card; Permanent permanent = (Permanent) card;
this.loyalty = Integer.toString(permanent.getCounters().getCount(CounterType.LOYALTY)); this.loyalty = Integer.toString(permanent.getCounters().getCount(CounterType.LOYALTY));
this.pairedCard = permanent.getPairedCard(); this.pairedCard = permanent.getPairedCard() != null ? permanent.getPairedCard().getSourceId() : null;
if (!permanent.getControllerId().equals(permanent.getOwnerId())) { if (!permanent.getControllerId().equals(permanent.getOwnerId())) {
controlledByOwner = false; controlledByOwner = false;
} }
@ -421,12 +417,10 @@ public class CardView extends SimpleCardView {
if (card != null) { if (card != null) {
if (card instanceof Permanent) { if (card instanceof Permanent) {
this.mageObjectType = MageObjectType.PERMANENT; this.mageObjectType = MageObjectType.PERMANENT;
} else if (card.isCopy()) {
this.mageObjectType = MageObjectType.COPY_CARD;
} else { } else {
if (card.isCopy()) { this.mageObjectType = MageObjectType.CARD;
this.mageObjectType = MageObjectType.COPY_CARD;
} else {
this.mageObjectType = MageObjectType.CARD;
}
} }
if (card instanceof PermanentToken) { if (card instanceof PermanentToken) {
this.mageObjectType = MageObjectType.TOKEN; this.mageObjectType = MageObjectType.TOKEN;

View file

@ -58,7 +58,7 @@ public class DeadeyeNavigator extends CardImpl {
this.toughness = new MageInt(5); this.toughness = new MageInt(5);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Deadeye Navigator is paired with another creature, each of those creatures has "{1}{U}: Exile this creature, then return it to the battlefield under your control." // As long as Deadeye Navigator is paired with another creature, each of those creatures has "{1}{U}: Exile this creature, then return it to the battlefield under your control."
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileSourceEffect(true), new ManaCostsImpl("{1}{U}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileSourceEffect(true), new ManaCostsImpl("{1}{U}"));

View file

@ -64,7 +64,7 @@ public class DiregrafEscort extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Diregraf Escort is paired with another creature, both creatures have protection from Zombies. // As long as Diregraf Escort is paired with another creature, both creatures have protection from Zombies.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(new ProtectionAbility(filter), ruleText))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(new ProtectionAbility(filter), ruleText)));

View file

@ -55,7 +55,7 @@ public class DruidsFamiliar extends CardImpl {
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Druid's Familiar is paired with another creature, each of those creatures gets +2/+2. // As long as Druid's Familiar is paired with another creature, each of those creatures gets +2/+2.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostPairedEffect(2, 2, ruleText))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostPairedEffect(2, 2, ruleText)));

View file

@ -55,7 +55,7 @@ public class ElgaudShieldmate extends CardImpl {
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Elgaud Shieldmate is paired with another creature, both creatures have hexproof. // As long as Elgaud Shieldmate is paired with another creature, both creatures have hexproof.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(HexproofAbility.getInstance(), ruleText))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(HexproofAbility.getInstance(), ruleText)));

View file

@ -27,21 +27,20 @@
*/ */
package mage.sets.avacynrestored; package mage.sets.avacynrestored;
import mage.constants.CardType; import java.util.UUID;
import mage.constants.Rarity;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.RestrictionEffect;
import mage.abilities.keyword.SoulbondAbility; import mage.abilities.keyword.SoulbondAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Rarity;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import java.util.UUID;
/** /**
* @author noxx * @author noxx
*/ */
@ -83,17 +82,26 @@ class FloweringLumberknotEffect extends RestrictionEffect {
@Override @Override
public boolean applies(Permanent permanent, Ability source, Game game) { public boolean applies(Permanent permanent, Ability source, Game game) {
if (permanent.getId().equals(source.getSourceId())) { if (permanent.getId().equals(source.getSourceId())) {
if (permanent.getPairedCard() == null) { if (permanent.getPairedCard() != null) {
return true; // not paired => can't attack or block Permanent paired = permanent.getPairedCard().getPermanent(game);
if (paired != null) {
boolean found = false;
for (Ability ability : paired.getAbilities(game)) {
if (ability instanceof SoulbondAbility) {
found = true;
break;
}
}
if (found) {
return false;// paired => can attack or block
}
}
} }
Permanent paired = game.getPermanent(permanent.getPairedCard()); // can't attack or block
if (paired != null && paired.getAbilities().contains(SoulbondAbility.getInstance())) {
return false; // paired => can attack or block
}
// can't attack or block otherwise
return true; return true;
} }
return false; return false;
} }
@Override @Override

View file

@ -58,7 +58,7 @@ public class GalvanicAlchemist extends CardImpl {
this.toughness = new MageInt(4); this.toughness = new MageInt(4);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Galvanic Alchemist is paired with another creature, each of those creatures has "{2}{U}: Untap this creature." // As long as Galvanic Alchemist is paired with another creature, each of those creatures has "{2}{U}: Untap this creature."
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new UntapSourceEffect(), new ManaCostsImpl("{2}{U}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new UntapSourceEffect(), new ManaCostsImpl("{2}{U}"));

View file

@ -55,7 +55,7 @@ public class GeistTrappers extends CardImpl {
this.toughness = new MageInt(5); this.toughness = new MageInt(5);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Geist Trappers is paired with another creature, both creatures have reach. // As long as Geist Trappers is paired with another creature, both creatures have reach.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(ReachAbility.getInstance(), ruleText))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(ReachAbility.getInstance(), ruleText)));

View file

@ -55,7 +55,7 @@ public class HanweirLancer extends CardImpl {
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Hanweir Lancer is paired with another creature, both creatures have first strike. // As long as Hanweir Lancer is paired with another creature, both creatures have first strike.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(FirstStrikeAbility.getInstance(), ruleText))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(FirstStrikeAbility.getInstance(), ruleText)));

View file

@ -27,21 +27,21 @@
*/ */
package mage.sets.avacynrestored; package mage.sets.avacynrestored;
import mage.constants.CardType; import java.util.UUID;
import mage.constants.Rarity; import mage.MageObjectReference;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ContinuousEffectImpl;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Layer; import mage.constants.Layer;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Rarity;
import mage.constants.SubLayer; import mage.constants.SubLayer;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/** /**
* @author noxx * @author noxx
*/ */
@ -51,7 +51,6 @@ public class JointAssault extends CardImpl {
super(ownerId, 183, "Joint Assault", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{G}"); super(ownerId, 183, "Joint Assault", Rarity.COMMON, new CardType[]{CardType.INSTANT}, "{G}");
this.expansionSetCode = "AVR"; this.expansionSetCode = "AVR";
// Target creature gets +2/+2 until end of turn. If it's paired with a creature, that creature also gets +2/+2 until end of turn. // Target creature gets +2/+2 until end of turn. If it's paired with a creature, that creature also gets +2/+2 until end of turn.
this.getSpellAbility().addEffect(new JointAssaultBoostTargetEffect(2, 2, Duration.EndOfTurn)); this.getSpellAbility().addEffect(new JointAssaultBoostTargetEffect(2, 2, Duration.EndOfTurn));
this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addTarget(new TargetCreaturePermanent());
@ -69,9 +68,9 @@ public class JointAssault extends CardImpl {
class JointAssaultBoostTargetEffect extends ContinuousEffectImpl { class JointAssaultBoostTargetEffect extends ContinuousEffectImpl {
private int power; private final int power;
private int toughness; private final int toughness;
private UUID paired; private MageObjectReference paired;
public JointAssaultBoostTargetEffect(int power, int toughness, Duration duration) { public JointAssaultBoostTargetEffect(int power, int toughness, Duration duration) {
super(duration, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature); super(duration, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature);
@ -116,10 +115,10 @@ class JointAssaultBoostTargetEffect extends ContinuousEffectImpl {
} }
if (this.paired != null) { if (this.paired != null) {
Permanent paired = game.getPermanent(this.paired); Permanent pairedPermanent = this.paired.getPermanent(game);
if (paired != null) { if (pairedPermanent != null) {
paired.addPower(power); pairedPermanent.addPower(power);
paired.addToughness(toughness); pairedPermanent.addToughness(toughness);
affectedTargets++; affectedTargets++;
} }
} }

View file

@ -57,7 +57,7 @@ public class LightningMauler extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Lightning Mauler is paired with another creature, both creatures have haste. // As long as Lightning Mauler is paired with another creature, both creatures have haste.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(HasteAbility.getInstance(), ruleText))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(HasteAbility.getInstance(), ruleText)));

View file

@ -55,7 +55,7 @@ public class NearheathPilgrim extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Nearheath Pilgrim is paired with another creature, both creatures have lifelink. // As long as Nearheath Pilgrim is paired with another creature, both creatures have lifelink.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(LifelinkAbility.getInstance(), ruleText))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(LifelinkAbility.getInstance(), ruleText)));

View file

@ -55,7 +55,7 @@ public class NightshadePeddler extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Nightshade Peddler is paired with another creature, both creatures have deathtouch. // As long as Nightshade Peddler is paired with another creature, both creatures have deathtouch.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(DeathtouchAbility.getInstance(), ruleText))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(DeathtouchAbility.getInstance(), ruleText)));

View file

@ -54,7 +54,7 @@ public class PathbreakerWurm extends CardImpl {
this.toughness = new MageInt(4); this.toughness = new MageInt(4);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Pathbreaker Wurm is paired with another creature, both creatures have trample. // As long as Pathbreaker Wurm is paired with another creature, both creatures have trample.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(TrampleAbility.getInstance(), ruleText))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(TrampleAbility.getInstance(), ruleText)));

View file

@ -55,7 +55,7 @@ public class SilverbladePaladin extends CardImpl {
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Silverblade Paladin is paired with another creature, both creatures have double strike. // As long as Silverblade Paladin is paired with another creature, both creatures have double strike.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(DoubleStrikeAbility.getInstance(), ruleText))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(DoubleStrikeAbility.getInstance(), ruleText)));

View file

@ -55,7 +55,7 @@ public class SpectralGateguards extends CardImpl {
this.toughness = new MageInt(5); this.toughness = new MageInt(5);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Spectral Gateguards is paired with another creature, both creatures have vigilance. // As long as Spectral Gateguards is paired with another creature, both creatures have vigilance.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(VigilanceAbility.getInstance(), ruleText))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(VigilanceAbility.getInstance(), ruleText)));

View file

@ -59,7 +59,7 @@ public class SternMentor extends CardImpl {
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Stern Mentor is paired with another creature, each of those creatures has "{T}: Target player puts the top two cards of his or her library into his or her graveyard." // As long as Stern Mentor is paired with another creature, each of those creatures has "{T}: Target player puts the top two cards of his or her library into his or her graveyard."
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutLibraryIntoGraveTargetEffect(2), new TapSourceCost()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutLibraryIntoGraveTargetEffect(2), new TapSourceCost());

View file

@ -59,7 +59,7 @@ public class Stonewright extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Stonewright is paired with another creature, each of those creatures has "{R}: This creature gets +1/+0 until end of turn." // As long as Stonewright is paired with another creature, each of those creatures has "{R}: This creature gets +1/+0 until end of turn."
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{R}")); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{R}"));

View file

@ -57,7 +57,7 @@ public class TandemLookout extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Tandem Lookout is paired with another creature, each of those creatures has "Whenever this creature deals damage to an opponent, draw a card." // As long as Tandem Lookout is paired with another creature, each of those creatures has "Whenever this creature deals damage to an opponent, draw a card."
Ability ability = new DealsDamageToOpponentTriggeredAbility(new DrawCardSourceControllerEffect(1)); Ability ability = new DealsDamageToOpponentTriggeredAbility(new DrawCardSourceControllerEffect(1));

View file

@ -54,7 +54,7 @@ public class TrustedForcemage extends CardImpl {
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Trusted Forcemage is paired with another creature, each of those creatures gets +1/+1. // As long as Trusted Forcemage is paired with another creature, each of those creatures gets +1/+1.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostPairedEffect(1, 1, ruleText))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostPairedEffect(1, 1, ruleText)));

View file

@ -57,7 +57,7 @@ public class Wingcrafter extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Wingcrafter is paired with another creature, both creatures have flying. // As long as Wingcrafter is paired with another creature, both creatures have flying.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(FlyingAbility.getInstance(), ruleText))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityPairedEffect(FlyingAbility.getInstance(), ruleText)));

View file

@ -54,7 +54,7 @@ public class WolfirSilverheart extends CardImpl {
this.toughness = new MageInt(4); this.toughness = new MageInt(4);
// Soulbond // Soulbond
this.addAbility(SoulbondAbility.getInstance()); this.addAbility(new SoulbondAbility());
// As long as Wolfir Silverheart is paired with another creature, each of those creatures gets +4/+4. // As long as Wolfir Silverheart is paired with another creature, each of those creatures gets +4/+4.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostPairedEffect(4, 4, ruleText))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostPairedEffect(4, 4, ruleText)));

View file

@ -28,12 +28,12 @@
package mage.sets.magic2012; package mage.sets.magic2012;
import java.util.UUID; import java.util.UUID;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.BecomesTargetTriggeredAbility; import mage.abilities.common.BecomesTargetTriggeredAbility;
import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.effects.common.SacrificeSourceEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.constants.CardType;
import mage.constants.Rarity;
/** /**
* *
@ -50,6 +50,7 @@ public class PhantasmalBear extends CardImpl {
this.power = new MageInt(2); this.power = new MageInt(2);
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// When Phantasmal Bear becomes the target of a spell or ability, sacrifice it.
this.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect())); this.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect()));
} }

View file

@ -9,7 +9,6 @@ import mage.constants.Zone;
import mage.filter.Filter; import mage.filter.Filter;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase; import org.mage.test.serverside.base.CardTestPlayerBase;
@ -318,9 +317,12 @@ public class SoulbondKeywordTest extends CardTestPlayerBase {
*/ */
@Test @Test
public void testRebondOnNextCreature() { public void testRebondOnNextCreature() {
addCard(Zone.BATTLEFIELD, playerA, "Elite Vanguard"); // When Phantasmal Bear becomes the target of a spell or ability, sacrifice it.
addCard(Zone.HAND, playerA, "Phantasmal Bear"); addCard(Zone.HAND, playerA, "Phantasmal Bear");
// Soulbond
// As long as Trusted Forcemage is paired with another creature, each of those creatures gets +1/+1.
addCard(Zone.HAND, playerA, "Trusted Forcemage"); addCard(Zone.HAND, playerA, "Trusted Forcemage");
addCard(Zone.BATTLEFIELD, playerA, "Elite Vanguard"); // 2/1
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
@ -329,10 +331,10 @@ public class SoulbondKeywordTest extends CardTestPlayerBase {
addCard(Zone.HAND, playerA, "Lightning Bolt", 1); addCard(Zone.HAND, playerA, "Lightning Bolt", 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Trusted Forcemage"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Trusted Forcemage");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Elite Vanguard"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Elite Vanguard");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Bear"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Phantasmal Bear");
setStopAt(1, PhaseStep.BEGIN_COMBAT); setStopAt(1, PhaseStep.END_TURN);
execute(); execute();
assertPermanentCount(playerA, "Elite Vanguard", 0); assertPermanentCount(playerA, "Elite Vanguard", 0);
@ -347,7 +349,9 @@ public class SoulbondKeywordTest extends CardTestPlayerBase {
*/ */
@Test @Test
public void testGrantingAbility() { public void testGrantingAbility() {
addCard(Zone.BATTLEFIELD, playerA, "Elite Vanguard"); addCard(Zone.BATTLEFIELD, playerA, "Elite Vanguard"); // 2/1
// Soulbond
// As long as Nearheath Pilgrim is paired with another creature, both creatures have lifelink.
addCard(Zone.HAND, playerA, "Nearheath Pilgrim"); addCard(Zone.HAND, playerA, "Nearheath Pilgrim");
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
@ -394,9 +398,8 @@ public class SoulbondKeywordTest extends CardTestPlayerBase {
/* /*
* Reported bug: Soulbond should use the stack, but unable to use instant speed removal since no trigger occurs * Reported bug: Soulbond should use the stack, but unable to use instant speed removal since no trigger occurs
*/ */
@Test @Test
@Ignore
// Soulbond does not currently use the stack, so this test will fail until then // Soulbond does not currently use the stack, so this test will fail until then
public void testRespondToSoulboundWithRemoval() { public void testRespondToSoulboundWithRemoval() {
@ -408,23 +411,21 @@ public class SoulbondKeywordTest extends CardTestPlayerBase {
// As long as Deadeye Navigator is paired with another creature, each of those creatures has "{1}{U}: Exile this creature, then return it to the battlefield under your control." // As long as Deadeye Navigator is paired with another creature, each of those creatures has "{1}{U}: Exile this creature, then return it to the battlefield under your control."
addCard(Zone.HAND, playerA, "Deadeye Navigator"); // 5/5 addCard(Zone.HAND, playerA, "Deadeye Navigator"); // 5/5
addCard(Zone.BATTLEFIELD, playerA, "Island", 8); addCard(Zone.BATTLEFIELD, playerA, "Island", 8);
addCard(Zone.BATTLEFIELD, playerB, "Doom Blade", 1); // {1}{B} instant: Destroy target non-black creature addCard(Zone.HAND, playerB, "Doom Blade", 1); // {1}{B} instant: Destroy target non-black creature
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Deadeye Navigator"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Deadeye Navigator");
setChoice(playerA, "Yes"); setChoice(playerA, "Yes");
addTarget(playerA, "Palinchron"); setChoice(playerA, "Palinchron");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Doom Blade", "Deadeye Navigator"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Doom Blade", "Deadeye Navigator");
// Deadeye's ability should not be usable since was Destroyed before Soulbond trigger resolved // Deadeye's ability should not be usable since was destroyed before Soulbond trigger resolved
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{U}:"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{U}:");
setStopAt(1, PhaseStep.BEGIN_COMBAT); setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute(); execute();
Permanent palinchron = getPermanent("Palinchron", playerA); Permanent palinchron = getPermanent("Palinchron", playerA);
Permanent deadeye = getPermanent("Deadeye Navigator", playerA);
Assert.assertEquals(null, palinchron.getPairedCard()); // should not be paired Assert.assertEquals(null, palinchron.getPairedCard()); // should not be paired
Assert.assertEquals(null, deadeye.getPairedCard()); // should not be paired
assertGraveyardCount(playerA, "Deadeye Navigator", 1); assertGraveyardCount(playerA, "Deadeye Navigator", 1);
assertGraveyardCount(playerB, "Doom Blade", 1); assertGraveyardCount(playerB, "Doom Blade", 1);
assertPermanentCount(playerA, "Palinchron", 1); assertPermanentCount(playerA, "Palinchron", 1);

View file

@ -24,16 +24,15 @@
* 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.effects.ContinuousEffectImpl;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Layer; import mage.constants.Layer;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubLayer; import mage.constants.SubLayer;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
@ -68,7 +67,7 @@ public class BoostPairedEffect extends ContinuousEffectImpl {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId()); Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null && permanent.getPairedCard() != null) { if (permanent != null && permanent.getPairedCard() != null) {
Permanent paired = game.getPermanent(permanent.getPairedCard()); Permanent paired = permanent.getPairedCard().getPermanent(game);
if (paired != null) { if (paired != null) {
permanent.addPower(power); permanent.addPower(power);
permanent.addToughness(toughness); permanent.addToughness(toughness);

View file

@ -25,15 +25,15 @@
* 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.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Layer; import mage.constants.Layer;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubLayer; import mage.constants.SubLayer;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
@ -66,11 +66,15 @@ public class GainAbilityPairedEffect extends ContinuousEffectImpl {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId()); Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null && permanent.getPairedCard() != null) { if (permanent != null && permanent.getPairedCard() != null) {
Permanent paired = game.getPermanent(permanent.getPairedCard()); Permanent paired = permanent.getPairedCard().getPermanent(game);
if (paired != null) { if (paired != null && paired.getPairedCard() != null && paired.getPairedCard().equals(new MageObjectReference(permanent, game))) {
permanent.addAbility(ability, game); permanent.addAbility(ability, source.getSourceId(), game);
paired.addAbility(ability, source.getSourceId(), game, false); paired.addAbility(ability, source.getSourceId(), game, false);
return true; return true;
} else {
// No longer the same cards as orininally paired.
permanent.setPairedCard(null);
} }
} }
return false; return false;

View file

@ -24,32 +24,71 @@
* 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.keyword; package mage.abilities.keyword;
import java.io.ObjectStreamException; import mage.MageObjectReference;
import mage.abilities.MageSingleton; import mage.abilities.Ability;
import mage.abilities.StaticAbility; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SetTargetPointer;
import mage.constants.TargetController;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.AnotherPredicate;
import mage.filter.predicate.permanent.ControllerPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetControlledPermanent;
/** /**
* @author noxx * 702.94. Soulbond
*
* 702.94a Soulbond is a keyword that represents two triggered abilities.
* Soulbond means When this creature enters the battlefield, if you control
* both this creature and another creature and both are unpaired, you may pair
* this creature with another unpaired creature you control for as long as both
* remain creatures on the battlefield under your control and Whenever another
* creature enters the battlefield under your control, if you control both that
* creature and this one and both are unpaired, you may pair that creature with
* this creature for as long as both remain creatures on the battlefield under
* your control.
*
* 702.94b A creature becomes paired with another as the result of a soulbond
* ability. Abilities may refer to a paired creature, the creature another
* creature is paired with, or whether a creature is paired. An unpaired
* creature is one that is not paired.
*
* 702.94c When the soulbond ability resolves, if either object that would be
* paired is no longer a creature, no longer on the battlefield, or no longer
* under the control of the player who controls the soulbond ability, neither
* object becomes paired.
*
* 702.94d A creature can be paired with only one other creature.
*
* 702.94e A paired creature becomes unpaired if any of the following occur:
* another player gains control of it or the creature its paired with; it or
* the creature its paired with stops being a creature; or it or the creature
* its paired with leaves the battlefield.
*
* @author LevelX2
*/ */
public class SoulbondAbility extends StaticAbility implements MageSingleton { public class SoulbondAbility extends EntersBattlefieldTriggeredAbility {
private static final SoulbondAbility fINSTANCE = new SoulbondAbility(); public SoulbondAbility() {
super(new SoulboundEntersSelfEffect(), true);
private Object readResolve() throws ObjectStreamException { this.addSubAbility(new SoulbondEntersOtherAbility());
return fINSTANCE;
} }
public static SoulbondAbility getInstance() { public SoulbondAbility(SoulbondAbility ability) {
return fINSTANCE; super(ability);
}
private SoulbondAbility() {
super(Zone.BATTLEFIELD, null);
} }
@Override @Override
@ -57,9 +96,200 @@ public class SoulbondAbility extends StaticAbility implements MageSingleton {
return "Soulbond <i>(You may pair this creature with another unpaired creature when either enters the battlefield. They remain paired for as long as you control both of them.)</i>"; return "Soulbond <i>(You may pair this creature with another unpaired creature when either enters the battlefield. They remain paired for as long as you control both of them.)</i>";
} }
@Override
public boolean checkInterveningIfClause(Game game) {
// if you control both this creature and another creature and both are unpaired
boolean self = false;
boolean other = false;
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(getControllerId())) {
if (permanent.getCardType().contains(CardType.CREATURE)) {
if (permanent.getId().equals(getSourceId())) {
if (permanent.getControllerId().equals(getControllerId())) {
self = true;
if (other) {
return true;
}
} else {
return false;
}
} else if (permanent.getPairedCard() == null) {
other = true;
if (self) {
return true;
}
}
}
}
return false;
}
@Override @Override
public SoulbondAbility copy() { public SoulbondAbility copy() {
return fINSTANCE; return new SoulbondAbility(this);
}
}
// When this creature enters the battlefield, if you control both this creature and another creature and both are unpaired, you may pair
// this creature with another unpaired creature you control for as long as both remain creatures on the battlefield under your control
class SoulboundEntersSelfEffect extends OneShotEffect {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another not paired creature you control");
static {
filter.add(new AnotherPredicate());
filter.add(Predicates.not(new PairedPredicate()));
}
public SoulboundEntersSelfEffect() {
super(Outcome.Benefit);
}
public SoulboundEntersSelfEffect(final SoulboundEntersSelfEffect effect) {
super(effect);
}
@Override
public SoulboundEntersSelfEffect copy() {
return new SoulboundEntersSelfEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) {
Player controller = game.getPlayer(permanent.getControllerId());
if (controller != null) {
TargetControlledPermanent target = new TargetControlledPermanent(filter);
target.setNotTarget(true);
if (target.canChoose(permanent.getId(), controller.getId(), game)) {
if (controller.choose(Outcome.Benefit, target, permanent.getId(), game)) {
Permanent chosen = game.getPermanent(target.getFirstTarget());
if (chosen != null) {
chosen.setPairedCard(new MageObjectReference(permanent, game));
permanent.setPairedCard(new MageObjectReference(chosen, game));
if (!game.isSimulation()) {
game.informPlayers(controller.getLogName() + " soulbonds " + permanent.getLogName() + " with " + chosen.getLogName());
}
}
}
}
}
return true;
}
return false;
}
}
/**
* Whenever another creature enters the battlefield under your control, if you
* control both that creature and this one and both are unpaired, you may pair
* that creature with this creature for as long as both remain creatures on the
* battlefield under your control.
*
*/
class SoulbondEntersOtherAbility extends EntersBattlefieldAllTriggeredAbility {
private final static FilterCreaturePermanent soulbondFilter = new FilterCreaturePermanent();
static {
soulbondFilter.add(Predicates.not(new PairedPredicate()));
soulbondFilter.add(new ControllerPredicate(TargetController.YOU));
soulbondFilter.add(new AnotherPredicate());
}
public SoulbondEntersOtherAbility() {
super(Zone.BATTLEFIELD, new SoulboundEntersOtherEffect(), soulbondFilter, true, SetTargetPointer.PERMANENT, "");
setRuleVisible(false);
}
public SoulbondEntersOtherAbility(SoulbondEntersOtherAbility ability) {
super(ability);
}
@Override
public String getRule() {
return "Soulbond <i>(You may pair this creature with another unpaired creature when either enters the battlefield. They remain paired for as long as you control both of them.)</i>";
}
@Override
public boolean checkInterveningIfClause(Game game) {
// if you control both this creature and another creature and both are unpaired
if (game.getBattlefield().countAll(filter, getControllerId(), game) > 0) {
Permanent sourcePermanent = game.getPermanent(getSourceId());
if (sourcePermanent != null && sourcePermanent.getControllerId().equals(getControllerId()) && sourcePermanent.getPairedCard() == null) {
return true;
}
}
return false;
}
@Override
public SoulbondEntersOtherAbility copy() {
return new SoulbondEntersOtherAbility(this);
}
}
class SoulboundEntersOtherEffect extends OneShotEffect {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another not paired creature you control");
static {
filter.add(new AnotherPredicate());
filter.add(Predicates.not(new PairedPredicate()));
}
public SoulboundEntersOtherEffect() {
super(Outcome.Benefit);
}
public SoulboundEntersOtherEffect(final SoulboundEntersOtherEffect effect) {
super(effect);
}
@Override
public SoulboundEntersOtherEffect copy() {
return new SoulboundEntersOtherEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null && permanent.getPairedCard() == null
&& permanent.getCardType().contains(CardType.CREATURE)) {
Player controller = game.getPlayer(permanent.getControllerId());
if (controller != null) {
Permanent enteringPermanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (enteringPermanent != null && enteringPermanent.getCardType().contains(CardType.CREATURE) && enteringPermanent.getPairedCard() == null) {
enteringPermanent.setPairedCard(new MageObjectReference(permanent, game));
permanent.setPairedCard(new MageObjectReference(enteringPermanent, game));
if (!game.isSimulation()) {
game.informPlayers(controller.getLogName() + " soulbonds " + permanent.getLogName() + " with " + enteringPermanent.getLogName());
}
}
}
return true;
}
return false;
}
}
class PairedPredicate implements Predicate<Permanent> {
@Override
public boolean apply(Permanent input, Game game) {
return input.getPairedCard() != null;
}
@Override
public String toString() {
return "Paired";
} }
} }

View file

@ -131,7 +131,6 @@ import mage.watchers.common.DamageDoneWatcher;
import mage.watchers.common.MorbidWatcher; import mage.watchers.common.MorbidWatcher;
import mage.watchers.common.PlayerDamagedBySourceWatcher; import mage.watchers.common.PlayerDamagedBySourceWatcher;
import mage.watchers.common.PlayerLostLifeWatcher; import mage.watchers.common.PlayerLostLifeWatcher;
import mage.watchers.common.SoulbondWatcher;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
public abstract class GameImpl implements Game, Serializable { public abstract class GameImpl implements Game, Serializable {
@ -1007,7 +1006,6 @@ public abstract class GameImpl implements Game, Serializable {
} }
watchers.add(new MorbidWatcher()); watchers.add(new MorbidWatcher());
watchers.add(new CastSpellLastTurnWatcher()); watchers.add(new CastSpellLastTurnWatcher());
watchers.add(new SoulbondWatcher());
watchers.add(new PlayerLostLifeWatcher()); watchers.add(new PlayerLostLifeWatcher());
watchers.add(new BlockedAttackerWatcher()); watchers.add(new BlockedAttackerWatcher());
watchers.add(new DamageDoneWatcher()); watchers.add(new DamageDoneWatcher());
@ -1687,7 +1685,7 @@ public abstract class GameImpl implements Game, Serializable {
if (perm.getPairedCard() != null) { if (perm.getPairedCard() != null) {
//702.93e.: ...another player gains control //702.93e.: ...another player gains control
// ...or the creature it's paired with leaves the battlefield. // ...or the creature it's paired with leaves the battlefield.
Permanent paired = getPermanent(perm.getPairedCard()); Permanent paired = perm.getPairedCard().getPermanent(this);
if (paired == null || !perm.getControllerId().equals(paired.getControllerId()) || paired.getPairedCard() == null) { if (paired == null || !perm.getControllerId().equals(paired.getControllerId()) || paired.getPairedCard() == null) {
perm.setPairedCard(null); perm.setPairedCard(null);
if (paired != null) { if (paired != null) {
@ -1698,7 +1696,7 @@ public abstract class GameImpl implements Game, Serializable {
} }
} else if (perm.getPairedCard() != null) { } else if (perm.getPairedCard() != null) {
//702.93e.: ...stops being a creature //702.93e.: ...stops being a creature
Permanent paired = getPermanent(perm.getPairedCard()); Permanent paired = perm.getPairedCard().getPermanent(this);
perm.setPairedCard(null); perm.setPairedCard(null);
if (paired != null) { if (paired != null) {
paired.setPairedCard(null); paired.setPairedCard(null);

View file

@ -327,14 +327,14 @@ public interface Permanent extends Card, Controllable {
* *
* @param pairedCard * @param pairedCard
*/ */
void setPairedCard(UUID pairedCard); void setPairedCard(MageObjectReference pairedCard);
/** /**
* Gets paired card. Can return null. * Gets paired card. Can return null.
* *
* @return * @return
*/ */
UUID getPairedCard(); MageObjectReference getPairedCard();
/** /**
* Makes permanent paired with no other permanent. * Makes permanent paired with no other permanent.

View file

@ -116,7 +116,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
protected HashSet<MageObjectReference> dealtDamageByThisTurn; protected HashSet<MageObjectReference> dealtDamageByThisTurn;
protected UUID attachedTo; protected UUID attachedTo;
protected int attachedToZoneChangeCounter; protected int attachedToZoneChangeCounter;
protected UUID pairedCard; protected MageObjectReference pairedPermanent;
protected Counters counters; protected Counters counters;
protected List<Counter> markedDamage; protected List<Counter> markedDamage;
protected int timesLoyaltyUsed = 0; protected int timesLoyaltyUsed = 0;
@ -179,7 +179,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
this.transformed = permanent.transformed; this.transformed = permanent.transformed;
this.monstrous = permanent.monstrous; this.monstrous = permanent.monstrous;
this.renowned = permanent.renowned; this.renowned = permanent.renowned;
this.pairedCard = permanent.pairedCard; this.pairedPermanent = permanent.pairedPermanent;
this.timesLoyaltyUsed = permanent.timesLoyaltyUsed; this.timesLoyaltyUsed = permanent.timesLoyaltyUsed;
this.morphed = permanent.morphed; this.morphed = permanent.morphed;
@ -1318,18 +1318,18 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
} }
@Override @Override
public void setPairedCard(UUID pairedCard) { public void setPairedCard(MageObjectReference pairedCard) {
this.pairedCard = pairedCard; this.pairedPermanent = pairedCard;
} }
@Override @Override
public UUID getPairedCard() { public MageObjectReference getPairedCard() {
return pairedCard; return pairedPermanent;
} }
@Override @Override
public void clearPairedCard() { public void clearPairedCard() {
this.pairedCard = null; this.pairedPermanent = null;
} }
@Override @Override

View file

@ -839,7 +839,7 @@ public abstract class PlayerImpl implements Player, Serializable {
} }
if (permanent.getPairedCard() != null) { if (permanent.getPairedCard() != null) {
Permanent pairedCard = game.getPermanent(permanent.getPairedCard()); Permanent pairedCard = permanent.getPairedCard().getPermanent(game);
if (pairedCard != null) { if (pairedCard != null) {
pairedCard.clearPairedCard(); pairedCard.clearPairedCard();
} }

View file

@ -1,145 +0,0 @@
/*
* 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 mage.abilities.keyword.SoulbondAbility;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.WatcherScope;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.AnotherPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetControlledPermanent;
import mage.watchers.Watcher;
/**
* Reacts on various events to pair or unpair creatures on the battlefield.
*
* @author noxx
*/
public class SoulbondWatcher extends Watcher {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another not paired creature you control");
static {
filter.add(new AnotherPredicate());
filter.add(Predicates.not(new PairedPredicate()));
}
public SoulbondWatcher() {
super("SoulbondWatcher", WatcherScope.GAME);
}
public SoulbondWatcher(final SoulbondWatcher watcher) {
super(watcher);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null && permanent.getCardType().contains(CardType.CREATURE)) {
if (permanent.getAbilities().contains(SoulbondAbility.getInstance())) {
Player controller = game.getPlayer(permanent.getControllerId());
if (controller != null) {
Cards cards = new CardsImpl();
cards.add(permanent);
controller.lookAtCards("Soulbond", cards, game);
if (controller.chooseUse(Outcome.Benefit, "Use Soulbond?", null, game)) {
TargetControlledPermanent target = new TargetControlledPermanent(filter);
target.setNotTarget(true);
if (target.canChoose(permanent.getId(), controller.getId(), game)) {
if (controller.choose(Outcome.Benefit, target, permanent.getId(), game)) {
Permanent chosen = game.getPermanent(target.getFirstTarget());
if (chosen != null) {
chosen.setPairedCard(permanent.getId());
permanent.setPairedCard(chosen.getId());
if (!game.isSimulation()) {
game.informPlayers(new StringBuilder(controller.getLogName()).append(" souldbonds ").append(permanent.getLogName()).append(" with ").append(chosen.getName()).toString());
}
}
}
}
}
}
}
// if still unpaired
if (permanent.getPairedCard() == null) {
// try to find creature with Soulbond and unpaired
Player controller = null;
for (Permanent chosen : game.getBattlefield().getActivePermanents(filter, permanent.getControllerId(), permanent.getId(), game)) {
if (!chosen.getId().equals(permanent.getId()) && chosen.getAbilities().contains(SoulbondAbility.getInstance()) && chosen.getPairedCard() == null) {
if (controller == null) {
controller = game.getPlayer(permanent.getControllerId());
}
if (controller != null) {
Cards cards = new CardsImpl();
cards.add(chosen);
controller.lookAtCards("Soulbond", cards, game);
if (controller.chooseUse(Outcome.Benefit, "Use Soulbond for recent " + permanent.getLogName() + "?", SoulbondAbility.getInstance(), game)) {
chosen.setPairedCard(permanent.getId());
permanent.setPairedCard(chosen.getId());
if (!game.isSimulation()) {
game.informPlayers(new StringBuilder(controller.getLogName()).append(" souldbonds ").append(permanent.getLogName()).append(" with ").append(chosen.getName()).toString());
}
break;
}
}
}
}
}
}
}
}
@Override
public SoulbondWatcher copy() {
return new SoulbondWatcher(this);
}
}
class PairedPredicate implements Predicate<Permanent> {
@Override
public boolean apply(Permanent input, Game game) {
return input.getPairedCard() != null;
}
@Override
public String toString() {
return "Paired";
}
}