From 4e9d9de99f3cd800a2d71c9e7026b132ec226ede Mon Sep 17 00:00:00 2001
From: Evan Kranzler <theelk801@gmail.com>
Date: Sat, 29 Jun 2019 14:46:56 -0400
Subject: [PATCH] Implemented Bag of Holding

---
 Mage.Sets/src/mage/cards/b/BagOfHolding.java | 129 +++++++++++++++++++
 Mage.Sets/src/mage/sets/CoreSet2020.java     |   1 +
 2 files changed, 130 insertions(+)
 create mode 100644 Mage.Sets/src/mage/cards/b/BagOfHolding.java

diff --git a/Mage.Sets/src/mage/cards/b/BagOfHolding.java b/Mage.Sets/src/mage/cards/b/BagOfHolding.java
new file mode 100644
index 0000000000..133d11d508
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/b/BagOfHolding.java
@@ -0,0 +1,129 @@
+package mage.cards.b;
+
+import mage.abilities.Ability;
+import mage.abilities.TriggeredAbilityImpl;
+import mage.abilities.common.SimpleActivatedAbility;
+import mage.abilities.costs.common.SacrificeSourceCost;
+import mage.abilities.costs.common.TapSourceCost;
+import mage.abilities.costs.mana.GenericManaCost;
+import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.DrawDiscardControllerEffect;
+import mage.abilities.effects.common.ExileTargetForSourceEffect;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.CardType;
+import mage.constants.Outcome;
+import mage.constants.Zone;
+import mage.game.ExileZone;
+import mage.game.Game;
+import mage.game.events.GameEvent;
+import mage.players.Player;
+import mage.target.targetpointer.FixedTarget;
+import mage.util.CardUtil;
+
+import java.util.UUID;
+
+/**
+ * @author TheElk801
+ */
+public final class BagOfHolding extends CardImpl {
+
+    public BagOfHolding(UUID ownerId, CardSetInfo setInfo) {
+        super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}");
+
+        // Whenever you discard a card, exile that card from your graveyard.
+        this.addAbility(new BagOfHoldingTriggeredAbility());
+
+        // {2}, {T}: Draw a card, then discard a card.
+        Ability ability = new SimpleActivatedAbility(
+                new DrawDiscardControllerEffect(1, 1), new GenericManaCost(2)
+        );
+        ability.addCost(new TapSourceCost());
+        this.addAbility(ability);
+
+        // {4}, {T}, Sacrifice Bag of Holding: Return all cards exiled with Bag of Holding to their owner's hand.
+        ability = new SimpleActivatedAbility(new BagOfHoldingEffect(), new GenericManaCost(4));
+        ability.addCost(new TapSourceCost());
+        ability.addCost(new SacrificeSourceCost());
+        this.addAbility(ability);
+    }
+
+    private BagOfHolding(final BagOfHolding card) {
+        super(card);
+    }
+
+    @Override
+    public BagOfHolding copy() {
+        return new BagOfHolding(this);
+    }
+}
+
+class BagOfHoldingTriggeredAbility extends TriggeredAbilityImpl {
+
+    BagOfHoldingTriggeredAbility() {
+        super(Zone.BATTLEFIELD, null, false);
+    }
+
+    private BagOfHoldingTriggeredAbility(final BagOfHoldingTriggeredAbility ability) {
+        super(ability);
+    }
+
+    @Override
+    public BagOfHoldingTriggeredAbility copy() {
+        return new BagOfHoldingTriggeredAbility(this);
+    }
+
+    @Override
+    public boolean checkEventType(GameEvent event, Game game) {
+        return event.getType() == GameEvent.EventType.DISCARDED_CARD;
+    }
+
+    @Override
+    public boolean checkTrigger(GameEvent event, Game game) {
+        if (isControlledBy(event.getPlayerId())) {
+            this.getEffects().clear();
+            this.addEffect(
+                    new ExileTargetForSourceEffect().setTargetPointer(new FixedTarget(event.getTargetId(), game))
+            );
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public String getRule() {
+        return "Whenever you discard a card, exile that card from your graveyard.";
+    }
+}
+
+class BagOfHoldingEffect extends OneShotEffect {
+
+    BagOfHoldingEffect() {
+        super(Outcome.DrawCard);
+        this.staticText = "return all cards exiled with {this} into their owner's hand";
+    }
+
+    private BagOfHoldingEffect(final BagOfHoldingEffect effect) {
+        super(effect);
+    }
+
+    @Override
+    public BagOfHoldingEffect copy() {
+        return new BagOfHoldingEffect(this);
+    }
+
+    @Override
+    public boolean apply(Game game, Ability source) {
+        Player controller = game.getPlayer(source.getControllerId());
+        if (controller == null) {
+            return false;
+        }
+        ExileZone exileZone = game.getExile().getExileZone(
+                CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter())
+        );
+        if (exileZone == null) {
+            return true;
+        }
+        return controller.moveCards(exileZone, Zone.HAND, source, game);
+    }
+}
diff --git a/Mage.Sets/src/mage/sets/CoreSet2020.java b/Mage.Sets/src/mage/sets/CoreSet2020.java
index 3cdeec42cb..7cdaad4f86 100644
--- a/Mage.Sets/src/mage/sets/CoreSet2020.java
+++ b/Mage.Sets/src/mage/sets/CoreSet2020.java
@@ -58,6 +58,7 @@ public final class CoreSet2020 extends ExpansionSet {
         cards.add(new SetCardInfo("Apostle of Purifying Light", 6, Rarity.UNCOMMON, mage.cards.a.ApostleOfPurifyingLight.class));
         cards.add(new SetCardInfo("Atemsis, All-Seeing", 46, Rarity.RARE, mage.cards.a.AtemsisAllSeeing.class));
         cards.add(new SetCardInfo("Audacious Thief", 84, Rarity.COMMON, mage.cards.a.AudaciousThief.class));
+        cards.add(new SetCardInfo("Bag of Holding", 222, Rarity.RARE, mage.cards.b.BagOfHolding.class));
         cards.add(new SetCardInfo("Barkhide Troll", 165, Rarity.UNCOMMON, mage.cards.b.BarkhideTroll.class));
         cards.add(new SetCardInfo("Barony Vampire", 85, Rarity.COMMON, mage.cards.b.BaronyVampire.class));
         cards.add(new SetCardInfo("Battalion Foot Soldier", 7, Rarity.COMMON, mage.cards.b.BattalionFootSoldier.class));