From ff690700b76a6ee342a71c27753a22c54ea9371a Mon Sep 17 00:00:00 2001 From: L_J Date: Thu, 24 Jan 2019 22:56:59 +0100 Subject: [PATCH] Implemented Blazing Effigy, Infinite Authority, Voodoo Doll --- Mage.Sets/src/mage/cards/b/BlazingEffigy.java | 124 +++++++++++++++ .../src/mage/cards/i/InfiniteAuthority.java | 148 ++++++++++++++++++ Mage.Sets/src/mage/cards/v/VoodooDoll.java | 80 ++++++++++ Mage.Sets/src/mage/sets/Legends.java | 3 + 4 files changed, 355 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/b/BlazingEffigy.java create mode 100644 Mage.Sets/src/mage/cards/i/InfiniteAuthority.java create mode 100644 Mage.Sets/src/mage/cards/v/VoodooDoll.java diff --git a/Mage.Sets/src/mage/cards/b/BlazingEffigy.java b/Mage.Sets/src/mage/cards/b/BlazingEffigy.java new file mode 100644 index 0000000000..bc7d5800af --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlazingEffigy.java @@ -0,0 +1,124 @@ + +package mage.cards.b; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +/** + * + * @author TheElk801 & L_J + */ +public final class BlazingEffigy extends CardImpl { + + public BlazingEffigy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // When Blazing Effigy dies, it deals X damage to target creature, where X is 3 plus the amount of damage dealt to Blazing Effigy this turn by other sources named Blazing Effigy. + Ability ability = new DiesTriggeredAbility(new DamageTargetEffect(BlazingEffigyCount.instance), false); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability, new BlazingEffigyWatcher()); + } + + public BlazingEffigy(final BlazingEffigy card) { + super(card); + } + + @Override + public BlazingEffigy copy() { + return new BlazingEffigy(this); + } +} + +enum BlazingEffigyCount implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + BlazingEffigyWatcher watcher = (BlazingEffigyWatcher) game.getState().getWatchers().get(BlazingEffigyWatcher.class.getSimpleName()); + if (watcher == null) { + return 3; + } + int effigyDamage = watcher.damageDoneTo(sourceAbility.getSourceId(), sourceAbility.getSourceObjectZoneChangeCounter() - 1, game); + return CardUtil.addWithOverflowCheck(3, effigyDamage); + } + + @Override + public BlazingEffigyCount copy() { + return BlazingEffigyCount.instance; + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return "3 plus the amount of damage dealt to {this} this turn by other sources named Blazing Effigy"; + } +} + +class BlazingEffigyWatcher extends Watcher { + + public final Map damagedObjects = new HashMap<>(); + + public BlazingEffigyWatcher() { + super(BlazingEffigyWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public BlazingEffigyWatcher(final BlazingEffigyWatcher watcher) { + super(watcher); + this.damagedObjects.putAll(watcher.damagedObjects); + } + + @Override + public BlazingEffigyWatcher copy() { + return new BlazingEffigyWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.DAMAGED_CREATURE) { + if (!event.getSourceId().equals(event.getTargetId())) { + MageObjectReference damageSourceRef = new MageObjectReference(event.getSourceId(), game); + MageObjectReference damageTargetRef = new MageObjectReference(event.getTargetId(), game); + if (game.getPermanentOrLKIBattlefield(event.getSourceId()) != null && game.getPermanentOrLKIBattlefield(event.getSourceId()).getName().equals("Blazing Effigy")) { + damagedObjects.putIfAbsent(damageTargetRef, 0); + damagedObjects.compute(damageTargetRef, (k, damage) -> damage + event.getAmount()); + } + } + } + } + + @Override + public void reset() { + super.reset(); + damagedObjects.clear(); + } + + public int damageDoneTo(UUID objectId, int zoneChangeCounter, Game game) { + MageObjectReference mor = new MageObjectReference(objectId, zoneChangeCounter, game); + return damagedObjects.getOrDefault(mor, 0); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InfiniteAuthority.java b/Mage.Sets/src/mage/cards/i/InfiniteAuthority.java new file mode 100644 index 0000000000..b5155d9a87 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InfiniteAuthority.java @@ -0,0 +1,148 @@ + +package mage.cards.i; + +import java.util.Objects; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth & L_J + */ +public final class InfiniteAuthority extends CardImpl { + + public InfiniteAuthority(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}{W}{W}"); + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Whenever enchanted creature blocks or becomes blocked by a creature with toughness 3 or less, destroy the other creature at end of combat. At the beginning of the next end step, if that creature was destroyed this way, put a +1/+1 counter on the first creature. + this.addAbility(new InfiniteAuthorityTriggeredAbility()); + } + + public InfiniteAuthority(final InfiniteAuthority card) { + super(card); + } + + @Override + public InfiniteAuthority copy() { + return new InfiniteAuthority(this); + } +} + +class InfiniteAuthorityTriggeredAbility extends TriggeredAbilityImpl { + + InfiniteAuthorityTriggeredAbility() { + super(Zone.BATTLEFIELD, new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(new InfiniteAuthorityEffect()))); + } + + InfiniteAuthorityTriggeredAbility(final InfiniteAuthorityTriggeredAbility ability) { + super(ability); + } + + @Override + public InfiniteAuthorityTriggeredAbility copy() { + return new InfiniteAuthorityTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.BLOCKER_DECLARED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent aura = game.getPermanentOrLKIBattlefield(sourceId); + if (aura != null) { + Permanent enchantedCreature = game.getPermanentOrLKIBattlefield(aura.getAttachedTo()); + if (enchantedCreature != null) { + Permanent blocker = game.getPermanent(event.getSourceId()); + Permanent blocked = game.getPermanent(event.getTargetId()); + Effect effect = this.getEffects().get(0); + if (blocker != null + && Objects.equals(blocked, enchantedCreature) + && blocker.getToughness().getValue() <= 3) { + effect.setTargetPointer(new FixedTarget(blocker.getId())); + return true; + } + if (blocked != null + && Objects.equals(blocker, enchantedCreature) + && blocked.getToughness().getValue() <= 3) { + effect.setTargetPointer(new FixedTarget(blocked.getId())); + return true; + } + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever enchanted creature blocks or becomes blocked by a creature with toughness 3 or less, " + super.getRule(); + } +} + +class InfiniteAuthorityEffect extends OneShotEffect { + + InfiniteAuthorityEffect() { + super(Outcome.Detriment); + staticText = "destroy the other creature at end of combat. At the beginning of the next end step, if that creature was destroyed this way, put a +1/+1 counter on the first creature"; + } + + InfiniteAuthorityEffect(final InfiniteAuthorityEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent aura = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (aura != null) { + Permanent enchantedCreature = game.getPermanentOrLKIBattlefield(aura.getAttachedTo()); + if (enchantedCreature != null) { + Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + if (permanent != null) { + if (permanent.destroy(source.getSourceId(), game, false)) { + AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(enchantedCreature, game)); + game.addDelayedTriggeredAbility(delayedAbility, source); + } + return true; + } + } + } + return false; + } + + @Override + public InfiniteAuthorityEffect copy() { + return new InfiniteAuthorityEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VoodooDoll.java b/Mage.Sets/src/mage/cards/v/VoodooDoll.java new file mode 100644 index 0000000000..b1828f6a0b --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VoodooDoll.java @@ -0,0 +1,80 @@ + +package mage.cards.v; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.SourceTappedCondition; +import mage.abilities.costs.VariableCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.VariableManaCost; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DestroySourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetAnyTarget; + +/** + * + * @author L_J + */ +public final class VoodooDoll extends CardImpl { + + public VoodooDoll(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{6}"); + + // At the beginning of your upkeep, put a pin counter on Voodoo Doll. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.PIN.createInstance()), TargetController.YOU, false)); + // At the beginning of your end step, if Voodoo Doll is untapped, destroy Voodoo Doll and it deals damage to you equal to the number of pin counters on it. + Ability ability = new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, new DestroySourceEffect(), TargetController.YOU, + new InvertCondition(SourceTappedCondition.instance), false); + ability.addEffect(new DamageControllerEffect(new CountersSourceCount(CounterType.PIN))); + this.addAbility(ability); + // {X}{X}, {T}: Voodoo Doll deals damage equal to the number of pin counters on it to any target. X is the number of pin counters on Voodoo Doll. + Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new CountersSourceCount(CounterType.PIN)), new ManaCostsImpl("{X}{X}")); + ability2.addCost(new TapSourceCost()); + ability2.addTarget(new TargetAnyTarget()); + for (VariableCost cost : ability2.getManaCosts().getVariableCosts()) { + if (cost instanceof VariableManaCost) { + ((VariableManaCost) cost).setMaxX(0); + break; + } + } + this.addAbility(ability2); + } + + @Override + public void adjustCosts(Ability ability, Game game) { + if (ability instanceof SimpleActivatedAbility) { + Permanent sourcePermanent = game.getPermanent(ability.getSourceId()); + if (sourcePermanent != null) { + int pin = sourcePermanent.getCounters(game).getCount(CounterType.PIN); + ability.getManaCostsToPay().clear(); + ability.getManaCostsToPay().add(0, new GenericManaCost(pin * 2)); + } + } + } + + public VoodooDoll(final VoodooDoll card) { + super(card); + } + + @Override + public VoodooDoll copy() { + return new VoodooDoll(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Legends.java b/Mage.Sets/src/mage/sets/Legends.java index 44a5d2d450..87857da7c8 100644 --- a/Mage.Sets/src/mage/sets/Legends.java +++ b/Mage.Sets/src/mage/sets/Legends.java @@ -54,6 +54,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Bartel Runeaxe", 222, Rarity.RARE, mage.cards.b.BartelRuneaxe.class)); cards.add(new SetCardInfo("Beasts of Bogardan", 133, Rarity.UNCOMMON, mage.cards.b.BeastsOfBogardan.class)); cards.add(new SetCardInfo("Black Mana Battery", 274, Rarity.UNCOMMON, mage.cards.b.BlackManaBattery.class)); + cards.add(new SetCardInfo("Blazing Effigy", 134, Rarity.COMMON, mage.cards.b.BlazingEffigy.class)); cards.add(new SetCardInfo("Blight", 89, Rarity.UNCOMMON, mage.cards.b.Blight.class)); cards.add(new SetCardInfo("Blood Lust", 135, Rarity.UNCOMMON, mage.cards.b.BloodLust.class)); cards.add(new SetCardInfo("Blue Mana Battery", 275, Rarity.UNCOMMON, mage.cards.b.BlueManaBattery.class)); @@ -152,6 +153,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("In the Eye of Chaos", 61, Rarity.RARE, mage.cards.i.InTheEyeOfChaos.class)); cards.add(new SetCardInfo("Indestructible Aura", 21, Rarity.COMMON, mage.cards.i.IndestructibleAura.class)); cards.add(new SetCardInfo("Infernal Medusa", 108, Rarity.UNCOMMON, mage.cards.i.InfernalMedusa.class)); + cards.add(new SetCardInfo("Infinite Authority", 22, Rarity.RARE, mage.cards.i.InfiniteAuthority.class)); cards.add(new SetCardInfo("Invoke Prejudice", 62, Rarity.RARE, mage.cards.i.InvokePrejudice.class)); cards.add(new SetCardInfo("Ivory Guardians", 23, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class)); cards.add(new SetCardInfo("Jacques le Vert", 232, Rarity.RARE, mage.cards.j.JacquesLeVert.class)); @@ -299,6 +301,7 @@ public final class Legends extends ExpansionSet { cards.add(new SetCardInfo("Vaevictis Asmadi", 269, Rarity.RARE, mage.cards.v.VaevictisAsmadi.class)); cards.add(new SetCardInfo("Vampire Bats", 125, Rarity.COMMON, mage.cards.v.VampireBats.class)); cards.add(new SetCardInfo("Visions", 41, Rarity.UNCOMMON, mage.cards.v.Visions.class)); + cards.add(new SetCardInfo("Voodoo Doll", 298, Rarity.RARE, mage.cards.v.VoodooDoll.class)); cards.add(new SetCardInfo("Walking Dead", 126, Rarity.COMMON, mage.cards.w.WalkingDead.class)); cards.add(new SetCardInfo("Wall of Caltrops", 42, Rarity.COMMON, mage.cards.w.WallOfCaltrops.class)); cards.add(new SetCardInfo("Wall of Dust", 168, Rarity.UNCOMMON, mage.cards.w.WallOfDust.class));