Reworking "as long as you control this" effects (WIP) (#8620)

* added WhileControlled duration, removed SourceOnBattlefieldControlUnchangedCondition

* refactored effects which keep things tapped

* a few additional missed cards

* refactored cards which check for being controlled and tapped

* [NEO] Implemented Kyodai, Soul of Kamigawa
This commit is contained in:
Evan Kranzler 2022-01-30 22:00:10 -05:00 committed by GitHub
parent 0ca75806fe
commit d030848552
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 495 additions and 1239 deletions

View file

@ -1,11 +1,8 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.SourceOnBattlefieldControlUnchangedCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.IndestructibleAbility;
@ -17,7 +14,8 @@ import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.target.TargetPermanent;
import mage.watchers.common.LostControlWatcher;
import java.util.UUID;
/**
* @author Loki
@ -41,13 +39,10 @@ public final class AegisAngel extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// When Aegis Angel enters the battlefield, another target permanent is indestructible for as long as you control Aegis Angel.
ConditionalContinuousEffect effect = new ConditionalContinuousEffect(
new GainAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.Custom),
new SourceOnBattlefieldControlUnchangedCondition(),
"another target permanent is indestructible for as long as you control Aegis Angel");
Ability ability = new EntersBattlefieldTriggeredAbility(effect, false);
Ability ability = new EntersBattlefieldTriggeredAbility(new GainAbilityTargetEffect(
IndestructibleAbility.getInstance(), Duration.WhileControlled
), false);
ability.addTarget(new TargetPermanent(filter));
ability.addWatcher(new LostControlWatcher());
this.addAbility(ability);
}
@ -59,5 +54,4 @@ public final class AegisAngel extends CardImpl {
public AegisAngel copy() {
return new AegisAngel(this);
}
}

View file

@ -1,25 +1,21 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.common.SourceOnBattlefieldControlUnchangedCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.target.common.TargetArtifactPermanent;
import mage.watchers.common.LostControlWatcher;
import java.util.UUID;
/**
*
* @author nigelzor
*/
public final class Aladdin extends CardImpl {
@ -32,14 +28,11 @@ public final class Aladdin extends CardImpl {
this.toughness = new MageInt(1);
// {1}{R}{R}, {tap}: Gain control of target artifact for as long as you control Aladdin.
ConditionalContinuousEffect effect = new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.Custom),
new SourceOnBattlefieldControlUnchangedCondition(),
"Gain control of target artifact for as long as you control Aladdin");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}{R}{R}"));
Ability ability = new SimpleActivatedAbility(
new GainControlTargetEffect(Duration.WhileControlled), new ManaCostsImpl<>("{1}{R}{R}")
);
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetArtifactPermanent());
ability.addWatcher(new LostControlWatcher());
this.addAbility(ability);
}

View file

@ -1,14 +1,8 @@
package mage.cards.d;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.CompoundCondition;
import mage.abilities.condition.common.SourceHasRemainedInSameZoneCondition;
import mage.abilities.condition.common.SourceOnBattlefieldControlUnchangedCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.abilities.keyword.DeathtouchAbility;
import mage.abilities.keyword.FlyingAbility;
@ -16,19 +10,13 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCreatureOrPlaneswalker;
import mage.util.CardUtil;
import mage.util.GameLog;
import mage.watchers.common.LostControlWatcher;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class DragonlordSilumgar extends CardImpl {
@ -48,11 +36,9 @@ public final class DragonlordSilumgar extends CardImpl {
this.addAbility(DeathtouchAbility.getInstance());
// When Dragonlord Silumgar enters the battlefield, gain control of target creature or planeswalker for as long as you control Dragonlord Silumgar.
Ability ability = new EntersBattlefieldTriggeredAbility(new DragonlordSilumgarEffect(), false);
Ability ability = new EntersBattlefieldTriggeredAbility(new GainControlTargetEffect(Duration.WhileControlled));
ability.addTarget(new TargetCreatureOrPlaneswalker());
ability.addWatcher(new LostControlWatcher());
this.addAbility(ability);
}
private DragonlordSilumgar(final DragonlordSilumgar card) {
@ -64,44 +50,3 @@ public final class DragonlordSilumgar extends CardImpl {
return new DragonlordSilumgar(this);
}
}
class DragonlordSilumgarEffect extends OneShotEffect {
public DragonlordSilumgarEffect() {
super(Outcome.GainControl);
this.staticText = "gain control of target creature or planeswalker for as long as you control {this}";
}
public DragonlordSilumgarEffect(final DragonlordSilumgarEffect effect) {
super(effect);
}
@Override
public DragonlordSilumgarEffect copy() {
return new DragonlordSilumgarEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
Player controller = game.getPlayer(source.getControllerId());
Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source));
if (controller != null && sourcePermanent != null) {
if (target != null && controller.getId().equals(sourcePermanent.getControllerId())) {
SourceHasRemainedInSameZoneCondition condition = new SourceHasRemainedInSameZoneCondition(sourcePermanent.getId());
game.addEffect(new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.Custom),
new CompoundCondition(new SourceOnBattlefieldControlUnchangedCondition(), condition),
null),
source);
if (!game.isSimulation()) {
game.informPlayers(sourcePermanent.getLogName() + ": " + controller.getLogName() + " gained control of " + target.getLogName());
}
sourcePermanent.addInfo("gained control of", CardUtil.addToolTipMarkTags("Gained control of: " + GameLog.getColoredObjectIdNameForTooltip(target)), game);
}
return true;
}
return false;
}
}

View file

@ -1,34 +1,33 @@
package mage.cards.d;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.common.DontUntapInControllersUntapStepTargetEffect;
import mage.abilities.effects.common.TapTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.target.common.TargetCreaturePermanent;
import mage.watchers.Watcher;
import java.util.UUID;
/**
*
* @author BetaSteward
*/
public final class DungeonGeists extends CardImpl {
public DungeonGeists(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}");
this.subtype.add(SubType.SPIRIT);
this.power = new MageInt(3);
@ -38,11 +37,9 @@ public final class DungeonGeists extends CardImpl {
// When Dungeon Geists enters the battlefield, tap target creature an opponent controls. That creature doesn't untap during its controller's untap step for as long as you control Dungeon Geists.
Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect(), false);
ability.addEffect(new DungeonGeistsEffect());
Target target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE);
ability.addTarget(target);
this.addAbility(ability, new DungeonGeistsWatcher());
// watcher needed to send normal events to Dungeon Geists ReplacementEffect
ability.addEffect(new DontUntapInControllersUntapStepTargetEffect(Duration.WhileControlled));
ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE));
this.addAbility(ability);
}
private DungeonGeists(final DungeonGeists card) {
@ -54,101 +51,3 @@ public final class DungeonGeists extends CardImpl {
return new DungeonGeists(this);
}
}
class DungeonGeistsEffect extends ContinuousRuleModifyingEffectImpl {
public DungeonGeistsEffect() {
super(Duration.Custom, Outcome.Detriment, false, false);
this.staticText = "That creature doesn't untap during its controller's untap step for as long as you control {this}";
}
public DungeonGeistsEffect(final DungeonGeistsEffect effect) {
super(effect);
}
@Override
public DungeonGeistsEffect copy() {
return new DungeonGeistsEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.UNTAP
|| event.getType() == GameEvent.EventType.ZONE_CHANGE
|| event.getType() == GameEvent.EventType.LOST_CONTROL;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
// Source must be on the battlefield (it's neccessary to check here because if as response to the enter
// the battlefield triggered ability the source dies (or will be exiled), then the ZONE_CHANGE or LOST_CONTROL
// event will happen before this effect is applied ever)
MageObject sourceObject = source.getSourceObjectIfItStillExists(game);
if (!(sourceObject instanceof Permanent) || !((Permanent) sourceObject).isControlledBy(source.getControllerId())) {
discard();
return false;
}
switch (event.getType()) {
case ZONE_CHANGE:
// end effect if source does a zone move
if (event.getTargetId().equals(source.getSourceId())) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
discard();
return false;
}
}
break;
case UNTAP:
// prevent to untap the target creature
if (game.getTurn().getStepType() == PhaseStep.UNTAP && event.getTargetId().equals(targetPointer.getFirst(game, source))) {
Permanent targetCreature = game.getPermanent(targetPointer.getFirst(game, source));
if (targetCreature != null) {
return targetCreature.isControlledBy(game.getActivePlayerId());
} else {
discard();
return false;
}
}
break;
case LOST_CONTROL:
// end effect if source control is changed
if (event.getTargetId().equals(source.getSourceId())) {
discard();
return false;
}
break;
}
return false;
}
}
class DungeonGeistsWatcher extends Watcher {
DungeonGeistsWatcher() {
super(WatcherScope.CARD);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.LOST_CONTROL
&& event.getPlayerId().equals(controllerId)
&& event.getTargetId().equals(sourceId)) {
condition = true;
game.replaceEvent(event);
return;
}
if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(sourceId)) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
condition = true;
game.replaceEvent(event);
}
}
}
@Override
public void reset() {
//don't reset condition each turn - only when this leaves the battlefield
}
}

View file

@ -1,11 +1,10 @@
package mage.cards.h;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SkipUntapOptionalAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceTappedCondition;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
@ -15,15 +14,14 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Zone;
import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT;
/**
*
* @author fireshoes
*/
public final class HelmOfPossession extends CardImpl {
@ -35,14 +33,13 @@ public final class HelmOfPossession extends CardImpl {
this.addAbility(new SkipUntapOptionalAbility());
// {2}, {tap}, Sacrifice a creature: Gain control of target creature for as long as you control Helm of Possession and Helm of Possession remains tapped.
ConditionalContinuousEffect effect = new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.Custom),
new HelmOfPossessionCondition(),
"Gain control of target creature for as long as you control {this} and {this} remains tapped");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new GenericManaCost(2));
Ability ability = new SimpleActivatedAbility(new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.WhileControlled), SourceTappedCondition.instance,
"gain control of target creature for as long as you control {this} and {this} remains tapped"
), new GenericManaCost(2));
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT)));
ability.addTarget(new TargetCreaturePermanent());
ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT)));
this.addAbility(ability);
}
@ -55,22 +52,3 @@ public final class HelmOfPossession extends CardImpl {
return new HelmOfPossession(this);
}
}
class HelmOfPossessionCondition implements Condition {
private UUID controllerId;
@Override
public boolean apply(Game game, Ability source) {
if (controllerId == null) {
controllerId = source.getControllerId();
}
Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId());
if (permanent != null) {
if (permanent.isTapped()) {
return controllerId.equals(source.getControllerId());
}
}
return false;
}
}

View file

@ -1,16 +1,13 @@
package mage.cards.h;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SkipUntapOptionalAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceMatchesFilterCondition;
import mage.abilities.condition.common.SourceTappedCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -18,31 +15,25 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.predicate.permanent.TappedPredicate;
import mage.target.TargetPermanent;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class HivisOfTheScale extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent();
private static final FilterPermanent filterDragon = new FilterPermanent();
private static final String rule = "Gain control of target Dragon for as long as you control Hivis and Hivis remains tapped.";
static {
filter.add(TappedPredicate.TAPPED);
filter.add(TargetController.YOU.getControllerPredicate());
filterDragon.add(SubType.DRAGON.getPredicate());
}
public HivisOfTheScale(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}");
addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.VIASHINO);
this.subtype.add(SubType.SHAMAN);
@ -51,14 +42,14 @@ public final class HivisOfTheScale extends CardImpl {
// You may choose not to untap Hivis of the Scale during your untap step.
this.addAbility(new SkipUntapOptionalAbility());
// {tap}: Gain control of target Dragon for as long as you control Hivis and Hivis remains tapped.
Condition condition = new SourceMatchesFilterCondition(filter);
Effect effect = new ConditionalContinuousEffect(new GainControlTargetEffect(Duration.Custom), condition, rule);
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost());
Ability ability = new SimpleActivatedAbility(new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.WhileControlled), SourceTappedCondition.instance,
"gain control of target Dragon for as long as you control {this} and {this} remains tapped"
), new TapSourceCost());
ability.addTarget(new TargetPermanent(filterDragon));
this.addAbility(ability);
}
private HivisOfTheScale(final HivisOfTheScale card) {

View file

@ -4,22 +4,19 @@ import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.common.DontUntapInControllersUntapStepTargetEffect;
import mage.abilities.effects.common.TapTargetEffect;
import mage.abilities.effects.common.cost.SpellsCostModificationThatTargetSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.target.common.TargetCreaturePermanent;
import mage.watchers.Watcher;
import java.util.UUID;
@ -40,15 +37,14 @@ public final class IcefallRegent extends CardImpl {
// When Icefall Regent enters the battlefield, tap target creature an opponent controls.
// That creature doesn't untap during its controller's untap step for as long as you control Icefall Regent.
Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect(), false);
ability.addEffect(new IcefallRegentEffect());
Target target = new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE);
ability.addTarget(target);
this.addAbility(ability, new IcefallRegentWatcher());
ability.addEffect(new DontUntapInControllersUntapStepTargetEffect(Duration.WhileControlled));
ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE));
this.addAbility(ability);
// Spells your opponents cast that target Icefall Regent cost {2} more to cast.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
new SpellsCostModificationThatTargetSourceEffect(2, new FilterCard("Spells"), TargetController.OPPONENT))
);
this.addAbility(new SimpleStaticAbility(new SpellsCostModificationThatTargetSourceEffect(
2, new FilterCard("Spells"), TargetController.OPPONENT
)));
}
private IcefallRegent(final IcefallRegent card) {
@ -60,96 +56,3 @@ public final class IcefallRegent extends CardImpl {
return new IcefallRegent(this);
}
}
class IcefallRegentEffect extends ContinuousRuleModifyingEffectImpl {
public IcefallRegentEffect() {
super(Duration.Custom, Outcome.Detriment, false, false);
this.staticText = "That creature doesn't untap during its controller's untap step for as long as you control {this}";
}
public IcefallRegentEffect(final IcefallRegentEffect effect) {
super(effect);
}
@Override
public IcefallRegentEffect copy() {
return new IcefallRegentEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.LOST_CONTROL
|| event.getType() == GameEvent.EventType.ZONE_CHANGE
|| event.getType() == GameEvent.EventType.UNTAP;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
// Source must be on the battlefield (it's neccessary to check here because if as response to the enter
// the battlefield triggered ability the source dies (or will be exiled), then the ZONE_CHANGE or LOST_CONTROL
// event will happen before this effect is applied ever)
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (sourcePermanent == null || !sourcePermanent.isControlledBy(source.getControllerId())) {
discard();
return false;
}
if (event.getType() == GameEvent.EventType.LOST_CONTROL) {
if (event.getTargetId().equals(source.getSourceId())) {
discard();
return false;
}
}
if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(source.getSourceId())) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
discard();
return false;
}
}
if (game.getTurn().getStepType() == PhaseStep.UNTAP && event.getType() == GameEvent.EventType.UNTAP) {
if (event.getTargetId().equals(targetPointer.getFirst(game, source))) {
Permanent targetCreature = game.getPermanent(targetPointer.getFirst(game, source));
return targetCreature != null && game.isActivePlayer(targetCreature.getControllerId());
}
}
return false;
}
}
class IcefallRegentWatcher extends Watcher {
IcefallRegentWatcher() {
super(WatcherScope.CARD);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.LOST_CONTROL
&& event.getPlayerId().equals(controllerId)
&& event.getTargetId().equals(sourceId)) {
condition = true;
game.replaceEvent(event);
return;
}
if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(sourceId)) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
condition = true;
game.replaceEvent(event);
}
}
}
@Override
public void reset() {
//don't reset condition each turn - only when this leaves the battlefield
}
}

View file

@ -0,0 +1,72 @@
package mage.cards.k;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.keyword.FlashAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.IndestructibleAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.target.TargetPermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class KyodaiSoulOfKamigawa extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("another target permanent");
static {
filter.add(AnotherPredicate.instance);
}
public KyodaiSoulOfKamigawa(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}");
this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.DRAGON);
this.subtype.add(SubType.SPIRIT);
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// Flash
this.addAbility(FlashAbility.getInstance());
// Flying
this.addAbility(FlyingAbility.getInstance());
// When Kyodai, Soul of Kamigawa enters the battlefield, another target permanent gains indestructible for as long as you control Kyodai.
Ability ability = new EntersBattlefieldTriggeredAbility(new GainAbilityTargetEffect(
IndestructibleAbility.getInstance(), Duration.WhileControlled
), false);
ability.addTarget(new TargetPermanent(filter));
this.addAbility(ability);
// {W}{U}{B}{R}{G}: Kyodai, Soul of Kamigawa gets +5/+5 until end of turn.
this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect(
5, 5, Duration.EndOfTurn
), new ManaCostsImpl<>("{W}{U}{B}{R}{G}")));
}
private KyodaiSoulOfKamigawa(final KyodaiSoulOfKamigawa card) {
super(card);
}
@Override
public KyodaiSoulOfKamigawa copy() {
return new KyodaiSoulOfKamigawa(this);
}
}

View file

@ -1,11 +1,8 @@
package mage.cards.m;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.SourceOnBattlefieldControlUnchangedCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -13,7 +10,8 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.target.common.TargetArtifactPermanent;
import mage.watchers.common.LostControlWatcher;
import java.util.UUID;
/**
* @author Loki, JayDi85
@ -29,14 +27,8 @@ public final class MasterThief extends CardImpl {
this.toughness = new MageInt(2);
// When Master Thief enters the battlefield, gain control of target artifact for as long as you control Master Thief.
Ability ability = new EntersBattlefieldTriggeredAbility(new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.Custom),
new SourceOnBattlefieldControlUnchangedCondition(),
"gain control of target artifact for as long as you control {this}"),
false);
Ability ability = new EntersBattlefieldTriggeredAbility(new GainControlTargetEffect(Duration.WhileControlled));
ability.addTarget(new TargetArtifactPermanent());
ability.addWatcher(new LostControlWatcher());
this.addAbility(ability);
}

View file

@ -1,21 +1,17 @@
package mage.cards.m;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.common.DontUntapInControllersUntapStepTargetEffect;
import mage.abilities.effects.common.TapTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
import mage.watchers.Watcher;
import java.util.UUID;
@ -39,9 +35,9 @@ public final class MerchantRaiders extends CardImpl {
new TapTargetEffect("tap up to one target creature"),
filter, false, true
);
ability.addEffect(new MerchantRaidersEffect());
ability.addEffect(new DontUntapInControllersUntapStepTargetEffect(Duration.WhileControlled));
ability.addTarget(new TargetCreaturePermanent(0, 1));
this.addAbility(ability, new MerchantRaidersWatcher());
this.addAbility(ability);
}
private MerchantRaiders(final MerchantRaiders card) {
@ -53,98 +49,3 @@ public final class MerchantRaiders extends CardImpl {
return new MerchantRaiders(this);
}
}
class MerchantRaidersEffect extends ContinuousRuleModifyingEffectImpl {
public MerchantRaidersEffect() {
super(Duration.Custom, Outcome.Detriment, false, false);
this.staticText = "That creature doesn't untap during its controller's untap step for as long as you control {this}";
}
public MerchantRaidersEffect(final MerchantRaidersEffect effect) {
super(effect);
}
@Override
public MerchantRaidersEffect copy() {
return new MerchantRaidersEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.UNTAP
|| event.getType() == GameEvent.EventType.ZONE_CHANGE
|| event.getType() == GameEvent.EventType.LOST_CONTROL;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
// Source must be on the battlefield (it's neccessary to check here because if as response to the enter
// the battlefield triggered ability the source dies (or will be exiled), then the ZONE_CHANGE or LOST_CONTROL
// event will happen before this effect is applied ever)
MageObject sourceObject = source.getSourceObjectIfItStillExists(game);
if (!(sourceObject instanceof Permanent) || !((Permanent) sourceObject).isControlledBy(source.getControllerId())) {
discard();
return false;
}
switch (event.getType()) {
case ZONE_CHANGE:
// end effect if source does a zone move
if (!event.getTargetId().equals(source.getSourceId())) {
break;
}
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
discard();
return false;
}
break;
case UNTAP:
// prevent to untap the target creature
if (game.getTurn().getStepType() != PhaseStep.UNTAP
|| !event.getTargetId().equals(targetPointer.getFirst(game, source))) {
break;
}
Permanent targetCreature = game.getPermanent(targetPointer.getFirst(game, source));
if (targetCreature != null) {
return targetCreature.isControlledBy(game.getActivePlayerId());
} else {
discard();
return false;
}
case LOST_CONTROL:
// end effect if source control is changed
if (event.getTargetId().equals(source.getSourceId())) {
discard();
return false;
}
break;
}
return false;
}
}
class MerchantRaidersWatcher extends Watcher {
MerchantRaidersWatcher() {
super(WatcherScope.CARD);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.LOST_CONTROL
&& event.getPlayerId().equals(controllerId)
&& event.getTargetId().equals(sourceId)) {
condition = true;
game.replaceEvent(event);
return;
} else if (event.getType() == GameEvent.EventType.ZONE_CHANGE
&& event.getTargetId().equals(sourceId)) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
condition = true;
game.replaceEvent(event);
}
}
}
}

View file

@ -1,14 +1,11 @@
package mage.cards.m;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.SourceOnBattlefieldControlUnchangedCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect;
@ -24,10 +21,10 @@ import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
import mage.watchers.common.LostControlWatcher;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class MeriekeRiBerit extends CardImpl {
@ -43,16 +40,10 @@ public final class MeriekeRiBerit extends CardImpl {
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DontUntapInControllersUntapStepSourceEffect()));
// {tap}: Gain control of target creature for as long as you control Merieke Ri Berit. When Merieke Ri Berit leaves the battlefield or becomes untapped, destroy that creature. It can't be regenerated.
ConditionalContinuousEffect MeriekeRiBeritGainControlEffect = new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.Custom),
new SourceOnBattlefieldControlUnchangedCondition(),
"Gain control of target creature for as long as you control {this}");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, MeriekeRiBeritGainControlEffect, new TapSourceCost());
Ability ability = new SimpleActivatedAbility(new GainControlTargetEffect(Duration.WhileControlled), new TapSourceCost());
ability.addTarget(new TargetPermanent(new FilterCreaturePermanent("target creature")));
ability.addEffect(new MeriekeRiBeritCreateDelayedTriggerEffect());
ability.addWatcher(new LostControlWatcher());
this.addAbility(ability);
}
private MeriekeRiBerit(final MeriekeRiBerit card) {

View file

@ -9,8 +9,6 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
@ -28,7 +26,7 @@ public final class MindFlayer extends CardImpl {
this.toughness = new MageInt(3);
// Dominate Monster When Mind Flayer enters the battlefield, gain control of target creature for as long as you control Mind Flayer.
Ability ability = new EntersBattlefieldTriggeredAbility(new MindFlayerEffect());
Ability ability = new EntersBattlefieldTriggeredAbility(new GainControlTargetEffect(Duration.WhileControlled));
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability.withFlavorWord("Dominate Monster"));
}
@ -42,33 +40,3 @@ public final class MindFlayer extends CardImpl {
return new MindFlayer(this);
}
}
class MindFlayerEffect extends GainControlTargetEffect {
MindFlayerEffect() {
super(Duration.Custom, true);
staticText = "gain control of target creature for as long as you control {this}";
}
private MindFlayerEffect(final MindFlayerEffect effect) {
super(effect);
}
@Override
public MindFlayerEffect copy() {
return new MindFlayerEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (sourcePermanent == null
|| permanent == null
|| !sourcePermanent.isControlledBy(source.getControllerId())) {
discard();
return false;
}
return super.apply(game, source);
}
}

View file

@ -1,12 +1,9 @@
package mage.cards.o;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.continuous.AddCardSubTypeTargetEffect;
@ -19,14 +16,13 @@ import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.CardIdPredicate;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.filter.predicate.mageobject.CardIdPredicate;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author nantuko
*/
public final class OliviaVoldaren extends CardImpl {
@ -40,7 +36,7 @@ public final class OliviaVoldaren extends CardImpl {
}
public OliviaVoldaren(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{R}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}");
addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.VAMPIRE);
@ -57,9 +53,9 @@ public final class OliviaVoldaren extends CardImpl {
// {1}{R}: Olivia Voldaren deals 1 damage to another target creature. That creature becomes a Vampire in addition to its other types. Put a +1/+1 counter on Olivia Voldaren.
Ability ability = new SimpleActivatedAbility(
Zone.BATTLEFIELD,
new DamageTargetEffect(1).setText("{this} deals 1 damage to another target creature"),
new ManaCostsImpl("{1}{R}")
new DamageTargetEffect(1)
.setText("{this} deals 1 damage to another target creature"),
new ManaCostsImpl<>("{1}{R}")
);
ability.addTarget(new TargetCreaturePermanent(filter));
Effect effect = new AddCardSubTypeTargetEffect(SubType.VAMPIRE, Duration.WhileOnBattlefield);
@ -69,9 +65,9 @@ public final class OliviaVoldaren extends CardImpl {
this.addAbility(ability);
// {3}{B}{B}: Gain control of target Vampire for as long as you control Olivia Voldaren.
Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD,
new ConditionalContinuousEffect(new GainControlTargetEffect(Duration.Custom), new PermanentsOnTheBattlefieldCondition(filter2), rule),
new ManaCostsImpl("{3}{B}{B}"));
Ability ability2 = new SimpleActivatedAbility(
new GainControlTargetEffect(Duration.WhileControlled), new ManaCostsImpl<>("{3}{B}{B}")
);
ability2.addTarget(new TargetCreaturePermanent(vampireFilter));
this.addAbility(ability2);
}

View file

@ -1,11 +1,8 @@
package mage.cards.o;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility;
import mage.abilities.condition.common.SourceOnBattlefieldControlUnchangedCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.AssignNoCombatDamageSourceEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.cards.CardImpl;
@ -16,10 +13,10 @@ import mage.constants.SubType;
import mage.filter.common.FilterLandPermanent;
import mage.filter.predicate.permanent.DefendingPlayerControlsPredicate;
import mage.target.TargetPermanent;
import mage.watchers.common.LostControlWatcher;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class OrcishSquatters extends CardImpl {
@ -38,14 +35,9 @@ public final class OrcishSquatters extends CardImpl {
this.toughness = new MageInt(3);
// Whenever Orcish Squatters attacks and isn't blocked, you may gain control of target land defending player controls for as long as you control Orcish Squatters. If you do, Orcish Squatters assigns no combat damage this turn.
Ability ability = new AttacksAndIsNotBlockedTriggeredAbility(new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.Custom),
new SourceOnBattlefieldControlUnchangedCondition(),
"gain control of target land defending player controls for as long as you control {this}"
), true);
Ability ability = new AttacksAndIsNotBlockedTriggeredAbility(new GainControlTargetEffect(Duration.WhileControlled), true);
ability.addEffect(new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn, true));
ability.addTarget(new TargetPermanent(filter));
ability.addWatcher(new LostControlWatcher());
this.addAbility(ability);
}

View file

@ -1,13 +1,10 @@
package mage.cards.q;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.common.SourceOnBattlefieldControlUnchangedCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.cards.CardImpl;
@ -15,14 +12,13 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.common.FilterControlledArtifactPermanent;
import mage.filter.StaticFilters;
import mage.target.TargetPermanent;
import mage.target.common.TargetAnyTarget;
import mage.watchers.common.LostControlWatcher;
import java.util.UUID;
/**
*
* @author Styxo
*/
public final class QuicksmithRebel extends CardImpl {
@ -36,15 +32,10 @@ public final class QuicksmithRebel extends CardImpl {
this.toughness = new MageInt(2);
// When Quicksmith Rebel enters the battlefield, target artifact you control gains "{T}: This artifact deals 2 damage to any target" for as long as you control Quicksmith Rebel.
Ability artifactAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new TapSourceCost());
Ability artifactAbility = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost());
artifactAbility.addTarget(new TargetAnyTarget());
ConditionalContinuousEffect effect = new ConditionalContinuousEffect(
new GainAbilityTargetEffect(artifactAbility, Duration.Custom),
new SourceOnBattlefieldControlUnchangedCondition(),
"target artifact you control gains \"{T}: This artifact deals 2 damage to any target\" for as long as you control {this}");
Ability ability = new EntersBattlefieldTriggeredAbility(effect, false);
ability.addTarget(new TargetPermanent(new FilterControlledArtifactPermanent()));
ability.addWatcher(new LostControlWatcher());
Ability ability = new EntersBattlefieldTriggeredAbility(new GainAbilityTargetEffect(artifactAbility, Duration.WhileControlled).setText("target artifact you control gains \"{T}: This artifact deals 2 damage to any target\" for as long as you control {this}"));
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT));
this.addAbility(ability);
}

View file

@ -1,27 +1,24 @@
package mage.cards.q;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.common.SourceOnBattlefieldControlUnchangedCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.common.FilterControlledArtifactPermanent;
import mage.filter.StaticFilters;
import mage.target.TargetPermanent;
import mage.watchers.common.LostControlWatcher;
import mage.target.common.TargetAnyTarget;
import java.util.UUID;
/**
*
* @author Styxo
*/
public final class QuicksmithSpy extends CardImpl {
@ -35,14 +32,10 @@ public final class QuicksmithSpy extends CardImpl {
this.toughness = new MageInt(3);
// When Quicksmith Spy enters the battlefield, target artifact you control gains "{T}: Draw a card" for as long as you control Quicksmith Spy.
Ability artifactAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new TapSourceCost());
ConditionalContinuousEffect effect = new ConditionalContinuousEffect(
new GainAbilityTargetEffect(artifactAbility, Duration.Custom),
new SourceOnBattlefieldControlUnchangedCondition(),
"target artifact you control gains \"{T}: Draw a card\" for as long as you control {this}");
Ability ability = new EntersBattlefieldTriggeredAbility(effect, false);
ability.addTarget(new TargetPermanent(new FilterControlledArtifactPermanent()));
ability.addWatcher(new LostControlWatcher());
Ability artifactAbility = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost());
artifactAbility.addTarget(new TargetAnyTarget());
Ability ability = new EntersBattlefieldTriggeredAbility(new GainAbilityTargetEffect(artifactAbility, Duration.WhileControlled).setText("target artifact you control gains \"{T}: Draw a card\" for as long as you control {this}"));
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT));
this.addAbility(ability);
}

View file

@ -1,21 +1,20 @@
package mage.cards.r;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.LandfallAbility;
import mage.abilities.condition.common.SourceOnBattlefieldControlUnchangedCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.target.common.TargetCreaturePermanent;
import mage.watchers.common.LostControlWatcher;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class RoilElemental extends CardImpl {
@ -27,16 +26,12 @@ public final class RoilElemental extends CardImpl {
this.power = new MageInt(3);
this.toughness = new MageInt(2);
String rule = "you may gain control of target creature for as long as you control Roil Elemental";
// Flying
this.addAbility(FlyingAbility.getInstance());
// Landfall - Whenever a land enters the battlefield under your control, you may gain control of target creature for as long as you control Roil Elemental.
ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainControlTargetEffect(Duration.Custom), new SourceOnBattlefieldControlUnchangedCondition(), rule);
Ability ability = new LandfallAbility(Zone.BATTLEFIELD, effect, true);
Ability ability = new LandfallAbility(new GainControlTargetEffect(Duration.WhileControlled), true);
ability.addTarget(new TargetCreaturePermanent());
ability.addWatcher(new LostControlWatcher());
this.addAbility(ability);
}

View file

@ -1,34 +1,30 @@
package mage.cards.r;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SkipUntapOptionalAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceTappedCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class RubiniaSoulsinger extends CardImpl {
public RubiniaSoulsinger(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{W}{U}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{W}{U}");
addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.FAERIE);
@ -37,12 +33,12 @@ public final class RubiniaSoulsinger extends CardImpl {
// You may choose not to untap Rubinia Soulsinger during your untap step.
this.addAbility(new SkipUntapOptionalAbility());
// {tap}: Gain control of target creature for as long as you control Rubinia and Rubinia remains tapped.
ConditionalContinuousEffect effect = new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.OneUse),
new RubiniaSoulsingerCondition(),
"Gain control of target creature for as long as you control Rubinia and Rubinia remains tapped");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost());
Ability ability = new SimpleActivatedAbility(new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.WhileControlled), SourceTappedCondition.instance,
"gain control of target creature for as long as you control {this} and {this} remains tapped"
), new TapSourceCost());
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
@ -56,22 +52,3 @@ public final class RubiniaSoulsinger extends CardImpl {
return new RubiniaSoulsinger(this);
}
}
class RubiniaSoulsingerCondition implements Condition {
private UUID controllerId;
@Override
public boolean apply(Game game, Ability source) {
if (controllerId == null) {
controllerId = source.getControllerId();
}
Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId());
if (permanent != null) {
if (permanent.isTapped()) {
return controllerId.equals(source.getControllerId());
}
}
return false;
}
}

View file

@ -5,9 +5,6 @@ import mage.abilities.Ability;
import mage.abilities.common.ControlsPermanentsControllerTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SkipUntapOptionalAbility;
import mage.abilities.condition.CompoundCondition;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.condition.common.SourceTappedCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalContinuousEffect;
@ -17,11 +14,13 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.common.FilterLandPermanent;
import mage.filter.predicate.mageobject.CardIdPredicate;
import mage.filter.predicate.permanent.ControllerControlsIslandPredicate;
import mage.target.common.TargetCreaturePermanent;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import java.util.UUID;
@ -30,13 +29,15 @@ import java.util.UUID;
*/
public final class Seasinger extends CardImpl {
private static final String rule = "Gain control of target creature whose controller controls an Island for as long as you control Seasinger and Seasinger remains tapped";
private static final FilterPermanent islandYouControl = new FilterPermanent("Island");
private static final FilterCreaturePermanent creatureWhoseControllerControlsIsland = new FilterCreaturePermanent("creature whose controller controls an island");
private static final FilterPermanent filter
= new FilterPermanent("Island");
private static final FilterPermanent filter2
= new FilterCreaturePermanent("creature whose controler controls an Island");
static {
islandYouControl.add(SubType.ISLAND.getPredicate());
islandYouControl.add(TargetController.YOU.getControllerPredicate());
filter.add(SubType.ISLAND.getPredicate());
filter.add(TargetController.YOU.getControllerPredicate());
filter2.add(SeasingerPredicate.instance);
}
public Seasinger(UUID ownerId, CardSetInfo setInfo) {
@ -46,26 +47,21 @@ public final class Seasinger extends CardImpl {
this.power = new MageInt(0);
this.toughness = new MageInt(1);
FilterPermanent seasinger = new FilterPermanent();
seasinger.add(TargetController.YOU.getControllerPredicate());
seasinger.add(new CardIdPredicate(this.getId()));
Condition condition = new CompoundCondition(new PermanentsOnTheBattlefieldCondition(seasinger, ComparisonType.EQUAL_TO, 1), SourceTappedCondition.instance);
// When you control no Islands, sacrifice Seasinger.
this.addAbility(new ControlsPermanentsControllerTriggeredAbility(
new FilterLandPermanent(SubType.ISLAND, "no Islands"), ComparisonType.EQUAL_TO, 0,
new SacrificeSourceEffect()));
filter, ComparisonType.EQUAL_TO, 0, new SacrificeSourceEffect()
));
// You may choose not to untap Seasinger during your untap step.
this.addAbility(new SkipUntapOptionalAbility());
// {tap}: Gain control of target creature whose controller controls an Island for as long as you control Seasinger and Seasinger remains tapped.
ConditionalContinuousEffect effect = new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.Custom),
condition, rule);
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost());
creatureWhoseControllerControlsIsland.add(new ControllerControlsIslandPredicate());
ability.addTarget(new TargetCreaturePermanent(creatureWhoseControllerControlsIsland));
Ability ability = new SimpleActivatedAbility(new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.WhileControlled), SourceTappedCondition.instance,
"gain control of target creature whose controller controls " +
"an Island for as long as you control {this} and {this} remains tapped"
), new TapSourceCost());
ability.addTarget(new TargetPermanent(filter2));
this.addAbility(ability);
}
@ -78,3 +74,13 @@ public final class Seasinger extends CardImpl {
return new Seasinger(this);
}
}
enum SeasingerPredicate implements ObjectSourcePlayerPredicate<Permanent> {
instance;
private static final FilterPermanent filter = new FilterControlledPermanent(SubType.ISLAND);
@Override
public boolean apply(ObjectSourcePlayer<Permanent> input, Game game) {
return game.getBattlefield().contains(filter, input.getSourceId(), input.getObject().getControllerId(), game, 1);
}
}

View file

@ -1,37 +1,28 @@
package mage.cards.s;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.BecomesMonstrousSourceTriggeredAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.common.DontUntapInControllersUntapStepTargetEffect;
import mage.abilities.effects.common.TapTargetEffect;
import mage.abilities.keyword.MonstrosityAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.PhaseStep;
import mage.constants.WatcherScope;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.constants.SubType;
import mage.target.common.TargetCreaturePermanent;
import mage.watchers.Watcher;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class ShipbreakerKraken extends CardImpl {
public ShipbreakerKraken(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}{U}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}");
this.subtype.add(SubType.KRAKEN);
this.power = new MageInt(6);
@ -39,11 +30,13 @@ public final class ShipbreakerKraken extends CardImpl {
// {6}{U}{U}: Monstrosity 4.
this.addAbility(new MonstrosityAbility("{6}{U}{U}", 4));
// When Shipbreaker Kraken becomes monstrous, tap up to four target creatures. Those creatures don't untap during their controllers' untap steps for as long as you control Shipbreaker Kraken.
Ability ability = new BecomesMonstrousSourceTriggeredAbility(new TapTargetEffect());
ability.addTarget(new TargetCreaturePermanent(0,4));
ability.addEffect(new ShipbreakerKrakenReplacementEffect());
this.addAbility(ability, new ShipbreakerKrakenWatcher());
ability.addTarget(new TargetCreaturePermanent(0, 4));
ability.addEffect(new DontUntapInControllersUntapStepTargetEffect(Duration.WhileControlled)
.setText("Those creatures don't untap during their controllers' untap steps for as long as you control {this}"));
this.addAbility(ability);
}
private ShipbreakerKraken(final ShipbreakerKraken card) {
@ -55,95 +48,3 @@ public final class ShipbreakerKraken extends CardImpl {
return new ShipbreakerKraken(this);
}
}
class ShipbreakerKrakenReplacementEffect extends ContinuousRuleModifyingEffectImpl {
public ShipbreakerKrakenReplacementEffect() {
super(Duration.Custom, Outcome.Detriment);
this.staticText = "Those creatures don't untap during their controllers' untap steps for as long as you control {this}";
}
public ShipbreakerKrakenReplacementEffect(final ShipbreakerKrakenReplacementEffect effect) {
super(effect);
}
@Override
public ShipbreakerKrakenReplacementEffect copy() {
return new ShipbreakerKrakenReplacementEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.LOST_CONTROL ||
event.getType() == GameEvent.EventType.ZONE_CHANGE ||
event.getType() == GameEvent.EventType.UNTAP;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
// Source must be on the battlefield (it's neccessary to check here because if as response to the enter
// the battlefield triggered ability the source dies (or will be exiled), then the ZONE_CHANGE or LOST_CONTROL
// event will happen before this effect is applied ever)
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (sourcePermanent == null || !sourcePermanent.isControlledBy(source.getControllerId())) {
discard();
return false;
}
if (event.getType() == GameEvent.EventType.LOST_CONTROL) {
if (event.getTargetId().equals(source.getSourceId())) {
discard();
return false;
}
}
if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(source.getSourceId())) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
discard();
return false;
}
}
if (game.getTurn().getStepType() == PhaseStep.UNTAP && event.getType() == GameEvent.EventType.UNTAP) {
if (targetPointer.getTargets(game, source).contains(event.getTargetId())) {
return true;
}
}
return false;
}
}
class ShipbreakerKrakenWatcher extends Watcher {
ShipbreakerKrakenWatcher () {
super(WatcherScope.CARD);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.LOST_CONTROL
&& event.getPlayerId().equals(controllerId)
&& event.getTargetId().equals(sourceId)) {
condition = true;
game.replaceEvent(event);
return;
}
if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(sourceId)) {
ZoneChangeEvent zEvent = (ZoneChangeEvent)event;
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
condition = true;
game.replaceEvent(event);
}
}
}
@Override
public void reset() {
//don't reset condition each turn - only when this leaves the battlefield
}
}

View file

@ -1,12 +1,8 @@
package mage.cards.t;
import java.util.Objects;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EndOfCombatTriggeredAbility;
import mage.abilities.condition.common.SourceOnBattlefieldControlUnchangedCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
@ -21,37 +17,37 @@ import mage.game.combat.CombatGroup;
import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTarget;
import mage.watchers.common.BlockedAttackerWatcher;
import mage.watchers.common.LostControlWatcher;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*
* <p>
* 5/1/2009 The ability grants you control of all creatures that are blocking it
* as the ability resolves. This will include any creatures that were put onto
* the battlefield blocking it.
*
* <p>
* 5/1/2009 Any blocking creatures that regenerated during combat will have been
* removed from combat. Since such creatures are no longer in combat, they
* cannot be blocking The Wretched, which means you won't be able to gain
* control of them.
*
* <p>
* 5/1/2009 If The Wretched itself regenerated during combat, then it will have
* been removed from combat. Since it is no longer in combat, there cannot be
* any creatures blocking it, which means you won't be able to gain control of
* any creatures.
*
* <p>
* 10/1/2009 The Wretched's ability triggers only if it's still on the
* battlefield when the end of combat step begins (after the combat damage
* step). For example, if it's blocked by a 7/7 creature and is destroyed, its
* ability won't trigger at all.
*
* <p>
* 10/1/2009 If The Wretched leaves the battlefield, you no longer control it,
* so the duration of its control-change effect ends.
*
* <p>
* 10/1/2009 If you lose control of The Wretched before its ability resolves,
* you won't gain control of the creatures blocking it at all.
*
* <p>
* 10/1/2009 Once the ability resolves, it doesn't care whether the permanents
* you gained control of remain creatures, only that they remain on the
* battlefield.
@ -65,9 +61,7 @@ public final class TheWretched extends CardImpl {
this.toughness = new MageInt(5);
// At end of combat, gain control of all creatures blocking The Wretched for as long as you control The Wretched.
Ability ability = new EndOfCombatTriggeredAbility(new TheWretchedEffect(), false);
this.addAbility(ability, new BlockedAttackerWatcher());
ability.addWatcher(new LostControlWatcher());
this.addAbility(new EndOfCombatTriggeredAbility(new TheWretchedEffect(), false), new BlockedAttackerWatcher());
}
private TheWretched(final TheWretched card) {
@ -93,33 +87,27 @@ class TheWretchedEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent theWretched = (Permanent) source.getSourceObjectIfItStillExists(game);
if (theWretched == null) {
return false;
}
if (theWretched.isRemovedFromCombat() || !theWretched.isAttacking()) {
Permanent theWretched = source.getSourcePermanentIfItStillExists(game);
if (theWretched == null
|| theWretched.isRemovedFromCombat()
|| !theWretched.isAttacking()
|| !source.isControlledBy(theWretched.getControllerId())) {
return false;
}
// Check if control of source has changed since ability triggered????? (does it work is it neccessary???)
Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId());
if (permanent != null && !Objects.equals(permanent.getControllerId(), source.getControllerId())) {
return false;
}
for (CombatGroup combatGroup : game.getCombat().getGroups()) {
if (combatGroup.getAttackers().contains(source.getSourceId())) {
for (UUID creatureId : combatGroup.getBlockers()) {
Permanent blocker = game.getPermanent(creatureId);
if (blocker != null
&& blocker.getBlocking() > 0) {
ContinuousEffect effect = new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.Custom, source.getControllerId()),
new SourceOnBattlefieldControlUnchangedCondition(), "");
effect.setTargetPointer(new FixedTarget(blocker.getId(), game));
game.addEffect(effect, source);
}
if (!combatGroup.getAttackers().contains(source.getSourceId())) {
continue;
}
for (UUID creatureId : combatGroup.getBlockers()) {
Permanent blocker = game.getPermanent(creatureId);
if (blocker == null
|| blocker.getBlocking() <= 0) {
continue;
}
ContinuousEffect effect = new GainControlTargetEffect(Duration.WhileControlled, source.getControllerId());
effect.setTargetPointer(new FixedTarget(blocker.getId(), game));
game.addEffect(effect, source);
}
}
return true;

View file

@ -1,13 +1,10 @@
package mage.cards.t;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.SourceOnBattlefieldControlUnchangedCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.cards.CardImpl;
@ -18,19 +15,15 @@ import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.TargetPermanent;
import mage.watchers.common.LostControlWatcher;
import java.util.UUID;
/**
*
* @author MarcoMarin
*/
public final class ThrullChampion extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Thrull creatures");
static {
filter.add(SubType.THRULL.getPredicate());
}
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.THRULL, "Thrull creatures");
public ThrullChampion(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}");
@ -40,14 +33,11 @@ public final class ThrullChampion extends CardImpl {
// Thrull creatures get +1/+1.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, false)));
// {tap}: Gain control of target Thrull for as long as you control Thrull Champion.
ConditionalContinuousEffect ThrullChampionGainControlEffect = new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.Custom),
new SourceOnBattlefieldControlUnchangedCondition(),
"Gain control of target Thrull for as long as you control {this}");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, ThrullChampionGainControlEffect, new TapSourceCost());
Ability ability = new SimpleActivatedAbility(new GainControlTargetEffect(Duration.WhileControlled)
.setText("gain control of target Thrull for as long as you control {this}"), new TapSourceCost());
ability.addTarget(new TargetPermanent(filter));
ability.addWatcher(new LostControlWatcher());
this.addAbility(ability);
}

View file

@ -1,48 +1,43 @@
package mage.cards.t;
import java.util.UUID;
import mage.MageInt;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.common.DontUntapInControllersUntapStepTargetEffect;
import mage.abilities.effects.common.TapTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.PhaseStep;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.constants.WatcherScope;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.target.Target;
import mage.target.common.TargetCreaturePermanent;
import mage.watchers.Watcher;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class TidebinderMage extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("red or green creature an opponent controls");
private static final FilterCreaturePermanent filter
= new FilterCreaturePermanent("red or green creature an opponent controls");
static {
filter.add(TargetController.OPPONENT.getControllerPredicate());
filter.add(Predicates.or(new ColorPredicate(ObjectColor.RED), new ColorPredicate(ObjectColor.GREEN)));
filter.add(Predicates.or(
new ColorPredicate(ObjectColor.RED),
new ColorPredicate(ObjectColor.GREEN)
));
}
public TidebinderMage(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{U}{U}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{U}");
this.subtype.add(SubType.MERFOLK);
this.subtype.add(SubType.WIZARD);
@ -52,11 +47,9 @@ public final class TidebinderMage extends CardImpl {
// When Tidebinder Mage enters the battlefield, tap target red or green creature an opponent controls.
// That creature doesn't untap during its controller's untap step for as long as you control Tidebinder Mage.
Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect(), false);
ability.addEffect(new TidebinderMageEffect());
Target target = new TargetCreaturePermanent(filter);
ability.addTarget(target);
this.addAbility(ability, new TidebinderMageWatcher());
ability.addEffect(new DontUntapInControllersUntapStepTargetEffect(Duration.WhileControlled));
ability.addTarget(new TargetCreaturePermanent(filter));
this.addAbility(ability);
}
private TidebinderMage(final TidebinderMage card) {
@ -68,90 +61,3 @@ public final class TidebinderMage extends CardImpl {
return new TidebinderMage(this);
}
}
class TidebinderMageEffect extends ContinuousRuleModifyingEffectImpl {
public TidebinderMageEffect() {
super(Duration.OneUse, Outcome.Detriment, false, false);
this.staticText = "That creature doesn't untap during its controller's untap step for as long as you control {this}";
}
public TidebinderMageEffect(final TidebinderMageEffect effect) {
super(effect);
}
@Override
public TidebinderMageEffect copy() {
return new TidebinderMageEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
// Source must be on the battlefield (it's neccessary to check here because if as response to the enter
// the battlefield triggered ability the source dies (or will be exiled), then the ZONE_CHANGE or LOST_CONTROL
// event will happen before this effect is applied ever)
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (sourcePermanent == null || !sourcePermanent.isControlledBy(source.getControllerId())) {
discard();
return false;
}
if (event.getType() == GameEvent.EventType.LOST_CONTROL) {
if (event.getTargetId().equals(source.getSourceId())) {
discard();
return false;
}
}
if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(source.getSourceId())) {
ZoneChangeEvent zEvent = (ZoneChangeEvent)event;
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
discard();
return false;
}
}
if (game.getTurn().getStepType() == PhaseStep.UNTAP && event.getType() == GameEvent.EventType.UNTAP) {
if (event.getTargetId().equals(targetPointer.getFirst(game, source))) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null && game.isActivePlayer(permanent.getControllerId())) {
return true;
}
}
}
return false;
}
}
class TidebinderMageWatcher extends Watcher {
TidebinderMageWatcher () {
super(WatcherScope.CARD);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.LOST_CONTROL
&& event.getPlayerId().equals(controllerId)
&& event.getTargetId().equals(sourceId)) {
condition = true;
game.replaceEvent(event);
return;
}
if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(sourceId)) {
ZoneChangeEvent zEvent = (ZoneChangeEvent)event;
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
condition = true;
game.replaceEvent(event);
}
}
}
@Override
public void reset() {
//don't reset condition each turn - only when this leaves the battlefield
}
}

View file

@ -1,35 +1,25 @@
package mage.cards.t;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SagaAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.Effects;
import mage.abilities.effects.common.DontUntapInControllersUntapStepTargetEffect;
import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect;
import mage.abilities.effects.common.TapTargetEffect;
import mage.constants.SubType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.PhaseStep;
import mage.constants.SagaChapter;
import mage.constants.WatcherScope;
import mage.constants.Zone;
import mage.constants.SubType;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.TappedPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
import mage.watchers.Watcher;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class TimeOfIce extends CardImpl {
@ -51,7 +41,7 @@ public final class TimeOfIce extends CardImpl {
// I, II Tap target creature an opponent controls. It doesn't untap during its controller's untap step for as long as you control Time of Ice.
Effects effects = new Effects();
effects.add(new TapTargetEffect());
effects.add(new TimeOfIceEffect());
effects.add(new DontUntapInControllersUntapStepTargetEffect(Duration.WhileControlled, "It"));
sagaAbility.addChapterEffect(
this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, effects,
new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)
@ -59,7 +49,7 @@ public final class TimeOfIce extends CardImpl {
// III Return all tapped creatures to their owners' hands.
sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ReturnToHandFromBattlefieldAllEffect(filter));
this.addAbility(sagaAbility, new TimeOfIceWatcher());
this.addAbility(sagaAbility);
}
private TimeOfIce(final TimeOfIce card) {
@ -71,101 +61,3 @@ public final class TimeOfIce extends CardImpl {
return new TimeOfIce(this);
}
}
class TimeOfIceEffect extends ContinuousRuleModifyingEffectImpl {
public TimeOfIceEffect() {
super(Duration.Custom, Outcome.Detriment, false, false);
this.staticText = "That creature doesn't untap during its controller's untap step for as long as you control {this}";
}
public TimeOfIceEffect(final TimeOfIceEffect effect) {
super(effect);
}
@Override
public TimeOfIceEffect copy() {
return new TimeOfIceEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.UNTAP
|| event.getType() == GameEvent.EventType.ZONE_CHANGE
|| event.getType() == GameEvent.EventType.LOST_CONTROL;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
// Source must be on the battlefield (it's neccessary to check here because if as response to the enter
// the battlefield triggered ability the source dies (or will be exiled), then the ZONE_CHANGE or LOST_CONTROL
// event will happen before this effect is applied ever)
Permanent sourceObject = game.getPermanent(source.getSourceId());
if (sourceObject == null || sourceObject.getZoneChangeCounter(game) > source.getSourceObjectZoneChangeCounter() + 1) {
discard();
return false;
}
switch (event.getType()) {
case ZONE_CHANGE:
// end effect if source does a zone move
if (event.getTargetId().equals(source.getSourceId())) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
discard();
return false;
}
}
break;
case UNTAP:
// prevent to untap the target creature
if (game.getTurn().getStepType() == PhaseStep.UNTAP && event.getTargetId().equals(targetPointer.getFirst(game, source))) {
Permanent targetCreature = game.getPermanent(targetPointer.getFirst(game, source));
if (targetCreature != null) {
return targetCreature.isControlledBy(game.getActivePlayerId());
} else {
discard();
return false;
}
}
break;
case LOST_CONTROL:
// end effect if source control is changed
if (event.getTargetId().equals(source.getSourceId())) {
discard();
return false;
}
break;
}
return false;
}
}
class TimeOfIceWatcher extends Watcher {
TimeOfIceWatcher() {
super(WatcherScope.CARD);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.LOST_CONTROL
&& event.getPlayerId().equals(controllerId)
&& event.getTargetId().equals(sourceId)) {
condition = true;
game.replaceEvent(event);
return;
}
if (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(sourceId)) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
condition = true;
game.replaceEvent(event);
}
}
}
@Override
public void reset() {
//don't reset condition each turn - only when this leaves the battlefield
}
}

View file

@ -4,14 +4,11 @@ import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.ContinuousRuleModifyingEffect;
import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
import mage.abilities.effects.EntersBattlefieldEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.common.DontUntapInControllersUntapStepTargetEffect;
import mage.abilities.effects.common.TapTargetEffect;
import mage.abilities.keyword.DefenderAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -35,8 +32,8 @@ import java.util.UUID;
*/
public final class WallOfStolenIdentity extends CardImpl {
final static private String rule = "You may have Wall of Stolen Identity enter the battlefield as a copy of any "
+ "creature on the battlefield, except it's a wall in addition to its other types and it has defender. "
final static private String rule = "You may have {this} enter the battlefield as a copy of any "
+ "creature on the battlefield, except it's a Wall in addition to its other types and it has defender. "
+ "When you do, tap the copied creature and it doesn't untap during its "
+ "controller's untap step for as long as you control {this}";
@ -49,9 +46,9 @@ public final class WallOfStolenIdentity extends CardImpl {
this.toughness = new MageInt(0);
// You may have Wall of Stolen Identity enter the battlefield as a copy of any creature on the battlefield, except it's a wall in addition to its other types and it has defender. When you do, tap the copied creature and it doesn't untap during its controller's untap step for as long as you control Wall of Stolen Identity.
Ability ability = new SimpleStaticAbility(
new EntersBattlefieldEffect(new WallOfStolenIdentityCopyEffect(), rule, true)
);
Ability ability = new SimpleStaticAbility(new EntersBattlefieldEffect(
new WallOfStolenIdentityCopyEffect(), rule, true
));
this.addAbility(ability);
}
@ -67,8 +64,7 @@ public final class WallOfStolenIdentity extends CardImpl {
class WallOfStolenIdentityCopyEffect extends OneShotEffect {
private static final String rule2 = "When you do, tap the copied creature and it doesn't untap during its "
+ "controller's untap step for as long as you control {this}.";
private static final String rule2 = "When you do, .";
public WallOfStolenIdentityCopyEffect() {
super(Outcome.Copy);
@ -115,18 +111,13 @@ class WallOfStolenIdentityCopyEffect extends OneShotEffect {
}
});
copyFromPermanent.tap(source, game);
// Incredibly, you can't just add a fixed target to a continuousrulemodifyingeffect, thus the workaround.
ContinuousRuleModifyingEffect effect = new DontUntapInControllersUntapStepSourceEffect();
Ability ability = new SimpleStaticAbility(effect);
ContinuousEffect effect2 = new GainAbilityTargetEffect(ability, Duration.Custom);
ConditionalContinuousEffect conditionalEffect = new ConditionalContinuousEffect(
effect2, new WallOfStolenIdentityCondition(
source,
source.getControllerId(),
sourcePermanent.getZoneChangeCounter(game)), "");
conditionalEffect.setTargetPointer(new FixedTarget(target.getFirstTarget()));
game.addEffect(conditionalEffect, source);
ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(
new TapTargetEffect(), false, "tap the copied creature " +
"and it doesn't untap during its controller's untap step for as long as you control {this}"
);
ability.addEffect(new DontUntapInControllersUntapStepTargetEffect(Duration.WhileControlled));
ability.getEffects().setTargetPointer(new FixedTarget(copyFromPermanent, game));
game.fireReflexiveTriggeredAbility(ability, source);
return true;
}
@ -135,27 +126,3 @@ class WallOfStolenIdentityCopyEffect extends OneShotEffect {
return new WallOfStolenIdentityCopyEffect(this);
}
}
class WallOfStolenIdentityCondition implements Condition {
// Checks for when it leaves play or changes control
private final Ability ability;
private final UUID controllerId;
private final int zcc;
public WallOfStolenIdentityCondition(Ability ability, UUID controllerId, int zcc) {
this.ability = ability;
this.controllerId = controllerId;
this.zcc = zcc;
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanentSource = game.getPermanent(ability.getSourceId());
if (permanentSource != null) {
return permanentSource.getZoneChangeCounter(game) == zcc + 1
&& permanentSource.getControllerId() == controllerId;
}
return false;
}
}

View file

@ -1,11 +1,7 @@
package mage.cards.w;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.condition.common.SourceOnBattlefieldControlUnchangedCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.continuous.GainControlTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -16,12 +12,11 @@ import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import mage.watchers.common.LostControlWatcher;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class Willbreaker extends CardImpl {
@ -34,11 +29,7 @@ public final class Willbreaker extends CardImpl {
this.toughness = new MageInt(3);
// Whenever a creature an opponent controls becomes the target of a spell or ability you control, gain control of that creature for as long as you control Willbreaker.
ConditionalContinuousEffect effect = new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.EndOfGame),
new SourceOnBattlefieldControlUnchangedCondition(), null);
effect.setText("gain control of that creature for as long as you control {this}");
this.addAbility(new WillbreakerTriggeredAbility(effect), new LostControlWatcher());
this.addAbility(new WillbreakerTriggeredAbility());
}
private Willbreaker(final Willbreaker card) {
@ -53,11 +44,11 @@ public final class Willbreaker extends CardImpl {
class WillbreakerTriggeredAbility extends TriggeredAbilityImpl {
public WillbreakerTriggeredAbility(Effect effect) {
super(Zone.BATTLEFIELD, effect);
WillbreakerTriggeredAbility() {
super(Zone.BATTLEFIELD, new GainControlTargetEffect(Duration.WhileControlled));
}
public WillbreakerTriggeredAbility(WillbreakerTriggeredAbility ability) {
private WillbreakerTriggeredAbility(final WillbreakerTriggeredAbility ability) {
super(ability);
}
@ -68,25 +59,23 @@ class WillbreakerTriggeredAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (isControlledBy(event.getPlayerId())) {
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null
&& permanent.isCreature(game)) {
Player controller = game.getPlayer(getControllerId());
if (controller != null
&& controller.hasOpponent(permanent.getControllerId(), game)) {
// always call this method for FixedTargets in case it is blinked
getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
return true;
}
}
if (!isControlledBy(event.getPlayerId())) {
return false;
}
return false;
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent == null || !permanent.isCreature(game)
|| !game.getOpponents(getControllerId()).contains(permanent.getControllerId())) {
return false;
}
// always call this method for FixedTargets in case it is blinked
this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
return true;
}
@Override
public String getTriggerPhrase() {
return "Whenever a creature an opponent controls becomes the target of a spell or ability you control, ";
public String getRule() {
return "Whenever a creature an opponent controls becomes the target of a spell or ability you control, " +
"gain control of that creature for as long as you control {this}";
}
@Override

View file

@ -1,12 +1,9 @@
package mage.cards.w;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SkipUntapOptionalAbility;
import mage.abilities.condition.CompoundCondition;
import mage.abilities.condition.common.SourceOnBattlefieldControlUnchangedCondition;
import mage.abilities.condition.common.SourceTappedCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.decorator.ConditionalContinuousEffect;
@ -17,13 +14,12 @@ import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.target.common.TargetCreaturePermanent;
import mage.watchers.common.LostControlWatcher;
import java.util.UUID;
/**
*
* @author fireshoes
*/
public final class WillowSatyr extends CardImpl {
@ -42,13 +38,13 @@ public final class WillowSatyr extends CardImpl {
// You may choose not to untap Willow Satyr during your untap step.
this.addAbility(new SkipUntapOptionalAbility());
// {tap}: Gain control of target legendary creature for as long as you control Willow Satyr and Willow Satyr remains tapped.
ConditionalContinuousEffect effect = new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.Custom), new CompoundCondition(SourceTappedCondition.instance, new SourceOnBattlefieldControlUnchangedCondition()),
"Gain control of target legendary creature for as long as you control {this} and {this} remains tapped");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost());
Ability ability = new SimpleActivatedAbility(new ConditionalContinuousEffect(
new GainControlTargetEffect(Duration.WhileControlled), SourceTappedCondition.instance,
"Gain control of target legendary creature for as long as you control {this} and {this} remains tapped"
), new TapSourceCost());
ability.addTarget(new TargetCreaturePermanent(filter));
ability.addWatcher(new LostControlWatcher());
this.addAbility(ability);
}

View file

@ -57,6 +57,7 @@ public final class KamigawaNeonDynasty extends ExpansionSet {
cards.add(new SetCardInfo("Kaito Shizuki", 226, Rarity.MYTHIC, mage.cards.k.KaitoShizuki.class));
cards.add(new SetCardInfo("Kappa Tech-Wrecker", 198, Rarity.UNCOMMON, mage.cards.k.KappaTechWrecker.class));
cards.add(new SetCardInfo("Kodama of the West Tree", 199, Rarity.MYTHIC, mage.cards.k.KodamaOfTheWestTree.class));
cards.add(new SetCardInfo("Kyodai, Soul of Kamigawa", 23, Rarity.RARE, mage.cards.k.KyodaiSoulOfKamigawa.class));
cards.add(new SetCardInfo("Leech Gauntlet", 106, Rarity.UNCOMMON, mage.cards.l.LeechGauntlet.class));
cards.add(new SetCardInfo("Lion Sash", 26, Rarity.RARE, mage.cards.l.LionSash.class));
cards.add(new SetCardInfo("Lizard Blades", 153, Rarity.RARE, mage.cards.l.LizardBlades.class));

View file

@ -0,0 +1,118 @@
package org.mage.test.cards.single.m12;
import mage.abilities.keyword.IndestructibleAbility;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author TheElk801
*/
public class AegisAngelTest extends CardTestPlayerBase {
private static final String angel = "Aegis Angel";
private static final String lion = "Silvercoat Lion";
private static final String murder = "Murder";
private static final String act = "Act of Treason";
@Test
public void testGainsAbility() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 6);
addCard(Zone.BATTLEFIELD, playerA, lion);
addCard(Zone.HAND, playerA, angel);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, angel);
addTarget(playerA, lion);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertAbility(playerA, lion, IndestructibleAbility.getInstance(), true);
}
@Test
public void testKeepsAbility() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 6);
addCard(Zone.BATTLEFIELD, playerA, lion);
addCard(Zone.HAND, playerA, angel);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, angel);
addTarget(playerA, lion);
setStrictChooseMode(true);
setStopAt(3, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertAbility(playerA, lion, IndestructibleAbility.getInstance(), true);
}
@Test
public void testAngelDiesBeforeEntering() {
addCard(Zone.BATTLEFIELD, playerA, "Scrubland", 9);
addCard(Zone.BATTLEFIELD, playerA, lion);
addCard(Zone.HAND, playerA, angel);
addCard(Zone.HAND, playerA, murder);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, angel);
addTarget(playerA, lion);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, murder, angel);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertGraveyardCount(playerA, angel, 1);
assertGraveyardCount(playerA, murder, 1);
assertAbility(playerA, lion, IndestructibleAbility.getInstance(), false);
}
@Test
public void testAngelDiesAfterEntering() {
addCard(Zone.BATTLEFIELD, playerA, "Scrubland", 9);
addCard(Zone.BATTLEFIELD, playerA, lion);
addCard(Zone.HAND, playerA, angel);
addCard(Zone.HAND, playerA, murder);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, angel);
addTarget(playerA, lion);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, murder, angel);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertGraveyardCount(playerA, angel, 1);
assertGraveyardCount(playerA, murder, 1);
assertAbility(playerA, lion, IndestructibleAbility.getInstance(), false);
}
@Test
public void testAngelLoseControl() {
addCard(Zone.BATTLEFIELD, playerA, "Plains", 6);
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 6);
addCard(Zone.BATTLEFIELD, playerA, lion);
addCard(Zone.HAND, playerA, angel);
addCard(Zone.HAND, playerB, act);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, angel);
addTarget(playerA, lion);
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, act, angel);
setStrictChooseMode(true);
setStopAt(2, PhaseStep.END_TURN);
execute();
assertAllCommandsUsed();
assertGraveyardCount(playerB, act, 1);
assertPermanentCount(playerB, angel, 1);
assertAbility(playerA, lion, IndestructibleAbility.getInstance(), false);
}
}

View file

@ -1,43 +0,0 @@
package mage.abilities.condition.common;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.game.Game;
import mage.watchers.common.LostControlWatcher;
/**
* This condition checks if ever since first call of the apply method the
* controller of the source has changed
*
* Monitoring the LOST_CONTROL event has the advantage that also all layered
* effects can correctly check for controller change because comparing old and
* new controller during their apply time does not take into account layered
* change control effects that will be applied later.
*
* This condition needs the LostControlWatcher, so be sure to add it to the card
* that uses the condition.
*
* @author LevelX2
*/
public class SourceOnBattlefieldControlUnchangedCondition implements Condition {
private Long checkingSince;
private int startingZoneChangeCounter;
@Override
public boolean apply(Game game, Ability source) {
if (checkingSince == null) {
checkingSince = System.currentTimeMillis() - 1;
startingZoneChangeCounter = game.getState().getZoneChangeCounter(source.getSourceId());
}
if (game.getState().getZoneChangeCounter(source.getSourceId()) > startingZoneChangeCounter) {
return false;
}
LostControlWatcher watcher = game.getState().getWatcher(LostControlWatcher.class);
if (watcher != null) {
return checkingSince > watcher.getOrderOfLastLostControl(source.getSourceId());
}
throw new UnsupportedOperationException("LostControlWatcher not found!");
}
}

View file

@ -104,8 +104,13 @@ public class ConditionalContinuousEffect extends ContinuousEffectImpl {
if (!conditionState && effect.getDuration() == Duration.OneUse) {
used = true;
}
if (!conditionState && effect.getDuration() == Duration.Custom) {
this.discard();
switch (effect.getDuration()) {
case OneUse:
used = true;
break;
case Custom:
case WhileControlled:
this.discard();
}
return false;
}
@ -123,11 +128,13 @@ public class ConditionalContinuousEffect extends ContinuousEffectImpl {
otherwiseEffect.setTargetPointer(this.targetPointer);
return otherwiseEffect.apply(game, source);
}
if (effect.getDuration() == Duration.OneUse) {
used = true;
}
if (effect.getDuration() == Duration.Custom) {
this.discard();
switch (effect.getDuration()) {
case OneUse:
used = true;
break;
case Custom:
case WhileControlled:
this.discard();
}
return false;
}
@ -176,7 +183,8 @@ public class ConditionalContinuousEffect extends ContinuousEffectImpl {
/**
* Return all effects list, for tests only
* @return
*
* @return
*/
public List<ContinuousEffect> getAllEffects() {
List<ContinuousEffect> res = new ArrayList<>();

View file

@ -177,6 +177,7 @@ public class ContinuousEffects implements Serializable {
for (ContinuousEffect effect : layeredEffects) {
switch (effect.getDuration()) {
case WhileOnBattlefield:
case WhileControlled:
case WhileOnStack:
case WhileInGraveyard:
Set<Ability> abilities = layeredEffects.getAbility(effect.getId());

View file

@ -1,6 +1,5 @@
package mage.abilities.effects;
import java.util.*;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.MageSingleton;
@ -8,9 +7,12 @@ import mage.cards.Card;
import mage.constants.Duration;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import org.apache.log4j.Logger;
import java.util.*;
/**
* @param <T>
* @author BetaSteward_at_googlemail.com
@ -145,6 +147,12 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
}
break;
case Custom:
case UntilYourNextTurn:
case UntilEndOfYourNextTurn:
// until your turn effects continue until real turn reached, their used it's own inactive method
// 514.2 Second, the following actions happen simultaneously: all damage marked on permanents
// (including phased-out permanents) is removed and all "until end of turn" and "this turn" effects end.
// This turn-based action doesnt use the stack.
// custom effects must process it's own inactive method (override)
// custom effects may not end, if the source permanent of the effect has left the game
// 800.4a (only any effects which give that player control of any objects or players end)
@ -156,18 +164,14 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
// end of turn discards on cleanup steps
// 514.2
break;
case UntilYourNextTurn:
case UntilEndOfYourNextTurn:
// until your turn effects continue until real turn reached, their used it's own inactive method
// 514.2 Second, the following actions happen simultaneously: all damage marked on permanents
// (including phased-out permanents) is removed and all "until end of turn" and "this turn" effects end.
// This turn-based action doesnt use the stack.
if (effect.isInactive(ability, game)) {
case UntilSourceLeavesBattlefield:
if (hasOwnerLeftGame || game.getState().getZone(ability.getSourceId()) != Zone.BATTLEFIELD) {
it.remove();
}
break;
case UntilSourceLeavesBattlefield:
if (hasOwnerLeftGame || Zone.BATTLEFIELD != game.getState().getZone(ability.getSourceId())) {
case WhileControlled:
Permanent permanent = ability.getSourcePermanentIfItStillExists(game);
if (hasOwnerLeftGame || permanent == null || !permanent.isControlledBy(ability.getControllerId())) {
it.remove();
}
break;

View file

@ -1,7 +1,5 @@
package mage.abilities.effects.common;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
@ -12,18 +10,27 @@ import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import java.util.UUID;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class DontUntapInControllersUntapStepTargetEffect extends ContinuousRuleModifyingEffectImpl {
private final String targetName;
public DontUntapInControllersUntapStepTargetEffect(Duration duration) {
this(duration, "That creature");
}
public DontUntapInControllersUntapStepTargetEffect(Duration duration, String targetName) {
super(duration, Outcome.Detriment);
this.targetName = targetName;
}
public DontUntapInControllersUntapStepTargetEffect(final DontUntapInControllersUntapStepTargetEffect effect) {
super(effect);
this.targetName = effect.targetName;
}
@Override
@ -36,16 +43,6 @@ public class DontUntapInControllersUntapStepTargetEffect extends ContinuousRuleM
return false;
}
@Override
public String getInfoMessage(Ability source, GameEvent event, Game game) {
MageObject mageObject = game.getObject(source.getSourceId());
Permanent permanentToUntap = game.getPermanent((event.getTargetId()));
if (permanentToUntap != null && mageObject != null) {
return permanentToUntap.getIdName() + " doesn't untap (" + mageObject.getIdName() + ')';
}
return null;
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.UNTAP;
@ -53,14 +50,16 @@ public class DontUntapInControllersUntapStepTargetEffect extends ContinuousRuleM
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (game.getTurn().getStepType() == PhaseStep.UNTAP) {
for (UUID targetId : targetPointer.getTargets(game, source)) {
if (event.getTargetId().equals(targetId)) {
Permanent permanent = game.getPermanent(targetId);
if (permanent != null && game.isActivePlayer(permanent.getControllerId())) {
return true;
}
}
if (game.getTurn().getStepType() != PhaseStep.UNTAP) {
return false;
}
for (UUID targetId : targetPointer.getTargets(game, source)) {
if (!event.getTargetId().equals(targetId)) {
continue;
}
Permanent permanent = game.getPermanent(targetId);
if (permanent != null && game.isActivePlayer(permanent.getControllerId())) {
return true;
}
}
return false;
@ -68,11 +67,11 @@ public class DontUntapInControllersUntapStepTargetEffect extends ContinuousRuleM
@Override
public String getText(Mode mode) {
if (staticText != null) {
if (staticText != null && !staticText.isEmpty()) {
return staticText;
}
return "target " + mode.getTargets().get(0).getTargetName()
+ " doesn't untap during its controller's untap step" + (getDuration().toString().isEmpty() ? "" : " " + getDuration());
return targetName + " doesn't untap during its controller's untap step"
+ (getDuration().toString().isEmpty() ? "" : " ") + getDuration();
}
}

View file

@ -7,6 +7,7 @@ public enum Duration {
OneUse("", true, true),
EndOfGame("for the rest of the game", false, false),
WhileOnBattlefield("", false, false),
WhileControlled("for as long as you control {this}", true, false),
WhileOnStack("", false, true),
WhileInGraveyard("", false, false),
EndOfTurn("until end of turn", true, true),

View file

@ -1,39 +0,0 @@
package mage.watchers.common;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import mage.constants.WatcherScope;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.watchers.Watcher;
/**
*
* @author LevelX2
*/
public class LostControlWatcher extends Watcher {
private final Map<UUID, Long> lastLostControl = new HashMap<>();
public LostControlWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.LOST_CONTROL) {
lastLostControl.put(event.getTargetId(), System.currentTimeMillis());
}
}
@Override
public void reset() {
super.reset();
lastLostControl.clear();
}
public long getOrderOfLastLostControl(UUID sourceId) {
return lastLostControl.getOrDefault(sourceId, new Long(0));
}
}