From 096f2c0e51dde4558befc343b27d6eaa97f747f1 Mon Sep 17 00:00:00 2001 From: Mathieu Pouedras Date: Wed, 3 Jan 2018 12:12:19 +0100 Subject: [PATCH 1/2] Implements Brood of Cockroaches --- .../src/mage/cards/b/BroodOfCockroaches.java | 110 ++++++++++++++++++ Mage.Sets/src/mage/sets/Visions.java | 1 + .../single/vis/BroodOfCockroachesTest.java | 104 +++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/b/BroodOfCockroaches.java create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/vis/BroodOfCockroachesTest.java diff --git a/Mage.Sets/src/mage/cards/b/BroodOfCockroaches.java b/Mage.Sets/src/mage/cards/b/BroodOfCockroaches.java new file mode 100644 index 0000000000..0c9d652ca6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BroodOfCockroaches.java @@ -0,0 +1,110 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.Game; +import mage.target.targetpointer.FixedTarget; + +import static mage.constants.Outcome.Benefit; + +/** + * + * @author mpouedras + */ +public class BroodOfCockroaches extends CardImpl { + + public BroodOfCockroaches(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.INSECT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When Brood of Cockroaches is put into your graveyard from the battlefield, + // at the beginning of the next end step, + // you lose 1 life + // and return Brood of Cockroaches to your hand. + this.addAbility(new DiesTriggeredAbility(new BroodOfCockroachesEffect())); + } + + public BroodOfCockroaches(final BroodOfCockroaches card) { + super(card); + } + + @Override + public BroodOfCockroaches copy() { + return new BroodOfCockroaches(this); + } +} + +class BroodOfCockroachesEffect extends OneShotEffect { + private static final String effectText = "at the beginning of the next end step, you lose 1 life and return Brood of Cockroaches to your hand."; + + BroodOfCockroachesEffect() { + super(Benefit); + staticText = effectText; + } + + BroodOfCockroachesEffect(BroodOfCockroachesEffect broodOfCockroachesEffect) { + super(broodOfCockroachesEffect); + } + + @Override + public boolean apply(Game game, Ability source) { + AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedLifeLost = + new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new LoseLifeSourceControllerEffect(1)); + game.addDelayedTriggeredAbility(delayedLifeLost, source); + + Effect effect = new ReturnToHandTargetEffect(); + effect.setText("return Brood of Cockroaches to your hand."); + effect.setTargetPointer(new FixedTarget(source.getSourceId(), source.getSourceObjectZoneChangeCounter())); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); + game.addDelayedTriggeredAbility(delayedAbility, source); + + return true; + } + + @Override + public Effect copy() { + return new BroodOfCockroachesEffect(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/Visions.java b/Mage.Sets/src/mage/sets/Visions.java index 92817270e9..b537d3b33d 100644 --- a/Mage.Sets/src/mage/sets/Visions.java +++ b/Mage.Sets/src/mage/sets/Visions.java @@ -63,6 +63,7 @@ public class Visions extends ExpansionSet { cards.add(new SetCardInfo("Brass-Talon Chimera", 142, Rarity.UNCOMMON, mage.cards.b.BrassTalonChimera.class)); cards.add(new SetCardInfo("Breathstealer's Crypt", 127, Rarity.RARE, mage.cards.b.BreathstealersCrypt.class)); cards.add(new SetCardInfo("Breezekeeper", 27, Rarity.COMMON, mage.cards.b.Breezekeeper.class)); + cards.add(new SetCardInfo("Brood of Cockroaches", 3, Rarity.UNCOMMON, mage.cards.b.BroodOfCockroaches.class)); cards.add(new SetCardInfo("Bull Elephant", 51, Rarity.COMMON, mage.cards.b.BullElephant.class)); cards.add(new SetCardInfo("Chronatog", 28, Rarity.RARE, mage.cards.c.Chronatog.class)); cards.add(new SetCardInfo("City of Solitude", 52, Rarity.RARE, mage.cards.c.CityOfSolitude.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/vis/BroodOfCockroachesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/vis/BroodOfCockroachesTest.java new file mode 100644 index 0000000000..d4133f297a --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/vis/BroodOfCockroachesTest.java @@ -0,0 +1,104 @@ +package org.mage.test.cards.single.vis; + +import mage.game.permanent.Permanent; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.*; + +import static mage.constants.Zone.*; +import static mage.constants.PhaseStep.*; + +public class BroodOfCockroachesTest extends CardTestPlayerBase { + + private static final int TURN_1 = 1; + private static final int ANY_LIFE_TOTAL = 17; + private static final String BROOD_OF_COCKROACHES = "Brood of Cockroaches"; + private static final String SHOCK = "Shock"; + + @Test + public void should_display_correct_text() { + String expectedText = "When {this} dies, at the beginning of the next end step, you lose 1 life and return Brood of Cockroaches to your hand."; + + playerA_casts_Brood_of_Cockroaches_at_precombat_main_phase(); + + setStopAt(TURN_1, END_TURN); + execute(); + + Permanent permanent = getPermanent(BROOD_OF_COCKROACHES, playerA); + assertThat(permanent.getAbilities().get(1).toString(), is(expectedText)); + + } + + @Test + public void should_reduce_life_of_playerA_by_1_at_the_beginning_of_the_next_end_step() { + playerA.setLife(ANY_LIFE_TOTAL, currentGame); + + playerA_casts_Brood_of_Cockroaches_at_precombat_main_phase(); + + brood_of_cockroaches_diesat_precombat_main_phase(); + + setStopAt(TURN_1, END_TURN); + execute(); + + assertLife(playerA, ANY_LIFE_TOTAL - 1); + } + + @Test + public void should_not_reduce_life_of_playerA_by_1_at_post_combat_main_step() { + playerA.setLife(ANY_LIFE_TOTAL, currentGame); + + playerA_casts_Brood_of_Cockroaches_at_precombat_main_phase(); + + brood_of_cockroaches_diesat_precombat_main_phase(); + + setStopAt(TURN_1, PRECOMBAT_MAIN); + execute(); + + assertLife(playerA, ANY_LIFE_TOTAL ); + } + + @Test + public void should_return_Brood_of_Cockroaches_to_playerA_hand_end_of_turn() { + playerA.setLife(ANY_LIFE_TOTAL, currentGame); + + playerA_casts_Brood_of_Cockroaches_at_precombat_main_phase(); + + brood_of_cockroaches_diesat_precombat_main_phase(); + + setStopAt(TURN_1, END_TURN); + execute(); + + assertHandCount(playerA, BROOD_OF_COCKROACHES, 1); + } + + @Test + public void should_not_return_Brood_of_Cockroaches_to_playerA_at_post_combat_step() { + playerA.setLife(ANY_LIFE_TOTAL, currentGame); + + playerA_casts_Brood_of_Cockroaches_at_precombat_main_phase(); + + brood_of_cockroaches_diesat_precombat_main_phase(); + + setStopAt(TURN_1, POSTCOMBAT_MAIN); + execute(); + + assertHandCount(playerA, BROOD_OF_COCKROACHES, 0); + } + + + private void brood_of_cockroaches_diesat_precombat_main_phase() { + addCard(BATTLEFIELD, playerB, "Mountain", 1); + addCard(HAND, playerB, SHOCK, 1); + castSpell(TURN_1, PRECOMBAT_MAIN, playerB, SHOCK, BROOD_OF_COCKROACHES); + } + + private void playerA_casts_Brood_of_Cockroaches_at_precombat_main_phase() { + addCard(BATTLEFIELD, playerA, "Swamp", 2); + addCard(HAND, playerA, BROOD_OF_COCKROACHES, 1); + castSpell(TURN_1, PRECOMBAT_MAIN, playerA, BROOD_OF_COCKROACHES); + } + + +} From 0fe65e99fa8a8c8a1ffe8fbca750c2d21475f1a3 Mon Sep 17 00:00:00 2001 From: Mathieu Pouedras Date: Mon, 8 Jan 2018 12:04:56 +0100 Subject: [PATCH 2/2] replace the name of the card with {this} for effect text --- Mage.Sets/src/mage/cards/b/BroodOfCockroaches.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/b/BroodOfCockroaches.java b/Mage.Sets/src/mage/cards/b/BroodOfCockroaches.java index 0c9d652ca6..e1320b457b 100644 --- a/Mage.Sets/src/mage/cards/b/BroodOfCockroaches.java +++ b/Mage.Sets/src/mage/cards/b/BroodOfCockroaches.java @@ -95,7 +95,7 @@ class BroodOfCockroachesEffect extends OneShotEffect { game.addDelayedTriggeredAbility(delayedLifeLost, source); Effect effect = new ReturnToHandTargetEffect(); - effect.setText("return Brood of Cockroaches to your hand."); + effect.setText("return {this} to your hand."); effect.setTargetPointer(new FixedTarget(source.getSourceId(), source.getSourceObjectZoneChangeCounter())); DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); game.addDelayedTriggeredAbility(delayedAbility, source);