- Added Krovikan Vampire. Fixed Duplicity.

This commit is contained in:
Jeff 2018-12-27 18:01:37 -06:00
parent 8485d70552
commit ff11727596
4 changed files with 322 additions and 12 deletions

View file

@ -6,10 +6,15 @@ import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.StaticAbility;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.EntersBattlefieldEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.discard.DiscardControllerEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
@ -21,8 +26,8 @@ import mage.constants.TargetController;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.players.Player;
import mage.util.CardUtil;
/**
*
@ -43,7 +48,7 @@ public final class Duplicity extends CardImpl {
this.addAbility(new BeginningOfYourEndStepTriggeredAbility(new DiscardControllerEffect(1), false));
// When you lose control of Duplicity, put all cards exiled with Duplicity into their owner's graveyard.
this.addAbility(new LoseControlDuplicity());
this.addAbility(new DuplicityEntersBattlefieldAbility(new CreateDelayedTriggeredAbilityEffect(new LoseControlDuplicity())));
}
@ -75,7 +80,7 @@ class DuplicityEffect extends OneShotEffect {
if (controller != null
&& sourceObject != null) {
if (controller.getLibrary().hasCards()) {
UUID exileId = CardUtil.getCardExileZoneId(game, source);
UUID exileId = source.getSourceId();
Set<Card> cardsToExile = controller.getLibrary().getTopCards(game, 5);
for (Card card : cardsToExile) {
controller.moveCardsToExile(card, source, game, true, exileId, sourceObject.getName());
@ -111,7 +116,7 @@ class DuplicityExileHandEffect extends OneShotEffect {
if (controller != null
&& sourceObject != null) {
if (!controller.getHand().isEmpty()) {
UUID exileId = CardUtil.getCardExileZoneId(game, source);
UUID exileId = source.getSourceId();
Set<Card> cardsFromHandToExile = controller.getHand().getCards(game);
for (Card card : cardsFromHandToExile) {
controller.moveCardsToExile(card, source, game, true, exileId, sourceObject.getName());
@ -154,12 +159,23 @@ class LoseControlDuplicity extends DelayedTriggeredAbility {
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.LOST_CONTROL;
return event.getType() == GameEvent.EventType.LOST_CONTROL
|| event.getType() == GameEvent.EventType.ZONE_CHANGE;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return event.getPlayerId().equals(controllerId);
if (event.getType() == GameEvent.EventType.LOST_CONTROL
&& event.getPlayerId().equals(controllerId)
&& event.getSourceId().equals(getSourceId())) {
return true;
}
if (event.getType() == GameEvent.EventType.ZONE_CHANGE
&& event.getTargetId().equals(getSourceId())
&& ((ZoneChangeEvent) event).getToZone() != Zone.BATTLEFIELD) {
return true;
}
return false;
}
@Override
@ -182,13 +198,13 @@ class PutExiledCardsInOwnersGraveyard extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source.getSourceId());
if (controller != null
&& sourceObject != null) {
UUID exileId = CardUtil.getCardExileZoneId(game, source);
if (controller != null) {
UUID exileId = source.getSourceId();
Set<Card> cardsInExile = game.getExile().getExileZone(exileId).getCards(game);
controller.moveCardsToGraveyardWithInfo(cardsInExile, source, game, Zone.EXILED);
return true;
if (cardsInExile != null) {
controller.moveCards(cardsInExile, Zone.GRAVEYARD, source, game);
return true;
}
}
return false;
}
@ -198,3 +214,31 @@ class PutExiledCardsInOwnersGraveyard extends OneShotEffect {
return new PutExiledCardsInOwnersGraveyard(this);
}
}
class DuplicityEntersBattlefieldAbility extends StaticAbility {
public DuplicityEntersBattlefieldAbility(Effect effect) {
super(Zone.ALL, new EntersBattlefieldEffect(effect, null, null, true, false));
}
public DuplicityEntersBattlefieldAbility(final DuplicityEntersBattlefieldAbility ability) {
super(ability);
}
@Override
public void addEffect(Effect effect) {
if (!getEffects().isEmpty()) {
Effect entersBattlefieldEffect = this.getEffects().get(0);
if (entersBattlefieldEffect instanceof EntersBattlefieldEffect) {
((EntersBattlefieldEffect) entersBattlefieldEffect).addEffect(effect);
return;
}
}
super.addEffect(effect);
}
@Override
public DuplicityEntersBattlefieldAbility copy() {
return new DuplicityEntersBattlefieldAbility(this);
}
}

View file

@ -0,0 +1,264 @@
package mage.cards.k;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.common.BeginningOfEndStepTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.SacrificeTargetEffect;
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.TargetController;
import mage.constants.WatcherScope;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import mage.watchers.Watcher;
/**
*
* @author jeffwadsworth
*/
public final class KrovikanVampire extends CardImpl {
public KrovikanVampire(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}");
this.subtype.add(SubType.VAMPIRE);
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// At the beginning of each end step, if a creature dealt damage by Krovikan Vampire this turn died, put that card onto the battlefield under your control. Sacrifice it when you lose control of Krovikan Vampire.
Ability ability = new BeginningOfEndStepTriggeredAbility(
Zone.BATTLEFIELD,
new KrovikanVampireEffect(),
TargetController.ANY,
KrovikanVampireInterveningIfCondition.instance,
false);
ability.addWatcher(new KrovikanVampireCreaturesDamagedWatcher());
ability.addWatcher(new KrovikanVampireCreaturesDiedWatcher());
this.addAbility(ability);
}
public KrovikanVampire(final KrovikanVampire card) {
super(card);
}
@Override
public KrovikanVampire copy() {
return new KrovikanVampire(this);
}
}
class KrovikanVampireEffect extends OneShotEffect {
Set<UUID> creaturesAffected = new HashSet<>();
KrovikanVampireEffect() {
super(Outcome.Neutral);
staticText = "put that card onto the battlefield under your control. Sacrifice it when you lose control of {this}";
}
KrovikanVampireEffect(KrovikanVampireEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
Permanent krovikanVampire = game.getPermanent(source.getSourceId());
creaturesAffected = (Set<UUID>) game.getState().getValue(source.getSourceId() + "creatureToGainControl");
if (creaturesAffected != null
&& controller != null
&& krovikanVampire != null) {
for (UUID creatureId : creaturesAffected) {
controller.moveCards(game.getCard(creatureId), Zone.BATTLEFIELD, source, game, false, false, false, null);
OneShotEffect effect = new SacrificeTargetEffect();
effect.setText("Sacrifice this if Krovikan Vampire leaves the battlefield or its current controller loses control of it.");
effect.setTargetPointer(new FixedTarget(creatureId));
KrovikanVampireDelayedTriggeredAbility dTA = new KrovikanVampireDelayedTriggeredAbility(effect, krovikanVampire.getId());
game.addDelayedTriggeredAbility(dTA, source);
}
creaturesAffected.clear();
return true;
}
return false;
}
@Override
public KrovikanVampireEffect copy() {
return new KrovikanVampireEffect(this);
}
}
enum KrovikanVampireInterveningIfCondition implements Condition {
instance;
Set<UUID> creaturesAffected = new HashSet<>();
@Override
public boolean apply(Game game, Ability source) {
KrovikanVampireCreaturesDiedWatcher watcherDied = (KrovikanVampireCreaturesDiedWatcher) game.getState().getWatchers().get(KrovikanVampireCreaturesDiedWatcher.class.getSimpleName());
KrovikanVampireCreaturesDamagedWatcher watcherDamaged = (KrovikanVampireCreaturesDamagedWatcher) game.getState().getWatchers().get(KrovikanVampireCreaturesDamagedWatcher.class.getSimpleName());
if (watcherDied != null) {
Set<UUID> creaturesThatDiedThisTurn = watcherDied.diedThisTurn;
if (creaturesThatDiedThisTurn != null) {
for (UUID mor : creaturesThatDiedThisTurn) {
if (watcherDamaged != null) {
for (UUID mor2 : watcherDamaged.getDamagedBySource()) {
if (mor2 != null
&& mor == mor2) {
creaturesAffected.add(mor);
}
}
}
}
if (creaturesAffected != null
&& creaturesAffected.size() > 0) {
game.getState().setValue(source.getSourceId() + "creatureToGainControl", creaturesAffected);
return true;
}
}
}
return false;
}
@Override
public String toString() {
return "if a creature dealt damage by Krovikan Vampire this turn died";
}
}
class KrovikanVampireCreaturesDamagedWatcher extends Watcher {
public final Set<UUID> damagedBySource = new HashSet<>();
public KrovikanVampireCreaturesDamagedWatcher() {
super(KrovikanVampireCreaturesDamagedWatcher.class.getSimpleName(), WatcherScope.GAME);
}
public KrovikanVampireCreaturesDamagedWatcher(final KrovikanVampireCreaturesDamagedWatcher watcher) {
super(watcher);
this.damagedBySource.addAll(watcher.damagedBySource);
}
@Override
public KrovikanVampireCreaturesDamagedWatcher copy() {
return new KrovikanVampireCreaturesDamagedWatcher(this);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == EventType.DAMAGED_CREATURE
&& sourceId.equals(event.getSourceId())) {
damagedBySource.add(event.getTargetId());
}
}
public Set<UUID> getDamagedBySource() {
return this.damagedBySource;
}
@Override
public void reset() {
damagedBySource.clear();
}
}
class KrovikanVampireCreaturesDiedWatcher extends Watcher {
public final Set<UUID> diedThisTurn = new HashSet<>();
public KrovikanVampireCreaturesDiedWatcher() {
super(KrovikanVampireCreaturesDiedWatcher.class.getSimpleName(), WatcherScope.GAME);
}
public KrovikanVampireCreaturesDiedWatcher(final KrovikanVampireCreaturesDiedWatcher watcher) {
super(watcher);
this.diedThisTurn.addAll(watcher.diedThisTurn);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.ZONE_CHANGE) {
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
if (zEvent.isDiesEvent()
&& zEvent.getTarget() != null
&& zEvent.getTarget().isCreature()) {
diedThisTurn.add(zEvent.getTargetId());
}
}
}
@Override
public void reset() {
diedThisTurn.clear();
}
public Set<UUID> getDiedThisTurn() {
return this.diedThisTurn;
}
@Override
public KrovikanVampireCreaturesDiedWatcher copy() {
return new KrovikanVampireCreaturesDiedWatcher(this);
}
}
class KrovikanVampireDelayedTriggeredAbility extends DelayedTriggeredAbility {
UUID krovikanVampire;
KrovikanVampireDelayedTriggeredAbility(Effect effect, UUID krovikanVampire) {
super(effect, Duration.EndOfGame, true);
this.krovikanVampire = krovikanVampire;
}
KrovikanVampireDelayedTriggeredAbility(KrovikanVampireDelayedTriggeredAbility ability) {
super(ability);
this.krovikanVampire = ability.krovikanVampire;
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == EventType.LOST_CONTROL
|| event.getType() == EventType.ZONE_CHANGE;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getType() == EventType.LOST_CONTROL
&& event.getSourceId().equals(krovikanVampire)) {
return true;
}
if (event.getType() == EventType.ZONE_CHANGE
&& event.getTargetId().equals(krovikanVampire)) {
return true;
}
return false;
}
@Override
public KrovikanVampireDelayedTriggeredAbility copy() {
return new KrovikanVampireDelayedTriggeredAbility(this);
}
@Override
public String getRule() {
return "LOSE CONTROL DUDE WORKS";
}
}

View file

@ -195,6 +195,7 @@ public final class IceAge extends ExpansionSet {
cards.add(new SetCardInfo("Krovikan Elementalist", 139, Rarity.UNCOMMON, mage.cards.k.KrovikanElementalist.class));
cards.add(new SetCardInfo("Krovikan Fetish", 140, Rarity.COMMON, mage.cards.k.KrovikanFetish.class));
cards.add(new SetCardInfo("Krovikan Sorcerer", 81, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class));
cards.add(new SetCardInfo("Krovikan Vampire", 29, Rarity.UNCOMMON, mage.cards.k.KrovikanVampire.class));
cards.add(new SetCardInfo("Land Cap", 357, Rarity.RARE, mage.cards.l.LandCap.class));
cards.add(new SetCardInfo("Lapis Lazuli Talisman", 327, Rarity.UNCOMMON, mage.cards.l.LapisLazuliTalisman.class));
cards.add(new SetCardInfo("Lava Tubes", 358, Rarity.RARE, mage.cards.l.LavaTubes.class));

View file

@ -147,6 +147,7 @@ public final class MastersEditionII extends ExpansionSet {
cards.add(new SetCardInfo("Krovikan Fetish", 100, Rarity.COMMON, mage.cards.k.KrovikanFetish.class));
cards.add(new SetCardInfo("Krovikan Horror", 101, Rarity.RARE, mage.cards.k.KrovikanHorror.class));
cards.add(new SetCardInfo("Krovikan Sorcerer", 51, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class));
cards.add(new SetCardInfo("Krovikan Vampire", 102, Rarity.UNCOMMON, mage.cards.k.KrovikanVampire.class));
cards.add(new SetCardInfo("Lat-Nam's Legacy", 52, Rarity.COMMON, mage.cards.l.LatNamsLegacy.class));
cards.add(new SetCardInfo("Leaping Lizard", 171, Rarity.COMMON, mage.cards.l.LeapingLizard.class));
cards.add(new SetCardInfo("Lim-Dul's High Guard", 103, Rarity.UNCOMMON, mage.cards.l.LimDulsHighGuard.class));