From 02625442b1159a4069db4cb9392b35ed9b914c07 Mon Sep 17 00:00:00 2001 From: Alexsandro Date: Sun, 8 Jan 2017 11:11:31 -0200 Subject: [PATCH 01/44] Add Muraganda Petroglyphs --- .../mage/cards/m/MuragandaPetroglyphs.java | 69 +++++++++++++++++++ Mage.Sets/src/mage/sets/FutureSight.java | 1 + .../main/java/mage/cards/ExpansionSet.java | 2 +- .../mageobject/NoAbilityPredicate.java | 36 ++++++++++ 4 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java create mode 100644 Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java diff --git a/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java b/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java new file mode 100644 index 00000000000..d7731449c28 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java @@ -0,0 +1,69 @@ +/* + * 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.m; + +import java.util.UUID; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.NoAbilityPredicate; + +/** + * + * @author anonymous + */ +public class MuragandaPetroglyphs extends CardImpl { + + private static final FilterCreaturePermanent filterNoAbilities = new FilterCreaturePermanent( + "Creatures with no ability"); + + public MuragandaPetroglyphs(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT},"{3}{G}"); + this.expansionSetCode = "FUT"; + + filterNoAbilities.add(new NoAbilityPredicate()); + // Creatures with no abilities get +2/+2. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect( + 2, 2, Duration.WhileOnBattlefield, filterNoAbilities, false))); + } + + public MuragandaPetroglyphs(final MuragandaPetroglyphs card) { + super(card); + } + + @Override + public MuragandaPetroglyphs copy() { + return new MuragandaPetroglyphs(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/FutureSight.java b/Mage.Sets/src/mage/sets/FutureSight.java index fc74fe637e9..6a06a53d501 100644 --- a/Mage.Sets/src/mage/sets/FutureSight.java +++ b/Mage.Sets/src/mage/sets/FutureSight.java @@ -146,6 +146,7 @@ public class FutureSight extends ExpansionSet { cards.add(new SetCardInfo("Minions' Murmurs", 71, Rarity.UNCOMMON, mage.cards.m.MinionsMurmurs.class)); cards.add(new SetCardInfo("Mistmeadow Skulk", 27, Rarity.UNCOMMON, mage.cards.m.MistmeadowSkulk.class)); cards.add(new SetCardInfo("Molten Disaster", 102, Rarity.RARE, mage.cards.m.MoltenDisaster.class)); + cards.add(new SetCardInfo("Muraganda Petroglyphs", 146, Rarity.RARE, mage.cards.m.MuragandaPetroglyphs.class)); cards.add(new SetCardInfo("Mystic Speculation", 41, Rarity.UNCOMMON, mage.cards.m.MysticSpeculation.class)); cards.add(new SetCardInfo("Nacatl War-Pride", 147, Rarity.UNCOMMON, mage.cards.n.NacatlWarPride.class)); cards.add(new SetCardInfo("Narcomoeba", 54, Rarity.UNCOMMON, mage.cards.n.Narcomoeba.class)); diff --git a/Mage/src/main/java/mage/cards/ExpansionSet.java b/Mage/src/main/java/mage/cards/ExpansionSet.java index 24e3d35dc23..99fe4aa8a3f 100644 --- a/Mage/src/main/java/mage/cards/ExpansionSet.java +++ b/Mage/src/main/java/mage/cards/ExpansionSet.java @@ -46,7 +46,7 @@ import mage.util.RandomUtil; */ public abstract class ExpansionSet implements Serializable { - public class SetCardInfo implements Serializable { + public static class SetCardInfo implements Serializable { private final String name; private final String cardNumber; diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java new file mode 100644 index 00000000000..52ab89f35cd --- /dev/null +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java @@ -0,0 +1,36 @@ +package mage.filter.predicate.mageobject; + +import mage.MageObject; +import mage.abilities.Abilities; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.cards.Card; +import mage.filter.predicate.Predicate; +import mage.game.Game; + +/** + * Created by Alexsandro. + */ +public class NoAbilityPredicate implements Predicate { + @Override + public boolean apply(MageObject input, Game game) { + Abilities abilities; + if (input instanceof Card){ + abilities = ((Card)input).getAbilities(game); + } else { + abilities = input.getAbilities(); + } + + for (Ability a : abilities){ + if (a.getClass() != SpellAbility.class){ + return false; + } + } + return true; + } + + @Override + public String toString() { + return "with no abilities"; + } +} \ No newline at end of file From 3033dfecc4c5669c364827f91bd2030947ef5c21 Mon Sep 17 00:00:00 2001 From: Alexsandro Date: Sun, 8 Jan 2017 15:18:02 -0200 Subject: [PATCH 02/44] Add tests based on gatherer --- .../single/fut/MuragandaPetroglyphsTest.java | 185 ++++++++++++++++++ .../mageobject/NoAbilityPredicate.java | 18 +- 2 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java new file mode 100644 index 00000000000..f7ef102d666 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java @@ -0,0 +1,185 @@ +package org.mage.test.cards.single.fut; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.filter.Filter; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * This test is based on rulings of the card Muraganda Petroglyphs in magic Gatherer site + * (http://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=145110), accessed in + * 08/01/2017. + * + * @author alexsandro. + */ +public class MuragandaPetroglyphsTest extends CardTestPlayerBase { + + + /** + * Muraganda Petroglyphs gives a bonus only to creatures that have no rules text at all. + * This includes true vanilla creatures (such as Grizzly Bears), face-down creatures, + * many tokens, and creatures that have lost their abilities (due to Ovinize, for example). + * Any ability of any kind, whether or not the ability functions in the on the battlefield zone, + * including things like “Cycling 2” means the creature doesn’t get the bonus. + */ + @Test + public void trueVanillaCardsTest() { + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1); + addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 1); + + addCard(Zone.BATTLEFIELD, playerA, "Muraganda Petroglyphs", 1); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPowerToughness(playerA, "Grizzly Bears", 4, 4, Filter.ComparisonScope.Any); + assertPowerToughness(playerB, "Grizzly Bears", 4, 4, Filter.ComparisonScope.Any); + + } + + @Test + public void faceDownCreaturesTest() { + addCard(Zone.HAND, playerA, "Pine Walker"); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 3); + addCard(Zone.BATTLEFIELD, playerA, "Muraganda Petroglyphs", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pine Walker"); + setChoice(playerA, "Yes"); // cast it face down as 2/2 creature + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "", 1); + assertPowerToughness(playerA, "", 4, 4); + } + + @Test + public void faceDownGainedAbilityTest() { + addCard(Zone.HAND, playerA, "Pine Walker"); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mass Hysteria"); // All creatures have haste. + + addCard(Zone.BATTLEFIELD, playerA, "Muraganda Petroglyphs", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pine Walker"); + setChoice(playerA, "Yes"); // cast it face down as 2/2 creature + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "", 1); + assertPowerToughness(playerA, "", 2, 2); + } + + @Test + public void tokenTest() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.BATTLEFIELD, playerA, "Muraganda Petroglyphs", 1); + // Put two 1/1 white Soldier creature tokens onto the battlefield. + addCard(Zone.HAND, playerA, "Raise the Alarm"); // Instant {1}{W} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Raise the Alarm"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPowerToughness(playerA, "Soldier", 3, 3); + } + + @Test + public void loseAbilitiesTest() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerB, "Goblin Guide", 1); + addCard(Zone.BATTLEFIELD, playerA, "Muraganda Petroglyphs", 1); + + addCard(Zone.HAND, playerA, "Ovinize"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ovinize", "Goblin Guide"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPowerToughness(playerB, "Goblin Guide", 2, 3); + } + + @Test + public void CyclingAbilityTest() { + addCard(Zone.BATTLEFIELD, playerA, "Hundroog", 1); // Cycling {3}, 4/7 + addCard(Zone.BATTLEFIELD, playerA, "Muraganda Petroglyphs", 1); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPowerToughness(playerA, "Hundroog", 4, 7); + } + + /** + * Animated basic lands have mana abilities, so they won’t get the bonus. + */ + + @Test + public void animateBasicLandTest() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); + addCard(Zone.BATTLEFIELD, playerA, "Muraganda Petroglyphs", 1); + addCard(Zone.HAND, playerA, "Vastwood Zendikon"); + + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vastwood Zendikon", "Forest"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPowerToughness(playerA, "Forest", 6, 4); + + } + + /** + * Some Auras and Equipment grant abilities to creatures, meaning the affected creature would no longer + * get the +2/+2 bonus. For example, Flight grants flying to the enchanted creature. Other Auras and Equipment + * do not, meaning the affected creature would continue to get the +2/+2 bonus. For example, Dehydration states + * something now true about the enchanted creature, but doesn’t give it any abilities. Auras and Equipment that + * grant abilities will use the words “gains” or “has,” and they’ll list a keyword ability or an ability in + * quotation marks. + */ + @Test + public void grantAbilitiesTest() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.BATTLEFIELD, playerA, "Muraganda Petroglyphs", 1); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1); + addCard(Zone.BATTLEFIELD, playerA, "Runeclaw Bear", 1); + // Enchanted creature gets +2/+0 and has trample. + addCard(Zone.HAND, playerA, "Rancor"); + // Enchanted creature doesn't untap during itscontroller's untap step. + addCard(Zone.HAND, playerA, "Dehydration"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA,"Rancor", "Grizzly Bears"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Dehydration", "Runeclaw Bear"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPowerToughness(playerA, "Grizzly Bears", 4, 2); + + assertPowerToughness(playerA, "Runeclaw Bear", 4, 4); + + } + + /** + * Cipher grants an ability to creatures, meaning the affected creatures would no longer get the +2/+2 bonus. + */ +// TODO See how to set the cipher ability in tests +// public void cipherTest() { +// addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6); +// addCard(Zone.BATTLEFIELD, playerA, "Muraganda Petroglyphs", 1); +// addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1); +// +// addCard(Zone.HAND, playerA, "Shadow Slice"); // {4}{B} +// castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shadow Slice"); +// +// +// } +} diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java index 52ab89f35cd..ad20b77f474 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java @@ -4,6 +4,7 @@ import mage.MageObject; import mage.abilities.Abilities; import mage.abilities.Ability; import mage.abilities.SpellAbility; +import mage.abilities.keyword.MorphAbility; import mage.cards.Card; import mage.filter.predicate.Predicate; import mage.game.Game; @@ -12,17 +13,30 @@ import mage.game.Game; * Created by Alexsandro. */ public class NoAbilityPredicate implements Predicate { + @Override public boolean apply(MageObject input, Game game) { + boolean isFaceDown = false; Abilities abilities; if (input instanceof Card){ abilities = ((Card)input).getAbilities(game); + + isFaceDown = ((Card)input).isFaceDown(game); } else { abilities = input.getAbilities(); } + if (isFaceDown) { + for (Ability ability : abilities){ + if(ability.getSourceId() != input.getId()) { + return false; + } + } + return true; + } + + for (Ability ability : abilities){ + if (ability.getClass() != SpellAbility.class){ - for (Ability a : abilities){ - if (a.getClass() != SpellAbility.class){ return false; } } From 47b96e5411a039533cd13f6a27635d9bbfa401ed Mon Sep 17 00:00:00 2001 From: Alexsandro Date: Tue, 10 Jan 2017 11:17:09 -0200 Subject: [PATCH 03/44] Remove static placed by IDE --- Mage/src/main/java/mage/cards/ExpansionSet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage/src/main/java/mage/cards/ExpansionSet.java b/Mage/src/main/java/mage/cards/ExpansionSet.java index 99fe4aa8a3f..24e3d35dc23 100644 --- a/Mage/src/main/java/mage/cards/ExpansionSet.java +++ b/Mage/src/main/java/mage/cards/ExpansionSet.java @@ -46,7 +46,7 @@ import mage.util.RandomUtil; */ public abstract class ExpansionSet implements Serializable { - public static class SetCardInfo implements Serializable { + public class SetCardInfo implements Serializable { private final String name; private final String cardNumber; From 92cfe2403e61e5167eb4169be5a64ef4304ace1e Mon Sep 17 00:00:00 2001 From: Alexsandro Date: Tue, 10 Jan 2017 11:40:04 -0200 Subject: [PATCH 04/44] Create cipher test for Muraganda Petroglyphs --- .../single/fut/MuragandaPetroglyphsTest.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java index f7ef102d666..c8263589cbb 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java @@ -171,15 +171,19 @@ public class MuragandaPetroglyphsTest extends CardTestPlayerBase { /** * Cipher grants an ability to creatures, meaning the affected creatures would no longer get the +2/+2 bonus. */ -// TODO See how to set the cipher ability in tests -// public void cipherTest() { -// addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6); -// addCard(Zone.BATTLEFIELD, playerA, "Muraganda Petroglyphs", 1); -// addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1); -// -// addCard(Zone.HAND, playerA, "Shadow Slice"); // {4}{B} -// castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shadow Slice"); -// -// -// } + @Test + public void cipherTest() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6); + addCard(Zone.BATTLEFIELD, playerA, "Muraganda Petroglyphs", 1); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1); + + addCard(Zone.HAND, playerA, "Shadow Slice"); // {4}{B} + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shadow Slice"); + setChoice(playerA, "Grizzly Bears"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPowerToughness(playerA, "Grizzly Bears", 2, 2); + } } From 0a0878aba6edf4ebbb8c7d7ed9dd2e93d6a2b92f Mon Sep 17 00:00:00 2001 From: Alexsandro Date: Tue, 10 Jan 2017 12:37:15 -0200 Subject: [PATCH 05/44] Create Hivestone card --- Mage.Sets/src/mage/cards/h/Hivestone.java | 71 +++++++++++++++++++++++ Mage.Sets/src/mage/sets/TimeSpiral.java | 1 + 2 files changed, 72 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/h/Hivestone.java diff --git a/Mage.Sets/src/mage/cards/h/Hivestone.java b/Mage.Sets/src/mage/cards/h/Hivestone.java new file mode 100644 index 00000000000..da2f346c156 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/Hivestone.java @@ -0,0 +1,71 @@ +package mage.cards.h; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.List; +import java.util.UUID; + +/** + * Created by Alexsandr0x. + */ +public class Hivestone extends CardImpl { + + public Hivestone(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // Creatures you control are Slivers in addition to their other creature types. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CreaturesAreSliversEffect())); + } + + public Hivestone(final Hivestone card) { + super(card); + } + + @Override + public Card copy() { + return new Hivestone(this); + } + +} + +class CreaturesAreSliversEffect extends ContinuousEffectImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + + public CreaturesAreSliversEffect() { + + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Neutral); + staticText = "All permanents are artifacts in addition to their other types"; + } + + @Override + public boolean apply(Game game, Ability source) { + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game); + for (Permanent perm : permanents) { + List cardSubType = perm.getSubtype(game); + if (!cardSubType.contains("Sliver")) { + cardSubType.add("Sliver"); + } + } + return true; + } + + @Override + public mage.cards.h.CreaturesAreSliversEffect copy() { + return new mage.cards.h.CreaturesAreSliversEffect(this); + } + + private CreaturesAreSliversEffect(mage.cards.h.CreaturesAreSliversEffect effect) { + super(effect); + } +} diff --git a/Mage.Sets/src/mage/sets/TimeSpiral.java b/Mage.Sets/src/mage/sets/TimeSpiral.java index b3c01a8ad82..f943f5cb345 100644 --- a/Mage.Sets/src/mage/sets/TimeSpiral.java +++ b/Mage.Sets/src/mage/sets/TimeSpiral.java @@ -130,6 +130,7 @@ public class TimeSpiral extends ExpansionSet { cards.add(new SetCardInfo("Haunting Hymn", 112, Rarity.UNCOMMON, mage.cards.h.HauntingHymn.class)); cards.add(new SetCardInfo("Havenwood Wurm", 199, Rarity.COMMON, mage.cards.h.HavenwoodWurm.class)); cards.add(new SetCardInfo("Herd Gnarr", 200, Rarity.COMMON, mage.cards.h.HerdGnarr.class)); + cards.add(new SetCardInfo("Hivestone", 256, Rarity.RARE, mage.cards.h.Hivestone.class)); cards.add(new SetCardInfo("Hypergenesis", 201, Rarity.RARE, mage.cards.h.Hypergenesis.class)); cards.add(new SetCardInfo("Ib Halfheart, Goblin Tactician", 163, Rarity.RARE, mage.cards.i.IbHalfheartGoblinTactician.class)); cards.add(new SetCardInfo("Icatian Crier", 23, Rarity.COMMON, mage.cards.i.IcatianCrier.class)); From 81954b92ea3ea0ac2df014cfe6fc5a3989026813 Mon Sep 17 00:00:00 2001 From: Alexsandro Date: Tue, 10 Jan 2017 12:47:50 -0200 Subject: [PATCH 06/44] Change card text --- Mage.Sets/src/mage/cards/h/Hivestone.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/cards/h/Hivestone.java b/Mage.Sets/src/mage/cards/h/Hivestone.java index da2f346c156..badf162e41e 100644 --- a/Mage.Sets/src/mage/cards/h/Hivestone.java +++ b/Mage.Sets/src/mage/cards/h/Hivestone.java @@ -43,9 +43,8 @@ class CreaturesAreSliversEffect extends ContinuousEffectImpl { public CreaturesAreSliversEffect() { - super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Neutral); - staticText = "All permanents are artifacts in addition to their other types"; + staticText = "Creatures you control are Slivers in addition to their other creature types."; } @Override From 4bf2137e9d1b754ad22cd72e1e08c53df4b9b59e Mon Sep 17 00:00:00 2001 From: Alexsandro Date: Tue, 10 Jan 2017 12:56:39 -0200 Subject: [PATCH 07/44] Add hivestone test structure --- .../test/cards/single/tsp/HivestoneTest.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/HivestoneTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/HivestoneTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/HivestoneTest.java new file mode 100644 index 00000000000..94db7d00adf --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/HivestoneTest.java @@ -0,0 +1,31 @@ +package org.mage.test.cards.single.tsp; + +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * Created by Alexsandr0x. + */ + + +public class HivestoneTest extends CardTestPlayerBase { + + /** + * If a creature is already a Sliver, Hivestone has no effect on it. + */ + @Test + public void abilityCheckTest() { + // Coloca criatura qualquer em campo, uma no player A e outra no player B, checa se + // receberam o subtipo + } + + /** + * Turns only your creatures on the battlefield, not in other zones, into Slivers. It won’t allow you to have + * Root Sliver on the battlefield and make your Grizzly Bears uncounterable, for example. + */ + @Test + public void rootSliverTest() { + // com o root sliver e a hivestone em campo, tenta counterar uma carta que não é sliver vinda + // da mão (tem que funcionar, ja que a carta não é sliver na stack) + } +} From 1d91e04ac12d32c6b86f2e3a95d0d5c2882c332f Mon Sep 17 00:00:00 2001 From: Alexsandro Date: Wed, 11 Jan 2017 14:08:34 -0200 Subject: [PATCH 08/44] Add Hivestone tests --- Mage.Sets/src/mage/cards/h/Hivestone.java | 4 +- .../test/cards/single/tsp/HivestoneTest.java | 41 ++++++++++++++++--- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/Mage.Sets/src/mage/cards/h/Hivestone.java b/Mage.Sets/src/mage/cards/h/Hivestone.java index badf162e41e..a159823ef56 100644 --- a/Mage.Sets/src/mage/cards/h/Hivestone.java +++ b/Mage.Sets/src/mage/cards/h/Hivestone.java @@ -10,6 +10,7 @@ import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; import java.util.List; import java.util.UUID; @@ -49,10 +50,11 @@ class CreaturesAreSliversEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game); for (Permanent perm : permanents) { List cardSubType = perm.getSubtype(game); - if (!cardSubType.contains("Sliver")) { + if (!cardSubType.contains("Sliver") && perm.getOwnerId() == player.getId()) { cardSubType.add("Sliver"); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/HivestoneTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/HivestoneTest.java index 94db7d00adf..945e1848111 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/HivestoneTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/HivestoneTest.java @@ -1,13 +1,14 @@ package org.mage.test.cards.single.tsp; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.filter.Filter; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** * Created by Alexsandr0x. */ - - public class HivestoneTest extends CardTestPlayerBase { /** @@ -15,8 +16,21 @@ public class HivestoneTest extends CardTestPlayerBase { */ @Test public void abilityCheckTest() { - // Coloca criatura qualquer em campo, uma no player A e outra no player B, checa se - // receberam o subtipo + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 1); + addCard(Zone.BATTLEFIELD, playerA, "Hivestone", 1); + + addCard(Zone.BATTLEFIELD, playerA, "Muscle Sliver", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Runeclaw Bear", 1); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPowerToughness(playerA, "Grizzly Bears", 3, 3, Filter.ComparisonScope.Any); + + assertPowerToughness(playerB, "Runeclaw Bear", 2, 2, Filter.ComparisonScope.Any); + + } /** @@ -25,7 +39,22 @@ public class HivestoneTest extends CardTestPlayerBase { */ @Test public void rootSliverTest() { - // com o root sliver e a hivestone em campo, tenta counterar uma carta que não é sliver vinda - // da mão (tem que funcionar, ja que a carta não é sliver na stack) + addCard(Zone.HAND, playerA, "Grizzly Bears", 1); + addCard(Zone.BATTLEFIELD, playerA, "Hivestone", 1); + // Root Sliver can't be countered. Sliver spells can't be countered by spells or abilities. + addCard(Zone.BATTLEFIELD, playerA, "Root Sliver", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + + + addCard(Zone.BATTLEFIELD, playerB, "Island", 2); + addCard(Zone.HAND, playerB, "Counterspell"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Counterspell", "Grizzly Bears", "Grizzly Bears"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, 1); } } From 03576ce11a50d9a5fca47a9151611e9242d4a618 Mon Sep 17 00:00:00 2001 From: Alexsandro Date: Thu, 12 Jan 2017 09:40:55 -0200 Subject: [PATCH 09/44] Change operators for .equals() --- Mage.Sets/src/mage/cards/h/Hivestone.java | 2 +- .../mage/filter/predicate/mageobject/NoAbilityPredicate.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/cards/h/Hivestone.java b/Mage.Sets/src/mage/cards/h/Hivestone.java index a159823ef56..1738625eaf8 100644 --- a/Mage.Sets/src/mage/cards/h/Hivestone.java +++ b/Mage.Sets/src/mage/cards/h/Hivestone.java @@ -54,7 +54,7 @@ class CreaturesAreSliversEffect extends ContinuousEffectImpl { List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game); for (Permanent perm : permanents) { List cardSubType = perm.getSubtype(game); - if (!cardSubType.contains("Sliver") && perm.getOwnerId() == player.getId()) { + if (!cardSubType.contains("Sliver") && perm.getOwnerId().equals(player.getId())) { cardSubType.add("Sliver"); } } diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java index ad20b77f474..83e285132be 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java @@ -27,7 +27,7 @@ public class NoAbilityPredicate implements Predicate { } if (isFaceDown) { for (Ability ability : abilities){ - if(ability.getSourceId() != input.getId()) { + if(!ability.getSourceId().equals(input.getId())) { return false; } } From f5ddd77e5b6cbe6f35499bb4616957a85043a48a Mon Sep 17 00:00:00 2001 From: Alexsandro Date: Thu, 12 Jan 2017 09:45:35 -0200 Subject: [PATCH 10/44] Move NoAbilityPredicate to MuragandaPetroglyphs file --- .../mage/cards/m/MuragandaPetroglyphs.java | 45 ++++++++++++++++- .../mageobject/NoAbilityPredicate.java | 50 ------------------- 2 files changed, 44 insertions(+), 51 deletions(-) delete mode 100644 Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java diff --git a/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java b/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java index d7731449c28..ae27cf86d92 100644 --- a/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java +++ b/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java @@ -29,15 +29,21 @@ package mage.cards.m; import java.util.UUID; +import mage.MageObject; +import mage.abilities.Abilities; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.NoAbilityPredicate; +import mage.filter.predicate.Predicate; +import mage.game.Game; /** * @@ -66,4 +72,41 @@ public class MuragandaPetroglyphs extends CardImpl { public MuragandaPetroglyphs copy() { return new MuragandaPetroglyphs(this); } +} + +class NoAbilityPredicate implements Predicate { + + @Override + public boolean apply(MageObject input, Game game) { + boolean isFaceDown = false; + Abilities abilities; + if (input instanceof Card){ + abilities = ((Card)input).getAbilities(game); + + isFaceDown = ((Card)input).isFaceDown(game); + } else { + abilities = input.getAbilities(); + } + if (isFaceDown) { + for (Ability ability : abilities){ + if(!ability.getSourceId().equals(input.getId())) { + return false; + } + } + return true; + } + + for (Ability ability : abilities){ + if (ability.getClass() != SpellAbility.class){ + + return false; + } + } + return true; + } + + @Override + public String toString() { + return "with no abilities"; + } } \ No newline at end of file diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java deleted file mode 100644 index 83e285132be..00000000000 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java +++ /dev/null @@ -1,50 +0,0 @@ -package mage.filter.predicate.mageobject; - -import mage.MageObject; -import mage.abilities.Abilities; -import mage.abilities.Ability; -import mage.abilities.SpellAbility; -import mage.abilities.keyword.MorphAbility; -import mage.cards.Card; -import mage.filter.predicate.Predicate; -import mage.game.Game; - -/** - * Created by Alexsandro. - */ -public class NoAbilityPredicate implements Predicate { - - @Override - public boolean apply(MageObject input, Game game) { - boolean isFaceDown = false; - Abilities abilities; - if (input instanceof Card){ - abilities = ((Card)input).getAbilities(game); - - isFaceDown = ((Card)input).isFaceDown(game); - } else { - abilities = input.getAbilities(); - } - if (isFaceDown) { - for (Ability ability : abilities){ - if(!ability.getSourceId().equals(input.getId())) { - return false; - } - } - return true; - } - - for (Ability ability : abilities){ - if (ability.getClass() != SpellAbility.class){ - - return false; - } - } - return true; - } - - @Override - public String toString() { - return "with no abilities"; - } -} \ No newline at end of file From 073100273ccb0688eddec608d9c3ff67e35e8f9e Mon Sep 17 00:00:00 2001 From: vereena42 Date: Sun, 15 Jan 2017 17:28:42 +0100 Subject: [PATCH 11/44] Adding PowerstoneMinefield card --- .../src/mage/cards/p/PowerstoneMinefield.java | 109 ++++++++++++++++++ Mage.Sets/src/mage/sets/Apocalypse.java | 1 + 2 files changed, 110 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/p/PowerstoneMinefield.java diff --git a/Mage.Sets/src/mage/cards/p/PowerstoneMinefield.java b/Mage.Sets/src/mage/cards/p/PowerstoneMinefield.java new file mode 100644 index 00000000000..97dc6b032b5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PowerstoneMinefield.java @@ -0,0 +1,109 @@ +/* + * 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.p; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * + * @author vereena42 + */ +public class PowerstoneMinefield extends CardImpl { + + public PowerstoneMinefield(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{W}"); + + + // Whenever a creature attacks or blocks, Powerstone Minefield deals 2 damage to it. + this.addAbility(new PowerstoneMinefieldTriggeredAbility()); + } + + public PowerstoneMinefield(final PowerstoneMinefield card) { + super(card); + } + + @Override + public PowerstoneMinefield copy() { + return new PowerstoneMinefield(this); + } +} + +class PowerstoneMinefieldTriggeredAbility extends TriggeredAbilityImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + public PowerstoneMinefieldTriggeredAbility() { + super(Zone.BATTLEFIELD, new DamageTargetEffect(2), false); + } + + public PowerstoneMinefieldTriggeredAbility(PowerstoneMinefieldTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.ATTACKER_DECLARED || event.getType() == EventType.BLOCKER_DECLARED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + UUID sourceId = event.getSourceId(); + Permanent permanent = game.getPermanent(sourceId); + if (filter.match(permanent, getSourceId(), getControllerId(), game)) { + for (Effect effect : this.getEffects()) { + effect.setTargetPointer(new FixedTarget(sourceId)); + } + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever a creature attacks or blocks, Powerstone Minefield deals 2 damage to it."; + } + + @Override + public PowerstoneMinefieldTriggeredAbility copy() { + return new PowerstoneMinefieldTriggeredAbility(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Apocalypse.java b/Mage.Sets/src/mage/sets/Apocalypse.java index 8369a55174b..2ce5226b2cf 100644 --- a/Mage.Sets/src/mage/sets/Apocalypse.java +++ b/Mage.Sets/src/mage/sets/Apocalypse.java @@ -110,6 +110,7 @@ public class Apocalypse extends ExpansionSet { cards.add(new SetCardInfo("Phyrexian Gargantua", 48, Rarity.UNCOMMON, mage.cards.p.PhyrexianGargantua.class)); cards.add(new SetCardInfo("Phyrexian Rager", 49, Rarity.COMMON, mage.cards.p.PhyrexianRager.class)); cards.add(new SetCardInfo("Planar Despair", 50, Rarity.RARE, mage.cards.p.PlanarDespair.class)); + cards.add(new SetCardInfo("Powerstone Minefield", 115, Rarity.RARE, mage.cards.p.PowerstoneMinefield.class)); cards.add(new SetCardInfo("Prophetic Bolt", 116, Rarity.RARE, mage.cards.p.PropheticBolt.class)); cards.add(new SetCardInfo("Putrid Warrior", 117, Rarity.COMMON, mage.cards.p.PutridWarrior.class)); cards.add(new SetCardInfo("Quagmire Druid", 51, Rarity.COMMON, mage.cards.q.QuagmireDruid.class)); From c52637343c810cd9c75d7ccae3489194a6162978 Mon Sep 17 00:00:00 2001 From: Quercitron Date: Fri, 20 Jan 2017 04:18:44 +0300 Subject: [PATCH 12/44] Fix build. --- Mage.Server/src/main/java/mage/server/game/GameController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Server/src/main/java/mage/server/game/GameController.java b/Mage.Server/src/main/java/mage/server/game/GameController.java index 0417687ab76..854f40680ed 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameController.java +++ b/Mage.Server/src/main/java/mage/server/game/GameController.java @@ -313,7 +313,7 @@ public class GameController implements GameCallback { logger.fatal("- userId: " + userId); return; } - if(!user.isPresent(){ + if (!user.isPresent()) { logger.fatal("User not found : "+userId); return; } From 292c9f6eba7c04733292e0e8d3425b75844e7044 Mon Sep 17 00:00:00 2001 From: Quercitron Date: Fri, 20 Jan 2017 04:20:43 +0300 Subject: [PATCH 13/44] * Hope of Ghirapur - Fix that ability could be activated if Hope of Ghirapur was removed from the battlefield and returned back (fixes #2808). --- .../src/mage/cards/h/HopeOfGhirapur.java | 41 +++++++------ .../cards/single/aer/HopeOfGhirapurTest.java | 59 +++++++++++++++++++ 2 files changed, 81 insertions(+), 19 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/aer/HopeOfGhirapurTest.java diff --git a/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java b/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java index 0dfb3029ca5..411652317cc 100644 --- a/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java +++ b/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java @@ -33,6 +33,7 @@ import java.util.Set; import java.util.UUID; import mage.MageInt; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -88,7 +89,8 @@ public class HopeOfGhirapur extends CardImpl { if (sourceObject != null) { ability.getTargets().clear(); FilterPlayer playerFilter = new FilterPlayer("player who was dealt combat damage by " + sourceObject.getIdName() + " this turn"); - playerFilter.add(new HopeOfGhirapurPlayerLostLifePredicate(ability.getSourceId())); + MageObjectReference sourceReference = new MageObjectReference(ability.getSourceId(), ability.getSourceObjectZoneChangeCounter(), game); + playerFilter.add(new HopeOfGhirapurPlayerLostLifePredicate(sourceReference)); ability.addTarget(new TargetPlayer(1, 1, false, playerFilter)); } } @@ -155,17 +157,17 @@ class HopeOfGhirapurCantCastEffect extends ContinuousRuleModifyingEffectImpl { class HopeOfGhirapurPlayerLostLifePredicate implements Predicate { - private final UUID sourceId; + private final MageObjectReference sourceReference; - public HopeOfGhirapurPlayerLostLifePredicate(UUID sourceId) { - this.sourceId = sourceId; + public HopeOfGhirapurPlayerLostLifePredicate(MageObjectReference sourceReference) { + this.sourceReference = sourceReference; } @Override public boolean apply(Player input, Game game) { HopeOfGhirapurCombatDamageWatcher watcher = (HopeOfGhirapurCombatDamageWatcher) game.getState().getWatchers().get(HopeOfGhirapurCombatDamageWatcher.class.getName()); if (watcher != null) { - return watcher.playerGotCombatDamage(sourceId, input.getId()); + return watcher.playerGotCombatDamage(sourceReference, input.getId()); } return false; } @@ -173,7 +175,7 @@ class HopeOfGhirapurPlayerLostLifePredicate implements Predicate { class HopeOfGhirapurCombatDamageWatcher extends Watcher { - private final HashMap> combatDamagedPlayers = new HashMap<>(); + private final HashMap> combatDamagedPlayers = new HashMap<>(); public HopeOfGhirapurCombatDamageWatcher() { super(HopeOfGhirapurCombatDamageWatcher.class.getName(), WatcherScope.GAME); @@ -181,10 +183,10 @@ class HopeOfGhirapurCombatDamageWatcher extends Watcher { public HopeOfGhirapurCombatDamageWatcher(final HopeOfGhirapurCombatDamageWatcher watcher) { super(watcher); - for (UUID objectId : watcher.combatDamagedPlayers.keySet()) { + for (MageObjectReference sourceReference : watcher.combatDamagedPlayers.keySet()) { Set players = new HashSet<>(); - players.addAll(watcher.combatDamagedPlayers.get(objectId)); - this.combatDamagedPlayers.put(objectId, players); + players.addAll(watcher.combatDamagedPlayers.get(sourceReference)); + this.combatDamagedPlayers.put(sourceReference, players); } } @@ -196,28 +198,29 @@ class HopeOfGhirapurCombatDamageWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { if (event.getType() == EventType.DAMAGED_PLAYER && ((DamagedPlayerEvent) event).isCombatDamage()) { + MageObjectReference sourceReference = new MageObjectReference(event.getSourceId(), game); Set players; - if (combatDamagedPlayers.containsKey(event.getSourceId())) { - players = combatDamagedPlayers.get(event.getSourceId()); + if (combatDamagedPlayers.containsKey(sourceReference)) { + players = combatDamagedPlayers.get(sourceReference); } else { players = new HashSet<>(); - combatDamagedPlayers.put(event.getSourceId(), players); + combatDamagedPlayers.put(sourceReference, players); } players.add(event.getTargetId()); } } /** - * Checks if the current object with sourceId has damaged the player during - * the current turn. The zoneChangeCounter will be taken into account. + * Checks if the current object has damaged the player during + * the current turn. * - * @param sourceId - * @param game + * @param objectReference + * @param playerId * @return */ - public boolean playerGotCombatDamage(UUID sourceId, UUID playerId) { - if (combatDamagedPlayers.containsKey(sourceId)) { - return combatDamagedPlayers.get(sourceId).contains(playerId); + public boolean playerGotCombatDamage(MageObjectReference objectReference, UUID playerId) { + if (combatDamagedPlayers.containsKey(objectReference)) { + return combatDamagedPlayers.get(objectReference).contains(playerId); } return false; } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/aer/HopeOfGhirapurTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/aer/HopeOfGhirapurTest.java new file mode 100644 index 00000000000..b0340abb5b6 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/aer/HopeOfGhirapurTest.java @@ -0,0 +1,59 @@ +package org.mage.test.cards.single.aer; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author Quercitron + */ +public class HopeOfGhirapurTest extends CardTestPlayerBase { + + @Test + public void testThatNoncreatureSpellsCannotBeCast() { + addCard(Zone.BATTLEFIELD, playerA, "Hope of Ghirapur"); + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + addCard(Zone.HAND, playerB, "Shock"); + + attack(1, playerA, "Hope of Ghirapur"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Sacrifice", playerB); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Shock", playerA); + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 19); + assertPermanentCount(playerA, "Hope of Ghirapur", 0); + } + + // Test that ability cannot be activated if after damage Hope of Ghirapur was removed + // from the battlefield and returned back. + @Test + public void testWhenHopeOfGhirapurWasRemovedAndReturnedBack() { + addCard(Zone.BATTLEFIELD, playerA, "Hope of Ghirapur"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + addCard(Zone.HAND, playerA, "Cloudshift"); + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + addCard(Zone.HAND, playerB, "Shock"); + + attack(1, playerA, "Hope of Ghirapur"); + castSpell(1, PhaseStep.END_COMBAT, playerA, "Cloudshift", "Hope of Ghirapur"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Sacrifice", playerB); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Shock", playerA); + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + execute(); + + assertLife(playerA, 18); + assertLife(playerB, 19); + assertPermanentCount(playerA, "Hope of Ghirapur", 1); + } + +} From 2bac7637b9c1e31b34ef5b7aee6b7fb09af39aac Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 20 Jan 2017 15:45:42 +0100 Subject: [PATCH 14/44] * Donate - Fixed not correctly working change control effect. --- Mage.Sets/src/mage/cards/d/Donate.java | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Mage.Sets/src/mage/cards/d/Donate.java b/Mage.Sets/src/mage/cards/d/Donate.java index 338195434fc..de1284c6656 100644 --- a/Mage.Sets/src/mage/cards/d/Donate.java +++ b/Mage.Sets/src/mage/cards/d/Donate.java @@ -29,19 +29,20 @@ package mage.cards.d; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +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.Layer; import mage.constants.Outcome; -import mage.constants.SubLayer; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetControlledPermanent; +import mage.target.targetpointer.FixedTarget; /** * @@ -52,7 +53,6 @@ public class Donate extends CardImpl { public Donate(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{U}"); - // Target player gains control of target permanent you control. this.getSpellAbility().addEffect(new DonateEffect()); this.getSpellAbility().addTarget(new TargetPlayer()); @@ -69,10 +69,10 @@ public class Donate extends CardImpl { } } -class DonateEffect extends ContinuousEffectImpl { +class DonateEffect extends OneShotEffect { public DonateEffect() { - super(Duration.EndOfGame, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.Benefit); + super(Outcome.Detriment); this.staticText = "Target player gains control of target permanent you control"; } @@ -86,14 +86,13 @@ class DonateEffect extends ContinuousEffectImpl { } @Override - public boolean apply(Game game, Ability source) { - UUID controllerId = source.getTargets().get(0).getFirstTarget(); - Player controller = game.getPlayer(controllerId); + public boolean apply(Game game, Ability source) { + Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); Permanent permanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (controller != null && permanent != null) { - permanent.changeControllerId(controllerId, game); - } else { - this.discard(); + if (targetPlayer != null && permanent != null) { + ContinuousEffect effect = new GainControlTargetEffect(Duration.Custom, true, targetPlayer.getId()); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); } return true; } From 509139bb4a04c117e3a8db7e5dfc8609eff89d45 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 20 Jan 2017 15:46:17 +0100 Subject: [PATCH 15/44] * Steel Golem - Fixed not correct working "dont cast" effect. --- Mage.Sets/src/mage/cards/s/SteelGolem.java | 14 +++----- .../control/GainControlTargetEffectTest.java | 32 +++++++++++++++++++ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/Mage.Sets/src/mage/cards/s/SteelGolem.java b/Mage.Sets/src/mage/cards/s/SteelGolem.java index 99315c240b0..33467159101 100644 --- a/Mage.Sets/src/mage/cards/s/SteelGolem.java +++ b/Mage.Sets/src/mage/cards/s/SteelGolem.java @@ -28,18 +28,16 @@ package mage.cards.s; import java.util.UUID; - -import mage.constants.*; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.filter.common.FilterCreatureSpell; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.stack.Spell; /** * @@ -70,8 +68,6 @@ public class SteelGolem extends CardImpl { class SteelGolemEffect extends ContinuousRuleModifyingEffectImpl { - private static final FilterCreatureSpell filter = new FilterCreatureSpell(); - public SteelGolemEffect() { super(Duration.WhileOnBattlefield, Outcome.Detriment); staticText = "You can't cast creature spells"; @@ -94,10 +90,8 @@ class SteelGolemEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getPlayerId().equals(source.getControllerId())) { - Spell spell = game.getStack().getSpell(event.getSourceId()); - if (spell != null && filter.match(spell, game)) { - return true; - } + Card card = game.getCard(event.getSourceId()); + return card != null && card.getCardType().contains(CardType.CREATURE); } return false; } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/control/GainControlTargetEffectTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/control/GainControlTargetEffectTest.java index 67d160b6b8b..cad199d155f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/control/GainControlTargetEffectTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/control/GainControlTargetEffectTest.java @@ -105,4 +105,36 @@ public class GainControlTargetEffectTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Mutavault", 1); } + + /** + * Steel Golem, once Donate'd to another player does not disable their ability to play creature cards. + */ + @Test + public void testDonateSteelGolem() { + // You can't cast creature spells. + addCard(Zone.HAND, playerA, "Steel Golem", 1); // Creature 3/4 {3} + // Target player gains control of target permanent you control. + addCard(Zone.HAND, playerA, "Donate", 1); // Sorcery {2}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + + addCard(Zone.BATTLEFIELD, playerB, "Plains", 2); + addCard(Zone.HAND, playerB, "Silvercoat Lion", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Steel Golem"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Donate", playerB); + addTarget(playerA, "Steel Golem"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Silvercoat Lion"); + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Donate", 1); + assertPermanentCount(playerA, "Steel Golem", 0); + assertPermanentCount(playerB, "Steel Golem", 1); + assertPermanentCount(playerB, "Silvercoat Lion", 0); + assertHandCount(playerB, "Silvercoat Lion", 1); + + } + } From 8754dc0a69d00faadd3401d347b822f455c76235 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 20 Jan 2017 18:44:59 +0100 Subject: [PATCH 16/44] * Chief of the Foundry - Fixed wrong tooltip text. --- Mage.Sets/src/mage/cards/c/ChiefOfTheFoundry.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/cards/c/ChiefOfTheFoundry.java b/Mage.Sets/src/mage/cards/c/ChiefOfTheFoundry.java index 56b27d77b6d..8b309aabc70 100644 --- a/Mage.Sets/src/mage/cards/c/ChiefOfTheFoundry.java +++ b/Mage.Sets/src/mage/cards/c/ChiefOfTheFoundry.java @@ -46,8 +46,8 @@ import mage.filter.predicate.permanent.ControllerPredicate; * @author fireshoes */ public class ChiefOfTheFoundry extends CardImpl { - - private static final FilterCreaturePermanent filterBoosted = new FilterCreaturePermanent("artifact creatures"); + + private static final FilterCreaturePermanent filterBoosted = new FilterCreaturePermanent("Other artifact creatures you control"); static { filterBoosted.add(new CardTypePredicate(CardType.ARTIFACT)); @@ -55,7 +55,7 @@ public class ChiefOfTheFoundry extends CardImpl { } public ChiefOfTheFoundry(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); this.subtype.add("Construct"); this.power = new MageInt(2); this.toughness = new MageInt(3); From ce8d752f221039c1c96020ebb1cec64c2a616972 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 20 Jan 2017 19:01:11 +0100 Subject: [PATCH 17/44] * Fairgrounds Trumpeter - Fixed that counters added to permanents entering the battlefield were not taken into account. --- .../mage/cards/f/FairgroundsTrumpeter.java | 3 +++ .../AddingCountersToPermanentsTest.java | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/Mage.Sets/src/mage/cards/f/FairgroundsTrumpeter.java b/Mage.Sets/src/mage/cards/f/FairgroundsTrumpeter.java index 6d31fd6d877..21831facd9c 100644 --- a/Mage.Sets/src/mage/cards/f/FairgroundsTrumpeter.java +++ b/Mage.Sets/src/mage/cards/f/FairgroundsTrumpeter.java @@ -115,6 +115,9 @@ class FairgroundsTrumpeterWatcher extends Watcher { public void watch(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.COUNTER_ADDED && event.getData().equals(CounterType.P1P1.getName())) { Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); + if (permanent == null) { + permanent = game.getPermanentEntering(event.getTargetId()); + } if (permanent != null) { players.add(permanent.getControllerId()); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counter/AddingCountersToPermanentsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counter/AddingCountersToPermanentsTest.java index 131b7b18b0d..f341e607f4b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counter/AddingCountersToPermanentsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counter/AddingCountersToPermanentsTest.java @@ -67,4 +67,28 @@ public class AddingCountersToPermanentsTest extends CardTestPlayerBase { } + /** + * Fairgrounds Trumpeter does not get a counter at the end of turn when + * Woodland Wanderer enters the battlefield + */ + @Test + public void testFairgroundsTrumpeter() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 7); + // At the beginning of each end step, if a +1/+1 counter was placed on a permanent under your control this turn, put a +1/+1 counter on Fairgrounds Trumpeter. + addCard(Zone.HAND, playerA, "Fairgrounds Trumpeter", 1); // Creature 2/2 {2}{G} + // Vigilance, trample + // Converge — Woodland Wanderer enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it. + addCard(Zone.HAND, playerA, "Woodland Wanderer", 1); // Creature 2/2 {3}{G} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Woodland Wanderer"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Fairgrounds Trumpeter"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPowerToughness(playerA, "Woodland Wanderer", 3, 3); + assertPowerToughness(playerA, "Fairgrounds Trumpeter", 3, 3); + + } + } From c3f087246af2c8fec544cce3150c53f9cc7ad073 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 20 Jan 2017 19:16:19 +0100 Subject: [PATCH 18/44] * See Beyond - Fixed wrong card moving from hand to library. --- Mage.Sets/src/mage/cards/s/SeeBeyond.java | 43 +++++++++++------------ 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/Mage.Sets/src/mage/cards/s/SeeBeyond.java b/Mage.Sets/src/mage/cards/s/SeeBeyond.java index a591e49dba8..c0db7992f86 100644 --- a/Mage.Sets/src/mage/cards/s/SeeBeyond.java +++ b/Mage.Sets/src/mage/cards/s/SeeBeyond.java @@ -1,16 +1,16 @@ /* * 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 @@ -20,23 +20,22 @@ * 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.s; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; import mage.players.Player; @@ -49,7 +48,7 @@ import mage.target.TargetCard; public class SeeBeyond extends CardImpl { public SeeBeyond(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}"); this.getSpellAbility().addEffect(new SeeBeyondEffect()); } @@ -67,8 +66,6 @@ public class SeeBeyond extends CardImpl { class SeeBeyondEffect extends OneShotEffect { - private static FilterCard filter = new FilterCard("card to shuffle into your library"); - public SeeBeyondEffect() { super(Outcome.DrawCard); staticText = "Draw two cards, then shuffle a card from your hand into your library"; @@ -80,18 +77,18 @@ class SeeBeyondEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - player.drawCards(2, game); - if (player.getHand().size() > 0) { - TargetCard target = new TargetCard(Zone.HAND, filter); - player.choose(Outcome.Detriment, player.getHand(), target, game); - Card card = player.getHand().get(target.getFirstTarget(), game); + Player controller = game.getPlayer(source.getControllerId()); + controller.drawCards(2, game); + if (controller.getHand().size() > 0) { + TargetCard target = new TargetCard(Zone.HAND, new FilterCard("card to shuffle into your library")); + controller.choose(Outcome.Detriment, controller.getHand(), target, game); + Card card = controller.getHand().get(target.getFirstTarget(), game); if (card != null) { - player.removeFromHand(card, game); - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); - player.shuffleLibrary(source, game); - return true; + controller.moveCards(card, Zone.LIBRARY, source, game); + controller.shuffleLibrary(source, game); } + return true; + } return true; } @@ -101,4 +98,4 @@ class SeeBeyondEffect extends OneShotEffect { return new SeeBeyondEffect(this); } -} \ No newline at end of file +} From 83679ea7a26d79c204ec0101619c8f9426b12d43 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Fri, 20 Jan 2017 22:33:27 +0100 Subject: [PATCH 19/44] * Mystic Confluence - Judge Promo card set unique card number. --- Mage.Sets/src/mage/sets/JudgePromo.java | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Mage.Sets/src/mage/sets/JudgePromo.java b/Mage.Sets/src/mage/sets/JudgePromo.java index 23f5fe90e41..a6c06f4b072 100644 --- a/Mage.Sets/src/mage/sets/JudgePromo.java +++ b/Mage.Sets/src/mage/sets/JudgePromo.java @@ -24,14 +24,13 @@ * 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.sets; -import mage.constants.SetType; +import mage.cards.CardGraphicInfo; import mage.cards.ExpansionSet; import mage.constants.Rarity; -import mage.cards.CardGraphicInfo; +import mage.constants.SetType; /** * @@ -50,14 +49,14 @@ public class JudgePromo extends ExpansionSet { this.hasBoosters = false; cards.add(new SetCardInfo("Argothian Enchantress", 12, Rarity.RARE, mage.cards.a.ArgothianEnchantress.class)); cards.add(new SetCardInfo("Armageddon", 14, Rarity.RARE, mage.cards.a.Armageddon.class)); - cards.add(new SetCardInfo("Azusa, Lost but Seeking", 102, Rarity.RARE, mage.cards.a.AzusaLostButSeeking.class)); + cards.add(new SetCardInfo("Azusa, Lost but Seeking", 102, Rarity.RARE, mage.cards.a.AzusaLostButSeeking.class));// 2016 003/008 cards.add(new SetCardInfo("Balance", 15, Rarity.RARE, mage.cards.b.Balance.class)); cards.add(new SetCardInfo("Ball Lightning", 7, Rarity.RARE, mage.cards.b.BallLightning.class)); cards.add(new SetCardInfo("Bitterblossom", 59, Rarity.RARE, mage.cards.b.Bitterblossom.class)); cards.add(new SetCardInfo("Bloodstained Mire", 43, Rarity.RARE, mage.cards.b.BloodstainedMire.class)); cards.add(new SetCardInfo("Bribery", 73, Rarity.RARE, mage.cards.b.Bribery.class)); cards.add(new SetCardInfo("Burning Wish", 42, Rarity.RARE, mage.cards.b.BurningWish.class)); - cards.add(new SetCardInfo("Command Beacon", 105, Rarity.RARE, mage.cards.c.CommandBeacon.class)); + cards.add(new SetCardInfo("Command Beacon", 105, Rarity.RARE, mage.cards.c.CommandBeacon.class));// 2016 004/008 cards.add(new SetCardInfo("Command Tower", 71, Rarity.COMMON, mage.cards.c.CommandTower.class)); cards.add(new SetCardInfo("Counterspell", 5, Rarity.COMMON, mage.cards.c.Counterspell.class)); cards.add(new SetCardInfo("Crucible of Worlds", 75, Rarity.RARE, mage.cards.c.CrucibleOfWorlds.class)); @@ -66,7 +65,7 @@ public class JudgePromo extends ExpansionSet { cards.add(new SetCardInfo("Dark Confidant", 61, Rarity.RARE, mage.cards.d.DarkConfidant.class)); cards.add(new SetCardInfo("Dark Ritual", 38, Rarity.COMMON, mage.cards.d.DarkRitual.class)); cards.add(new SetCardInfo("Decree of Justice", 32, Rarity.RARE, mage.cards.d.DecreeOfJustice.class)); - cards.add(new SetCardInfo("Defense of the Heart", 106, Rarity.RARE, mage.cards.d.DefenseOfTheHeart.class)); + cards.add(new SetCardInfo("Defense of the Heart", 106, Rarity.RARE, mage.cards.d.DefenseOfTheHeart.class)); // 2016 007/008 cards.add(new SetCardInfo("Demonic Tutor", 35, Rarity.UNCOMMON, mage.cards.d.DemonicTutor.class)); cards.add(new SetCardInfo("Deranged Hermit", 18, Rarity.RARE, mage.cards.d.DerangedHermit.class)); cards.add(new SetCardInfo("Doubling Season", 62, Rarity.RARE, mage.cards.d.DoublingSeason.class)); @@ -91,7 +90,7 @@ public class JudgePromo extends ExpansionSet { cards.add(new SetCardInfo("Hanna, Ship's Navigator", 84, Rarity.RARE, mage.cards.h.HannaShipsNavigator.class)); cards.add(new SetCardInfo("Hermit Druid", 19, Rarity.RARE, mage.cards.h.HermitDruid.class)); cards.add(new SetCardInfo("Imperial Recruiter", 74, Rarity.UNCOMMON, mage.cards.i.ImperialRecruiter.class)); - cards.add(new SetCardInfo("Imperial Seal", 109, Rarity.SPECIAL, mage.cards.i.ImperialSeal.class)); + cards.add(new SetCardInfo("Imperial Seal", 109, Rarity.SPECIAL, mage.cards.i.ImperialSeal.class));// 2016 006/008 cards.add(new SetCardInfo("Intuition", 11, Rarity.RARE, mage.cards.i.Intuition.class)); cards.add(new SetCardInfo("Island", 90, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(null, true))); cards.add(new SetCardInfo("Karador, Ghost Chieftain", 80, Rarity.MYTHIC, mage.cards.k.KaradorGhostChieftain.class)); @@ -102,7 +101,7 @@ public class JudgePromo extends ExpansionSet { cards.add(new SetCardInfo("Living Death", 13, Rarity.RARE, mage.cards.l.LivingDeath.class)); cards.add(new SetCardInfo("Living Wish", 37, Rarity.RARE, mage.cards.l.LivingWish.class)); cards.add(new SetCardInfo("Mana Crypt", 60, Rarity.RARE, mage.cards.m.ManaCrypt.class)); - cards.add(new SetCardInfo("Mana Drain", 103, Rarity.UNCOMMON, mage.cards.m.ManaDrain.class)); + cards.add(new SetCardInfo("Mana Drain", 103, Rarity.UNCOMMON, mage.cards.m.ManaDrain.class));// 2016 002/008 cards.add(new SetCardInfo("Maze of Ith", 39, Rarity.UNCOMMON, mage.cards.m.MazeOfIth.class)); cards.add(new SetCardInfo("Meddling Mage", 26, Rarity.RARE, mage.cards.m.MeddlingMage.class)); cards.add(new SetCardInfo("Memory Lapse", 4, Rarity.COMMON, mage.cards.m.MemoryLapse.class)); @@ -110,7 +109,7 @@ public class JudgePromo extends ExpansionSet { cards.add(new SetCardInfo("Mishra's Factory", 23, Rarity.UNCOMMON, mage.cards.m.MishrasFactory.class)); cards.add(new SetCardInfo("Morphling", 53, Rarity.RARE, mage.cards.m.Morphling.class)); cards.add(new SetCardInfo("Mountain", 92, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(null, true))); - cards.add(new SetCardInfo("Mystic Confluence", 109, Rarity.SPECIAL, mage.cards.m.MysticConfluence.class, new CardGraphicInfo(null, true))); + cards.add(new SetCardInfo("Mystic Confluence", 108, Rarity.SPECIAL, mage.cards.m.MysticConfluence.class, new CardGraphicInfo(null, true))); // 2016 005/008 cards.add(new SetCardInfo("Natural Order", 49, Rarity.RARE, mage.cards.n.NaturalOrder.class)); cards.add(new SetCardInfo("Nekusar, the Mindrazer", 86, Rarity.MYTHIC, mage.cards.n.NekusarTheMindrazer.class)); cards.add(new SetCardInfo("Noble Hierarch", 66, Rarity.RARE, mage.cards.n.NobleHierarch.class)); @@ -155,7 +154,7 @@ public class JudgePromo extends ExpansionSet { cards.add(new SetCardInfo("Wooded Foothills", 47, Rarity.RARE, mage.cards.w.WoodedFoothills.class)); cards.add(new SetCardInfo("Xiahou Dun, the One-Eyed", 64, Rarity.RARE, mage.cards.x.XiahouDunTheOneEyed.class)); cards.add(new SetCardInfo("Yawgmoth's Will", 30, Rarity.RARE, mage.cards.y.YawgmothsWill.class)); - cards.add(new SetCardInfo("Zur the Enchanter", 107, Rarity.RARE, mage.cards.z.ZurTheEnchanter.class)); + cards.add(new SetCardInfo("Zur the Enchanter", 107, Rarity.RARE, mage.cards.z.ZurTheEnchanter.class)); // 2016 008/008 } -} \ No newline at end of file +} From 5fe25b0af7ba2164ca23a3132e2045d2cef09a6b Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 21 Jan 2017 00:51:31 +0100 Subject: [PATCH 20/44] * Fixed some problems with set icon download and displaying. --- .../org/mage/card/arcane/CardRenderer.java | 3 - .../org/mage/card/arcane/ManaSymbols.java | 30 ++++- .../plugins/card/dl/sources/GathererSets.java | 32 +++-- .../src/mage/sets/MagicPlayerRewards.java | 104 ++++++++------- .../src/mage/sets/MasterpieceSeries.java | 124 ++++++++---------- Mage/src/main/java/mage/cards/FrameStyle.java | 4 + .../cards/repository/ExpansionRepository.java | 2 +- 7 files changed, 164 insertions(+), 135 deletions(-) diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java index 7c4dbf24804..4b3bcc54b64 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java @@ -21,7 +21,6 @@ import mage.utils.CardUtil; import mage.view.CardView; import mage.view.CounterView; import mage.view.PermanentView; -import org.apache.log4j.Logger; /** * @author stravant@gmail.com @@ -56,8 +55,6 @@ import org.apache.log4j.Logger; */ public abstract class CardRenderer { - private static final Logger LOGGER = Logger.getLogger(CardPanel.class); - /////////////////////////////////////////////////////////////////////////// // Common layout metrics between all cards // The card to be rendered diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java index d1e37c6034f..32e2e6c0e79 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java @@ -17,6 +17,7 @@ import java.nio.file.SimpleFileVisitor; import java.nio.file.StandardCopyOption; import java.nio.file.attribute.BasicFileAttributes; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.StringTokenizer; @@ -38,6 +39,23 @@ public class ManaSymbols { private static boolean mediumSymbolsFound = false; private static final Map> setImages = new HashMap<>(); + + private static final HashSet onlyMythics = new HashSet<>(); + private static final HashSet withoutSymbols = new HashSet<>(); + + static { + onlyMythics.add("DRB"); + onlyMythics.add("V09"); + onlyMythics.add("V12"); + onlyMythics.add("V13"); + onlyMythics.add("V14"); + onlyMythics.add("V15"); + onlyMythics.add("V16"); + onlyMythics.add("EXP"); + onlyMythics.add("MPS"); + + withoutSymbols.add("MPRP"); + } private static final Map setImagesExist = new HashMap<>(); private static final Pattern REPLACE_SYMBOLS_PATTERN = Pattern.compile("\\{([^}/]*)/?([^}]*)\\}"); private static String cachedPath; @@ -57,7 +75,15 @@ public class ManaSymbols { return; } for (String set : setCodes) { - String[] codes = new String[]{"C", "U", "R", "M"}; + if (withoutSymbols.contains(set)) { + continue; + } + String[] codes; + if (onlyMythics.contains(set)) { + codes = new String[]{"M"}; + } else { + codes = new String[]{"C", "U", "R", "M"}; + } Map rarityImages = new HashMap<>(); setImages.put(set, rarityImages); @@ -72,7 +98,7 @@ public class ManaSymbols { if (h > 0) { Rectangle r = new Rectangle(21, (int) (h * 21.0f / width)); BufferedImage resized = ImageHelper.getResizedImage(BufferedImageBuilder.bufferImage(image, BufferedImage.TYPE_INT_ARGB), r); - rarityImages.put(set, resized); + rarityImages.put(rarityCode, resized); } } else { rarityImages.put(rarityCode, image); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java index 35df3572430..9a5aa9834d7 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java @@ -58,13 +58,16 @@ public class GathererSets implements Iterable { "KTK", "FRF", "DTK", "BFZ", "OGW", "SOI", "EMN", - "KLD", "MPS", "AER", + "KLD", "AER", "AKH", "HOU" }; private static final String[] onlyMythics = { "DRB", "V09", "V12", "V12", "V13", "V14", "V15", "V16", "EXP" }; + private static final String[] onlyMythicsAsSpecial = { + "MPS" + }; private static final HashMap symbolsReplacements = new HashMap<>(); @@ -93,6 +96,7 @@ public class GathererSets implements Iterable { symbolsReplacements.put("LEA", "1E"); symbolsReplacements.put("LEB", "2E"); symbolsReplacements.put("LEG", "LE"); + symbolsReplacements.put("MPS", "MPS_KLD"); symbolsReplacements.put("MIR", "MI"); symbolsReplacements.put("MMQ", "MM"); symbolsReplacements.put("NEM", "NE"); @@ -129,35 +133,41 @@ public class GathererSets implements Iterable { for (String symbol : symbols) { ExpansionSet exp = Sets.findSet(symbol); if (exp != null && exp.getReleaseDate().before(compareDate)) { - jobs.add(generateDownloadJob(symbol, "C")); - jobs.add(generateDownloadJob(symbol, "U")); - jobs.add(generateDownloadJob(symbol, "R")); + jobs.add(generateDownloadJob(symbol, "C", "C")); + jobs.add(generateDownloadJob(symbol, "U", "U")); + jobs.add(generateDownloadJob(symbol, "R", "R")); } } for (String symbol : withMythics) { ExpansionSet exp = Sets.findSet(symbol); if (exp != null && exp.getReleaseDate().before(compareDate)) { - jobs.add(generateDownloadJob(symbol, "C")); - jobs.add(generateDownloadJob(symbol, "U")); - jobs.add(generateDownloadJob(symbol, "R")); - jobs.add(generateDownloadJob(symbol, "M")); + jobs.add(generateDownloadJob(symbol, "C", "C")); + jobs.add(generateDownloadJob(symbol, "U", "U")); + jobs.add(generateDownloadJob(symbol, "R", "R")); + jobs.add(generateDownloadJob(symbol, "M", "M")); } } for (String symbol : onlyMythics) { ExpansionSet exp = Sets.findSet(symbol); if (exp != null && exp.getReleaseDate().before(compareDate)) { - jobs.add(generateDownloadJob(symbol, "M")); + jobs.add(generateDownloadJob(symbol, "M", "M")); + } + } + for (String symbol : onlyMythicsAsSpecial) { + ExpansionSet exp = Sets.findSet(symbol); + if (exp != null && exp.getReleaseDate().before(compareDate)) { + jobs.add(generateDownloadJob(symbol, "M", "S")); } } return jobs.iterator(); } - private DownloadJob generateDownloadJob(String set, String rarity) { + private DownloadJob generateDownloadJob(String set, String rarity, String urlRarity) { File dst = new File(outDir, set + "-" + rarity + ".jpg"); if (symbolsReplacements.containsKey(set)) { set = symbolsReplacements.get(set); } - String url = "http://gatherer.wizards.com/Handlers/Image.ashx?type=symbol&set=" + set + "&size=small&rarity=" + rarity; + String url = "http://gatherer.wizards.com/Handlers/Image.ashx?type=symbol&set=" + set + "&size=small&rarity=" + urlRarity; return new DownloadJob(set + "-" + rarity, fromURL(url), toFile(dst)); } diff --git a/Mage.Sets/src/mage/sets/MagicPlayerRewards.java b/Mage.Sets/src/mage/sets/MagicPlayerRewards.java index d7e730072e0..02d6a2b24c3 100644 --- a/Mage.Sets/src/mage/sets/MagicPlayerRewards.java +++ b/Mage.Sets/src/mage/sets/MagicPlayerRewards.java @@ -27,11 +27,14 @@ */ package mage.sets; +import mage.cards.CardGraphicInfo; import mage.cards.ExpansionSet; -import mage.constants.SetType; +import mage.cards.FrameStyle; import mage.constants.Rarity; +import mage.constants.SetType; public class MagicPlayerRewards extends ExpansionSet { + private static final MagicPlayerRewards fINSTANCE = new MagicPlayerRewards(); public static MagicPlayerRewards getInstance() { @@ -42,58 +45,59 @@ public class MagicPlayerRewards extends ExpansionSet { super("Magic Player Rewards", "MPRP", ExpansionSet.buildDate(1990, 1, 1), SetType.PROMOTIONAL); this.hasBoosters = false; this.hasBasicLands = false; - cards.add(new SetCardInfo("Bituminous Blast", 46, Rarity.SPECIAL, mage.cards.b.BituminousBlast.class)); - cards.add(new SetCardInfo("Blightning", 36, Rarity.SPECIAL, mage.cards.b.Blightning.class)); - cards.add(new SetCardInfo("Brave the Elements", 50, Rarity.SPECIAL, mage.cards.b.BraveTheElements.class)); - cards.add(new SetCardInfo("Burst Lightning", 47, Rarity.SPECIAL, mage.cards.b.BurstLightning.class)); - cards.add(new SetCardInfo("Cancel", 41, Rarity.SPECIAL, mage.cards.c.Cancel.class)); - cards.add(new SetCardInfo("Celestial Purge", 45, Rarity.SPECIAL, mage.cards.c.CelestialPurge.class)); - cards.add(new SetCardInfo("Condemn", 18, Rarity.SPECIAL, mage.cards.c.Condemn.class)); - cards.add(new SetCardInfo("Corrupt", 30, Rarity.SPECIAL, mage.cards.c.Corrupt.class)); - cards.add(new SetCardInfo("Cruel Edict", 21, Rarity.SPECIAL, mage.cards.c.CruelEdict.class)); - cards.add(new SetCardInfo("Cryptic Command", 31, Rarity.SPECIAL, mage.cards.c.CrypticCommand.class)); - cards.add(new SetCardInfo("Damnation", 24, Rarity.SPECIAL, mage.cards.d.Damnation.class)); - cards.add(new SetCardInfo("Day of Judgment", 49, Rarity.SPECIAL, mage.cards.d.DayOfJudgment.class)); - cards.add(new SetCardInfo("Disenchant", 22, Rarity.SPECIAL, mage.cards.d.Disenchant.class)); - cards.add(new SetCardInfo("Doom Blade", 51, Rarity.SPECIAL, mage.cards.d.DoomBlade.class)); - cards.add(new SetCardInfo("Fireball", 6, Rarity.SPECIAL, mage.cards.f.Fireball.class)); - cards.add(new SetCardInfo("Flame Javelin", 32, Rarity.SPECIAL, mage.cards.f.FlameJavelin.class)); - cards.add(new SetCardInfo("Giant Growth", 13, Rarity.SPECIAL, mage.cards.g.GiantGrowth.class)); - cards.add(new SetCardInfo("Harmonize", 28, Rarity.SPECIAL, mage.cards.h.Harmonize.class)); - cards.add(new SetCardInfo("Harrow", 48, Rarity.SPECIAL, mage.cards.h.Harrow.class)); - cards.add(new SetCardInfo("Hinder", 11, Rarity.SPECIAL, mage.cards.h.Hinder.class)); + CardGraphicInfo graphicInfo = new CardGraphicInfo(FrameStyle.MPRP_FULL_ART_BASIC, false); + cards.add(new SetCardInfo("Bituminous Blast", 46, Rarity.SPECIAL, mage.cards.b.BituminousBlast.class, graphicInfo)); + cards.add(new SetCardInfo("Blightning", 36, Rarity.SPECIAL, mage.cards.b.Blightning.class, graphicInfo)); + cards.add(new SetCardInfo("Brave the Elements", 50, Rarity.SPECIAL, mage.cards.b.BraveTheElements.class, graphicInfo)); + cards.add(new SetCardInfo("Burst Lightning", 47, Rarity.SPECIAL, mage.cards.b.BurstLightning.class, graphicInfo)); + cards.add(new SetCardInfo("Cancel", 41, Rarity.SPECIAL, mage.cards.c.Cancel.class, graphicInfo)); + cards.add(new SetCardInfo("Celestial Purge", 45, Rarity.SPECIAL, mage.cards.c.CelestialPurge.class, graphicInfo)); + cards.add(new SetCardInfo("Condemn", 18, Rarity.SPECIAL, mage.cards.c.Condemn.class, graphicInfo)); + cards.add(new SetCardInfo("Corrupt", 30, Rarity.SPECIAL, mage.cards.c.Corrupt.class, graphicInfo)); + cards.add(new SetCardInfo("Cruel Edict", 21, Rarity.SPECIAL, mage.cards.c.CruelEdict.class, graphicInfo)); + cards.add(new SetCardInfo("Cryptic Command", 31, Rarity.SPECIAL, mage.cards.c.CrypticCommand.class, graphicInfo)); + cards.add(new SetCardInfo("Damnation", 24, Rarity.SPECIAL, mage.cards.d.Damnation.class, graphicInfo)); + cards.add(new SetCardInfo("Day of Judgment", 49, Rarity.SPECIAL, mage.cards.d.DayOfJudgment.class, graphicInfo)); + cards.add(new SetCardInfo("Disenchant", 22, Rarity.SPECIAL, mage.cards.d.Disenchant.class, graphicInfo)); + cards.add(new SetCardInfo("Doom Blade", 51, Rarity.SPECIAL, mage.cards.d.DoomBlade.class, graphicInfo)); + cards.add(new SetCardInfo("Fireball", 6, Rarity.SPECIAL, mage.cards.f.Fireball.class, graphicInfo)); + cards.add(new SetCardInfo("Flame Javelin", 32, Rarity.SPECIAL, mage.cards.f.FlameJavelin.class, graphicInfo)); + cards.add(new SetCardInfo("Giant Growth", 13, Rarity.SPECIAL, mage.cards.g.GiantGrowth.class, graphicInfo)); + cards.add(new SetCardInfo("Harmonize", 28, Rarity.SPECIAL, mage.cards.h.Harmonize.class, graphicInfo)); + cards.add(new SetCardInfo("Harrow", 48, Rarity.SPECIAL, mage.cards.h.Harrow.class, graphicInfo)); + cards.add(new SetCardInfo("Hinder", 11, Rarity.SPECIAL, mage.cards.h.Hinder.class, graphicInfo)); cards.add(new SetCardInfo("Hypnotic Specter", 10, Rarity.SPECIAL, mage.cards.h.HypnoticSpecter.class)); - cards.add(new SetCardInfo("Incinerate", 26, Rarity.SPECIAL, mage.cards.i.Incinerate.class)); - cards.add(new SetCardInfo("Infest", 43, Rarity.SPECIAL, mage.cards.i.Infest.class)); - cards.add(new SetCardInfo("Lightning Bolt", 40, Rarity.SPECIAL, mage.cards.l.LightningBolt.class)); - cards.add(new SetCardInfo("Lightning Helix", 16, Rarity.SPECIAL, mage.cards.l.LightningHelix.class)); - cards.add(new SetCardInfo("Mana Leak", 8, Rarity.SPECIAL, mage.cards.m.ManaLeak.class)); - cards.add(new SetCardInfo("Mana Tithe", 27, Rarity.SPECIAL, mage.cards.m.ManaTithe.class)); - cards.add(new SetCardInfo("Mortify", 19, Rarity.SPECIAL, mage.cards.m.Mortify.class)); - cards.add(new SetCardInfo("Nameless Inversion", 34, Rarity.SPECIAL, mage.cards.n.NamelessInversion.class)); - cards.add(new SetCardInfo("Negate", 38, Rarity.SPECIAL, mage.cards.n.Negate.class)); - cards.add(new SetCardInfo("Oxidize", 7, Rarity.SPECIAL, mage.cards.o.Oxidize.class)); - cards.add(new SetCardInfo("Ponder", 29, Rarity.SPECIAL, mage.cards.p.Ponder.class)); + cards.add(new SetCardInfo("Incinerate", 26, Rarity.SPECIAL, mage.cards.i.Incinerate.class, graphicInfo)); + cards.add(new SetCardInfo("Infest", 43, Rarity.SPECIAL, mage.cards.i.Infest.class, graphicInfo)); + cards.add(new SetCardInfo("Lightning Bolt", 40, Rarity.SPECIAL, mage.cards.l.LightningBolt.class, graphicInfo)); + cards.add(new SetCardInfo("Lightning Helix", 16, Rarity.SPECIAL, mage.cards.l.LightningHelix.class, graphicInfo)); + cards.add(new SetCardInfo("Mana Leak", 8, Rarity.SPECIAL, mage.cards.m.ManaLeak.class, graphicInfo)); + cards.add(new SetCardInfo("Mana Tithe", 27, Rarity.SPECIAL, mage.cards.m.ManaTithe.class, graphicInfo)); + cards.add(new SetCardInfo("Mortify", 19, Rarity.SPECIAL, mage.cards.m.Mortify.class, graphicInfo)); + cards.add(new SetCardInfo("Nameless Inversion", 34, Rarity.SPECIAL, mage.cards.n.NamelessInversion.class, graphicInfo)); + cards.add(new SetCardInfo("Negate", 38, Rarity.SPECIAL, mage.cards.n.Negate.class, graphicInfo)); + cards.add(new SetCardInfo("Oxidize", 7, Rarity.SPECIAL, mage.cards.o.Oxidize.class, graphicInfo)); + cards.add(new SetCardInfo("Ponder", 29, Rarity.SPECIAL, mage.cards.p.Ponder.class, graphicInfo)); cards.add(new SetCardInfo("Powder Keg", 3, Rarity.SPECIAL, mage.cards.p.PowderKeg.class)); - cards.add(new SetCardInfo("Psionic Blast", 20, Rarity.COMMON, mage.cards.p.PsionicBlast.class)); + cards.add(new SetCardInfo("Psionic Blast", 20, Rarity.SPECIAL, mage.cards.p.PsionicBlast.class, graphicInfo)); cards.add(new SetCardInfo("Psychatog", 4, Rarity.SPECIAL, mage.cards.p.Psychatog.class)); - cards.add(new SetCardInfo("Putrefy", 14, Rarity.SPECIAL, mage.cards.p.Putrefy.class)); - cards.add(new SetCardInfo("Pyroclasm", 12, Rarity.SPECIAL, mage.cards.p.Pyroclasm.class)); - cards.add(new SetCardInfo("Rampant Growth", 37, Rarity.SPECIAL, mage.cards.r.RampantGrowth.class)); - cards.add(new SetCardInfo("Reciprocate", 9, Rarity.SPECIAL, mage.cards.r.Reciprocate.class)); - cards.add(new SetCardInfo("Recollect", 23, Rarity.SPECIAL, mage.cards.r.Recollect.class)); - cards.add(new SetCardInfo("Remove Soul", 35, Rarity.SPECIAL, mage.cards.r.RemoveSoul.class)); - cards.add(new SetCardInfo("Searing Blaze", 53, Rarity.SPECIAL, mage.cards.s.SearingBlaze.class)); - cards.add(new SetCardInfo("Sign in Blood", 42, Rarity.SPECIAL, mage.cards.s.SignInBlood.class)); - cards.add(new SetCardInfo("Terminate", 39, Rarity.SPECIAL, mage.cards.t.Terminate.class)); - cards.add(new SetCardInfo("Terror", 5, Rarity.SPECIAL, mage.cards.t.Terror.class)); - cards.add(new SetCardInfo("Tidings", 25, Rarity.SPECIAL, mage.cards.t.Tidings.class)); - cards.add(new SetCardInfo("Treasure Hunt", 52, Rarity.SPECIAL, mage.cards.t.TreasureHunt.class)); - cards.add(new SetCardInfo("Unmake", 33, Rarity.SPECIAL, mage.cards.u.Unmake.class)); + cards.add(new SetCardInfo("Putrefy", 14, Rarity.SPECIAL, mage.cards.p.Putrefy.class, graphicInfo)); + cards.add(new SetCardInfo("Pyroclasm", 12, Rarity.SPECIAL, mage.cards.p.Pyroclasm.class, graphicInfo)); + cards.add(new SetCardInfo("Rampant Growth", 37, Rarity.SPECIAL, mage.cards.r.RampantGrowth.class, graphicInfo)); + cards.add(new SetCardInfo("Reciprocate", 9, Rarity.SPECIAL, mage.cards.r.Reciprocate.class, graphicInfo)); + cards.add(new SetCardInfo("Recollect", 23, Rarity.SPECIAL, mage.cards.r.Recollect.class, graphicInfo)); + cards.add(new SetCardInfo("Remove Soul", 35, Rarity.SPECIAL, mage.cards.r.RemoveSoul.class, graphicInfo)); + cards.add(new SetCardInfo("Searing Blaze", 53, Rarity.SPECIAL, mage.cards.s.SearingBlaze.class, graphicInfo)); + cards.add(new SetCardInfo("Sign in Blood", 42, Rarity.SPECIAL, mage.cards.s.SignInBlood.class, graphicInfo)); + cards.add(new SetCardInfo("Terminate", 39, Rarity.SPECIAL, mage.cards.t.Terminate.class, graphicInfo)); + cards.add(new SetCardInfo("Terror", 5, Rarity.SPECIAL, mage.cards.t.Terror.class, graphicInfo)); + cards.add(new SetCardInfo("Tidings", 25, Rarity.SPECIAL, mage.cards.t.Tidings.class, graphicInfo)); + cards.add(new SetCardInfo("Treasure Hunt", 52, Rarity.SPECIAL, mage.cards.t.TreasureHunt.class, graphicInfo)); + cards.add(new SetCardInfo("Unmake", 33, Rarity.SPECIAL, mage.cards.u.Unmake.class, graphicInfo)); cards.add(new SetCardInfo("Voidmage Prodigy", 2, Rarity.SPECIAL, mage.cards.v.VoidmageProdigy.class)); - cards.add(new SetCardInfo("Volcanic Fallout", 44, Rarity.SPECIAL, mage.cards.v.VolcanicFallout.class)); - cards.add(new SetCardInfo("Wasteland", 1, Rarity.SPECIAL, mage.cards.w.Wasteland.class)); - cards.add(new SetCardInfo("Wrath of God", 17, Rarity.SPECIAL, mage.cards.w.WrathOfGod.class)); - cards.add(new SetCardInfo("Zombify", 15, Rarity.SPECIAL, mage.cards.z.Zombify.class)); + cards.add(new SetCardInfo("Volcanic Fallout", 44, Rarity.SPECIAL, mage.cards.v.VolcanicFallout.class, graphicInfo)); + cards.add(new SetCardInfo("Wasteland", 1, Rarity.SPECIAL, mage.cards.w.Wasteland.class, graphicInfo)); + cards.add(new SetCardInfo("Wrath of God", 17, Rarity.SPECIAL, mage.cards.w.WrathOfGod.class, graphicInfo)); + cards.add(new SetCardInfo("Zombify", 15, Rarity.SPECIAL, mage.cards.z.Zombify.class, graphicInfo)); } } diff --git a/Mage.Sets/src/mage/sets/MasterpieceSeries.java b/Mage.Sets/src/mage/sets/MasterpieceSeries.java index 9145913fa1e..756a7ffd28d 100644 --- a/Mage.Sets/src/mage/sets/MasterpieceSeries.java +++ b/Mage.Sets/src/mage/sets/MasterpieceSeries.java @@ -27,11 +27,11 @@ */ package mage.sets; -import mage.cards.ExpansionSet; -import mage.constants.SetType; -import mage.constants.Rarity; import mage.cards.CardGraphicInfo; +import mage.cards.ExpansionSet; import mage.cards.FrameStyle; +import mage.constants.Rarity; +import mage.constants.SetType; /** * @@ -49,72 +49,60 @@ public class MasterpieceSeries extends ExpansionSet { super("Masterpiece Series", "MPS", ExpansionSet.buildDate(2016, 9, 30), SetType.PROMOTIONAL); this.hasBoosters = false; this.hasBasicLands = false; - cards.add(new SetCardInfo("Aether Vial", 6, Rarity.MYTHIC, mage.cards.a.AetherVial.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Arcbound Ravager", 31, Rarity.MYTHIC, mage.cards.a.ArcboundRavager.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Black Vise", 32, Rarity.MYTHIC, mage.cards.b.BlackVise.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Cataclysmic Gearhulk", 1, Rarity.MYTHIC, mage.cards.c.CataclysmicGearhulk.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Chalice of the Void", 33, Rarity.MYTHIC, mage.cards.c.ChaliceOfTheVoid.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Champion's Helm", 7, Rarity.MYTHIC, mage.cards.c.ChampionsHelm.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Chromatic Lantern", 8, Rarity.MYTHIC, mage.cards.c.ChromaticLantern.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, - false))); - cards.add(new SetCardInfo("Chrome Mox", 9, Rarity.MYTHIC, mage.cards.c.ChromeMox.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Cloudstone Curio", 10, Rarity.MYTHIC, mage.cards.c.CloudstoneCurio.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, - false))); - cards.add(new SetCardInfo("Combustible Gearhulk", 2, Rarity.MYTHIC, mage.cards.c.CombustibleGearhulk.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Crucible of Worlds", 11, Rarity.MYTHIC, mage.cards.c.CrucibleOfWorlds.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, - false))); - cards.add(new SetCardInfo("Defense Grid", 34, Rarity.MYTHIC, mage.cards.d.DefenseGrid.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Duplicant", 35, Rarity.MYTHIC, mage.cards.d.Duplicant.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Engineered Explosives", 36, Rarity.MYTHIC, mage.cards.e.EngineeredExplosives.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Ensnaring Bridge", 37, Rarity.MYTHIC, mage.cards.e.EnsnaringBridge.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Extraplanar Lens", 38, Rarity.MYTHIC, mage.cards.e.ExtraplanarLens.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Gauntlet of Power", 12, Rarity.MYTHIC, mage.cards.g.GauntletOfPower.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, - false))); - cards.add(new SetCardInfo("Grindstone", 39, Rarity.MYTHIC, mage.cards.g.Grindstone.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Hangarback Walker", 13, Rarity.MYTHIC, mage.cards.h.HangarbackWalker.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, - false))); - cards.add(new SetCardInfo("Lightning Greaves", 14, Rarity.MYTHIC, mage.cards.l.LightningGreaves.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, - false))); - cards.add(new SetCardInfo("Lotus Petal", 15, Rarity.MYTHIC, mage.cards.l.LotusPetal.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Mana Crypt", 16, Rarity.MYTHIC, mage.cards.m.ManaCrypt.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Mana Vault", 17, Rarity.MYTHIC, mage.cards.m.ManaVault.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Meekstone", 40, Rarity.MYTHIC, mage.cards.m.Meekstone.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Mind's Eye", 18, Rarity.MYTHIC, mage.cards.m.MindsEye.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Mox Opal", 19, Rarity.MYTHIC, mage.cards.m.MoxOpal.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Noxious Gearhulk", 3, Rarity.MYTHIC, mage.cards.n.NoxiousGearhulk.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Oblivion Stone", 41, Rarity.MYTHIC, mage.cards.o.OblivionStone.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Ornithopter", 42, Rarity.MYTHIC, mage.cards.o.Ornithopter.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Painter's Servant", 20, Rarity.MYTHIC, mage.cards.p.PaintersServant.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, - false))); + CardGraphicInfo cardGraphicInfo = new CardGraphicInfo(FrameStyle.KLD_INVENTION, false); + cards.add(new SetCardInfo("Aether Vial", 6, Rarity.MYTHIC, mage.cards.a.AetherVial.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Arcbound Ravager", 31, Rarity.MYTHIC, mage.cards.a.ArcboundRavager.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Black Vise", 32, Rarity.MYTHIC, mage.cards.b.BlackVise.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Cataclysmic Gearhulk", 1, Rarity.MYTHIC, mage.cards.c.CataclysmicGearhulk.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Chalice of the Void", 33, Rarity.MYTHIC, mage.cards.c.ChaliceOfTheVoid.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Champion's Helm", 7, Rarity.MYTHIC, mage.cards.c.ChampionsHelm.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Chromatic Lantern", 8, Rarity.MYTHIC, mage.cards.c.ChromaticLantern.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Chrome Mox", 9, Rarity.MYTHIC, mage.cards.c.ChromeMox.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Cloudstone Curio", 10, Rarity.MYTHIC, mage.cards.c.CloudstoneCurio.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Combustible Gearhulk", 2, Rarity.MYTHIC, mage.cards.c.CombustibleGearhulk.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Crucible of Worlds", 11, Rarity.MYTHIC, mage.cards.c.CrucibleOfWorlds.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Defense Grid", 34, Rarity.MYTHIC, mage.cards.d.DefenseGrid.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Duplicant", 35, Rarity.MYTHIC, mage.cards.d.Duplicant.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Engineered Explosives", 36, Rarity.MYTHIC, mage.cards.e.EngineeredExplosives.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Ensnaring Bridge", 37, Rarity.MYTHIC, mage.cards.e.EnsnaringBridge.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Extraplanar Lens", 38, Rarity.MYTHIC, mage.cards.e.ExtraplanarLens.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Gauntlet of Power", 12, Rarity.MYTHIC, mage.cards.g.GauntletOfPower.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Grindstone", 39, Rarity.MYTHIC, mage.cards.g.Grindstone.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Hangarback Walker", 13, Rarity.MYTHIC, mage.cards.h.HangarbackWalker.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Lightning Greaves", 14, Rarity.MYTHIC, mage.cards.l.LightningGreaves.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Lotus Petal", 15, Rarity.MYTHIC, mage.cards.l.LotusPetal.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Mana Crypt", 16, Rarity.MYTHIC, mage.cards.m.ManaCrypt.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Mana Vault", 17, Rarity.MYTHIC, mage.cards.m.ManaVault.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Meekstone", 40, Rarity.MYTHIC, mage.cards.m.Meekstone.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Mind's Eye", 18, Rarity.MYTHIC, mage.cards.m.MindsEye.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Mox Opal", 19, Rarity.MYTHIC, mage.cards.m.MoxOpal.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Noxious Gearhulk", 3, Rarity.MYTHIC, mage.cards.n.NoxiousGearhulk.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Oblivion Stone", 41, Rarity.MYTHIC, mage.cards.o.OblivionStone.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Ornithopter", 42, Rarity.MYTHIC, mage.cards.o.Ornithopter.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Painter's Servant", 20, Rarity.MYTHIC, mage.cards.p.PaintersServant.class, cardGraphicInfo)); cards.add(new SetCardInfo("Paradox Engine", 43, Rarity.MYTHIC, mage.cards.p.ParadoxEngine.class)); - cards.add(new SetCardInfo("Pithing Needle", 44, Rarity.MYTHIC, mage.cards.p.PithingNeedle.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); + cards.add(new SetCardInfo("Pithing Needle", 44, Rarity.MYTHIC, mage.cards.p.PithingNeedle.class, cardGraphicInfo)); cards.add(new SetCardInfo("Planar Bridge", 45, Rarity.MYTHIC, mage.cards.p.PlanarBridge.class)); - cards.add(new SetCardInfo("Platinum Angel", 46, Rarity.MYTHIC, mage.cards.p.PlatinumAngel.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Rings of Brighthearth", 21, Rarity.MYTHIC, mage.cards.r.RingsOfBrighthearth.class, new CardGraphicInfo( - FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Scroll Rack", 22, Rarity.MYTHIC, mage.cards.s.ScrollRack.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Sculpting Steel", 23, Rarity.MYTHIC, mage.cards.s.SculptingSteel.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Solemn Simulacrum", 25, Rarity.MYTHIC, mage.cards.s.SolemnSimulacrum.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, - false))); - cards.add(new SetCardInfo("Sol Ring", 24, Rarity.MYTHIC, mage.cards.s.SolRing.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Sphere of Resistance", 47, Rarity.MYTHIC, mage.cards.s.SphereOfResistance.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Staff of Domination", 48, Rarity.MYTHIC, mage.cards.s.StaffOfDomination.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Static Orb", 26, Rarity.MYTHIC, mage.cards.s.StaticOrb.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Steel Overseer", 27, Rarity.MYTHIC, mage.cards.s.SteelOverseer.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Sundering Titan", 49, Rarity.MYTHIC, mage.cards.s.SunderingTitan.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Sword of Body and Mind", 50, Rarity.MYTHIC, mage.cards.s.SwordOfBodyAndMind.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Sword of Feast and Famine", 28, Rarity.MYTHIC, mage.cards.s.SwordOfFeastAndFamine.class, new CardGraphicInfo( - FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Sword of Fire and Ice", 29, Rarity.MYTHIC, mage.cards.s.SwordOfFireAndIce.class, new CardGraphicInfo( - FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Sword of Light and Shadow", 30, Rarity.MYTHIC, mage.cards.s.SwordOfLightAndShadow.class, new CardGraphicInfo( - FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Sword of War and Peace", 51, Rarity.MYTHIC, mage.cards.s.SwordOfWarAndPeace.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Torrential Gearhulk", 4, Rarity.MYTHIC, mage.cards.t.TorrentialGearhulk.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Trinisphere", 52, Rarity.MYTHIC, mage.cards.t.Trinisphere.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Vedalken Shackles", 53, Rarity.MYTHIC, mage.cards.v.VedalkenShackles.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); - cards.add(new SetCardInfo("Verdurous Gearhulk", 5, Rarity.MYTHIC, mage.cards.v.VerdurousGearhulk.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, - false))); - cards.add(new SetCardInfo("Wurmcoil Engine", 54, Rarity.MYTHIC, mage.cards.w.WurmcoilEngine.class, new CardGraphicInfo(FrameStyle.KLD_INVENTION, false))); + cards.add(new SetCardInfo("Platinum Angel", 46, Rarity.MYTHIC, mage.cards.p.PlatinumAngel.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Rings of Brighthearth", 21, Rarity.MYTHIC, mage.cards.r.RingsOfBrighthearth.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Scroll Rack", 22, Rarity.MYTHIC, mage.cards.s.ScrollRack.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Sculpting Steel", 23, Rarity.MYTHIC, mage.cards.s.SculptingSteel.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Solemn Simulacrum", 25, Rarity.MYTHIC, mage.cards.s.SolemnSimulacrum.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Sol Ring", 24, Rarity.MYTHIC, mage.cards.s.SolRing.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Sphere of Resistance", 47, Rarity.MYTHIC, mage.cards.s.SphereOfResistance.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Staff of Domination", 48, Rarity.MYTHIC, mage.cards.s.StaffOfDomination.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Static Orb", 26, Rarity.MYTHIC, mage.cards.s.StaticOrb.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Steel Overseer", 27, Rarity.MYTHIC, mage.cards.s.SteelOverseer.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Sundering Titan", 49, Rarity.MYTHIC, mage.cards.s.SunderingTitan.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Sword of Body and Mind", 50, Rarity.MYTHIC, mage.cards.s.SwordOfBodyAndMind.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Sword of Feast and Famine", 28, Rarity.MYTHIC, mage.cards.s.SwordOfFeastAndFamine.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Sword of Fire and Ice", 29, Rarity.MYTHIC, mage.cards.s.SwordOfFireAndIce.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Sword of Light and Shadow", 30, Rarity.MYTHIC, mage.cards.s.SwordOfLightAndShadow.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Sword of War and Peace", 51, Rarity.MYTHIC, mage.cards.s.SwordOfWarAndPeace.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Torrential Gearhulk", 4, Rarity.MYTHIC, mage.cards.t.TorrentialGearhulk.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Trinisphere", 52, Rarity.MYTHIC, mage.cards.t.Trinisphere.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Vedalken Shackles", 53, Rarity.MYTHIC, mage.cards.v.VedalkenShackles.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Verdurous Gearhulk", 5, Rarity.MYTHIC, mage.cards.v.VerdurousGearhulk.class, cardGraphicInfo)); + cards.add(new SetCardInfo("Wurmcoil Engine", 54, Rarity.MYTHIC, mage.cards.w.WurmcoilEngine.class, cardGraphicInfo)); } } diff --git a/Mage/src/main/java/mage/cards/FrameStyle.java b/Mage/src/main/java/mage/cards/FrameStyle.java index add2795cc52..13a4dae88bd 100644 --- a/Mage/src/main/java/mage/cards/FrameStyle.java +++ b/Mage/src/main/java/mage/cards/FrameStyle.java @@ -26,6 +26,10 @@ public enum FrameStyle { * Zenkikar full art lands */ ZEN_FULL_ART_BASIC(BorderType.MOD, true), + /** + * Magic Player Rewards full art cards + */ + MPRP_FULL_ART_BASIC(BorderType.MOD, true), /** * Unhinged full art lands */ diff --git a/Mage/src/main/java/mage/cards/repository/ExpansionRepository.java b/Mage/src/main/java/mage/cards/repository/ExpansionRepository.java index 42b699aca27..c8c23f729e5 100644 --- a/Mage/src/main/java/mage/cards/repository/ExpansionRepository.java +++ b/Mage/src/main/java/mage/cards/repository/ExpansionRepository.java @@ -28,7 +28,7 @@ public enum ExpansionRepository { private static final String JDBC_URL = "jdbc:h2:file:./db/cards.h2;AUTO_SERVER=TRUE"; private static final String VERSION_ENTITY_NAME = "expansion"; private static final long EXPANSION_DB_VERSION = 5; - private static final long EXPANSION_CONTENT_VERSION = 11; + private static final long EXPANSION_CONTENT_VERSION = 12; private Dao expansionDao; From b1a51ce7cf21810a1a6edfb3c1adb210df95f09e Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 21 Jan 2017 01:10:37 +0100 Subject: [PATCH 21/44] * Lightning Runner - Fixed a bug of the optional untap and add combat phase effect. --- .../src/mage/cards/l/LightningRunner.java | 18 +++++++++++------- .../GetEnergyCountersControllerEffect.java | 8 ++++---- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Mage.Sets/src/mage/cards/l/LightningRunner.java b/Mage.Sets/src/mage/cards/l/LightningRunner.java index 4bb0e1dd231..3c992aee573 100644 --- a/Mage.Sets/src/mage/cards/l/LightningRunner.java +++ b/Mage.Sets/src/mage/cards/l/LightningRunner.java @@ -87,8 +87,8 @@ class LightningRunnerEffect extends OneShotEffect { LightningRunnerEffect() { super(Outcome.Benefit); - staticText = "you get {E}{E}, then you may pay {E}{E}{E}{E}{E}{E}{E}{E}. If you do, " + - "untap all creatures you control and after this phase, there is an additional combat phase"; + staticText = "you get {E}{E}, then you may pay {E}{E}{E}{E}{E}{E}{E}{E}. If you do, " + + "untap all creatures you control and after this phase, there is an additional combat phase"; } LightningRunnerEffect(final LightningRunnerEffect effect) { @@ -100,11 +100,15 @@ class LightningRunnerEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { new GetEnergyCountersControllerEffect(2).apply(game, source); - if (controller.getCounters().getCount(CounterType.ENERGY) > 5) { - Cost cost = new PayEnergyCost(6); - if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), true)) { - new UntapAllControllerEffect(new FilterControlledCreaturePermanent(), "untap all creatures you control").apply(game, source); - new AdditionalCombatPhaseEffect("and after this phase, there is an additional combat phase").apply(game, source); + if (controller.getCounters().getCount(CounterType.ENERGY) > 7) { + Cost cost = new PayEnergyCost(8); + if (controller.chooseUse(outcome, + "Pay {E}{E}{E}{E}{E}{E}{E}{E} to use this? ", + "Untap all creatures you control and after this phase, there is an additional combat phase.", + "Yes", "No", source, game) + && cost.pay(source, game, source.getSourceId(), source.getControllerId(), true)) { + new UntapAllControllerEffect(new FilterControlledCreaturePermanent()).apply(game, source); + new AdditionalCombatPhaseEffect().apply(game, source); } } return true; diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/GetEnergyCountersControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/GetEnergyCountersControllerEffect.java index 3cf03ea452b..b2555462216 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/GetEnergyCountersControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/GetEnergyCountersControllerEffect.java @@ -61,9 +61,9 @@ public class GetEnergyCountersControllerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - return player.addCounters(CounterType.ENERGY.createInstance(value.calculate(game, source, this)), game); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + return controller.addCounters(CounterType.ENERGY.createInstance(value.calculate(game, source, this)), game); } return false; } @@ -72,7 +72,7 @@ public class GetEnergyCountersControllerEffect extends OneShotEffect { if (!staticText.isEmpty()) { return; } - + StringBuilder sb = new StringBuilder(); sb.append("you get "); int val = 1; From f5b5014b2d87049b8323ddc876e07e8795f63ed4 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 21 Jan 2017 01:12:10 +0100 Subject: [PATCH 22/44] Fixed a bug from addding new java Optionals constructs that prevented games to start. --- .../java/mage/server/TableController.java | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index 28f1be09b7b..21d6f8aec6c 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -27,6 +27,14 @@ */ package mage.server; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; import mage.MageException; import mage.cards.decks.Deck; import mage.cards.decks.DeckCardLists; @@ -60,15 +68,6 @@ import mage.server.util.ThreadExecutor; import mage.view.ChatMessage; import org.apache.log4j.Logger; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - /** * @author BetaSteward_at_googlemail.com */ @@ -96,10 +95,9 @@ public class TableController { if (userId != null) { Optional user = UserManager.getInstance().getUser(userId); // TODO: Handle if user == null - if(user.isPresent()) { + if (user.isPresent()) { controllerName = user.get().getName(); - } - else{ + } else { controllerName = "undefined"; } } else { @@ -578,10 +576,10 @@ public class TableController { GameManager.getInstance().createGameSession(match.getGame(), userPlayerMap, table.getId(), choosingPlayerId, gameOptions); String creator = null; StringBuilder opponent = new StringBuilder(); - for (Entry entry : userPlayerMap.entrySet()) { // no AI players + for (Entry entry : userPlayerMap.entrySet()) { // do only for no AI players if (match.getPlayer(entry.getValue()) != null && !match.getPlayer(entry.getValue()).hasQuit()) { Optional _user = UserManager.getInstance().getUser(entry.getKey()); - if (!_user.isPresent()) { + if (_user.isPresent()) { User user = _user.get(); user.ccGameStarted(match.getGame().getId(), entry.getValue()); @@ -978,8 +976,8 @@ public class TableController { void cleanUp() { if (!table.isTournamentSubTable()) { for (Map.Entry entry : userPlayerMap.entrySet()) { - UserManager.getInstance().getUser(entry.getKey()).ifPresent(user -> - user.removeTable(entry.getValue())); + UserManager.getInstance().getUser(entry.getKey()).ifPresent(user + -> user.removeTable(entry.getValue())); } } From cdf05069d282f763114bf960334be2a45f5c4e85 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 21 Jan 2017 01:27:35 +0100 Subject: [PATCH 23/44] Fixed another problem of symbold downloading. --- .../java/org/mage/plugins/card/dl/sources/GathererSets.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java index 9a5aa9834d7..5d63f8ee150 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSets.java @@ -127,7 +127,7 @@ public class GathererSets implements Iterable { public Iterator iterator() { Calendar c = Calendar.getInstance(); c.setTime(new Date()); - c.add(Calendar.DATE, -14); + c.add(Calendar.DATE, +14); // Try to load the symbols eralies 14 days before release date Date compareDate = c.getTime(); ArrayList jobs = new ArrayList<>(); for (String symbol : symbols) { From fe4abd26c96fc916a2639120a2e1a92ffc38b399 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sat, 21 Jan 2017 01:33:46 +0100 Subject: [PATCH 24/44] Fixed a bug of the Revolt ability word that prevented that ot triggered always correctly. --- .../mage/abilities/condition/common/RevoltCondition.java | 2 +- Mage/src/main/java/mage/watchers/common/RevoltWatcher.java | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Mage/src/main/java/mage/abilities/condition/common/RevoltCondition.java b/Mage/src/main/java/mage/abilities/condition/common/RevoltCondition.java index 799a7362f7c..33d1ce9744a 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/RevoltCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/RevoltCondition.java @@ -45,7 +45,7 @@ public class RevoltCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - RevoltWatcher watcher = (RevoltWatcher) game.getState().getWatchers().get("Revolt"); + RevoltWatcher watcher = (RevoltWatcher) game.getState().getWatchers().get(RevoltWatcher.class.getName()); return watcher != null && watcher.revoltActive(source.getControllerId()); } diff --git a/Mage/src/main/java/mage/watchers/common/RevoltWatcher.java b/Mage/src/main/java/mage/watchers/common/RevoltWatcher.java index 549e3e5bc92..63f9d33717f 100644 --- a/Mage/src/main/java/mage/watchers/common/RevoltWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/RevoltWatcher.java @@ -25,7 +25,6 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.watchers.common; import java.util.HashSet; @@ -49,11 +48,12 @@ public class RevoltWatcher extends Watcher { private final Set revoltActivePlayerIds = new HashSet<>(0); public RevoltWatcher() { - super("Revolt", WatcherScope.GAME); + super(RevoltWatcher.class.getName(), WatcherScope.GAME); } public RevoltWatcher(final RevoltWatcher watcher) { super(watcher); + this.revoltActivePlayerIds.addAll(watcher.revoltActivePlayerIds); } @Override @@ -78,8 +78,6 @@ public class RevoltWatcher extends Watcher { revoltActivePlayerIds.clear(); } - - @Override public RevoltWatcher copy() { return new RevoltWatcher(this); From 8969157ce88c2ee752201a902ab679bef59d2ca5 Mon Sep 17 00:00:00 2001 From: Galatolol Date: Sat, 21 Jan 2017 14:26:04 +0100 Subject: [PATCH 25/44] Added 5 cards --- .../src/mage/cards/b/BlanketOfNight.java | 70 ++++++++++++++++ Mage.Sets/src/mage/cards/g/GhostHounds.java | 79 +++++++++++++++++++ Mage.Sets/src/mage/cards/m/Morale.java | 62 +++++++++++++++ Mage.Sets/src/mage/cards/s/SpiritShackle.java | 76 ++++++++++++++++++ .../mage/cards/u/UrborgTombOfYawgmoth.java | 38 +-------- Mage.Sets/src/mage/cards/w/WallOfLava.java | 70 ++++++++++++++++ Mage.Sets/src/mage/sets/FourthEdition.java | 2 + Mage.Sets/src/mage/sets/Homelands.java | 1 + Mage.Sets/src/mage/sets/IceAge.java | 1 + Mage.Sets/src/mage/sets/Legends.java | 3 +- .../src/mage/sets/MastersEditionIII.java | 1 + Mage.Sets/src/mage/sets/TheDark.java | 5 +- Mage.Sets/src/mage/sets/Visions.java | 1 + .../continuous/AddCardSubtypeAllEffect.java | 75 ++++++++++++++++++ 14 files changed, 445 insertions(+), 39 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/b/BlanketOfNight.java create mode 100644 Mage.Sets/src/mage/cards/g/GhostHounds.java create mode 100644 Mage.Sets/src/mage/cards/m/Morale.java create mode 100644 Mage.Sets/src/mage/cards/s/SpiritShackle.java create mode 100644 Mage.Sets/src/mage/cards/w/WallOfLava.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardSubtypeAllEffect.java diff --git a/Mage.Sets/src/mage/cards/b/BlanketOfNight.java b/Mage.Sets/src/mage/cards/b/BlanketOfNight.java new file mode 100644 index 00000000000..5807f7a5a6d --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlanketOfNight.java @@ -0,0 +1,70 @@ +/* + * 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.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.abilities.effects.common.continuous.AddCardSubtypeAllEffect; +import mage.constants.CardType; +import mage.constants.DependencyType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.common.FilterLandPermanent; + +/** + * + * @author Galatolol + */ +public class BlanketOfNight extends CardImpl { + + public BlanketOfNight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{B}"); + + + // Each land is a Swamp in addition to its other land types. + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(new BlackManaAbility(), Duration.WhileOnBattlefield, new FilterLandPermanent(), + "Each land is a Swamp in addition to its other land types")); + ability.addEffect(new AddCardSubtypeAllEffect(new FilterLandPermanent(), "Swamp", DependencyType.BecomeSwamp)); + this.addAbility(ability); + } + + public BlanketOfNight(final BlanketOfNight card) { + super(card); + } + + @Override + public BlanketOfNight copy() { + return new BlanketOfNight(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GhostHounds.java b/Mage.Sets/src/mage/cards/g/GhostHounds.java new file mode 100644 index 00000000000..5dbef9e482a --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GhostHounds.java @@ -0,0 +1,79 @@ +/* + * 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.g; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.common.BlocksOrBecomesBlockedTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; + +/** + * + * @author Galatolol + */ +public class GhostHounds extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("white creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + + public GhostHounds(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add("Hound"); + this.subtype.add("Spirit"); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Whenever Ghost Hounds blocks or becomes blocked by a white creature, Ghost Hounds gains first strike until end of turn. + this.addAbility(new BlocksOrBecomesBlockedTriggeredAbility(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn), filter, false)); + + } + + public GhostHounds(final GhostHounds card) { + super(card); + } + @Override + public GhostHounds copy() { + return new GhostHounds(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/Morale.java b/Mage.Sets/src/mage/cards/m/Morale.java new file mode 100644 index 00000000000..93b40bb0f26 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/Morale.java @@ -0,0 +1,62 @@ +/* + * 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.m; + +import java.util.UUID; + +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.common.FilterAttackingCreature; + +/** + * + * @author Galatolol + */ +public class Morale extends CardImpl { + + public Morale(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}{W}"); + + + // Attacking creatures get +1/+1 until end of turn. + this.getSpellAbility().addEffect(new BoostAllEffect(1, 1, Duration.EndOfTurn, new FilterAttackingCreature("Attacking creatures"), false)); + + } + + public Morale(final Morale card) { + super(card); + } + + @Override + public Morale copy() { + return new Morale(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpiritShackle.java b/Mage.Sets/src/mage/cards/s/SpiritShackle.java new file mode 100644 index 00000000000..d4c64a56972 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiritShackle.java @@ -0,0 +1,76 @@ +/* + * 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.s; + +import java.util.UUID; + +import mage.abilities.common.BecomesTappedAttachedTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersAttachedEffect; +import mage.counters.BoostCounter; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.effects.common.AttachEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author Galatolol + */ +public class SpiritShackle extends CardImpl { + + public SpiritShackle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}{B}"); + + this.subtype.add("Aura"); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Whenever enchanted creature becomes tapped, put a -0/-2 counter on it. + this.addAbility(new BecomesTappedAttachedTriggeredAbility(new AddCountersAttachedEffect(new BoostCounter(0, -2), "it"), "enchanted creature")); + + } + + public SpiritShackle(final SpiritShackle card) { + super(card); + } + + @Override + public SpiritShackle copy() { + return new SpiritShackle(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UrborgTombOfYawgmoth.java b/Mage.Sets/src/mage/cards/u/UrborgTombOfYawgmoth.java index 4d3a9e52235..5c0818e58c3 100644 --- a/Mage.Sets/src/mage/cards/u/UrborgTombOfYawgmoth.java +++ b/Mage.Sets/src/mage/cards/u/UrborgTombOfYawgmoth.java @@ -32,14 +32,12 @@ import java.util.UUID; import mage.constants.*; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.mana.BlackManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.filter.common.FilterLandPermanent; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.abilities.effects.common.continuous.AddCardSubtypeAllEffect; /** * @@ -54,7 +52,7 @@ public class UrborgTombOfYawgmoth extends CardImpl { // Each land is a Swamp in addition to its other land types. Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(new BlackManaAbility(), Duration.WhileOnBattlefield, new FilterLandPermanent(), "Each land is a Swamp in addition to its other land types")); - ability.addEffect(new AddCardSubtypeAllEffect()); + ability.addEffect(new AddCardSubtypeAllEffect(new FilterLandPermanent(), "Swamp", DependencyType.BecomeSwamp)); this.addAbility(ability); } @@ -68,35 +66,3 @@ public class UrborgTombOfYawgmoth extends CardImpl { return new UrborgTombOfYawgmoth(this); } } - -class AddCardSubtypeAllEffect extends ContinuousEffectImpl { - - private static final FilterLandPermanent filter = new FilterLandPermanent(); - private static final String addedSubtype = "Swamp"; - - public AddCardSubtypeAllEffect() { - super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); - staticText = ""; - addDependencyType(DependencyType.BecomeSwamp); - } - - public AddCardSubtypeAllEffect(final AddCardSubtypeAllEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { - if (perm != null && !perm.getSubtype(game).contains(addedSubtype)) { - perm.getSubtype(game).add(addedSubtype); - } - } - return true; - } - - @Override - public AddCardSubtypeAllEffect copy() { - return new AddCardSubtypeAllEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/w/WallOfLava.java b/Mage.Sets/src/mage/cards/w/WallOfLava.java new file mode 100644 index 00000000000..9c032f6f497 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WallOfLava.java @@ -0,0 +1,70 @@ +/* + * 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.w; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; + +/** + * + * @author anonymous + */ +public class WallOfLava extends CardImpl { + + public WallOfLava(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); + + this.subtype.add("Wall"); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // {R}: Wall of Lava gets +1/+1 until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl("{R}"))); + } + + public WallOfLava(final WallOfLava card) { + super(card); + } + + @Override + public WallOfLava copy() { + return new WallOfLava(this); + } +} diff --git a/Mage.Sets/src/mage/sets/FourthEdition.java b/Mage.Sets/src/mage/sets/FourthEdition.java index 2e819a3c2ae..6efaa0aa398 100644 --- a/Mage.Sets/src/mage/sets/FourthEdition.java +++ b/Mage.Sets/src/mage/sets/FourthEdition.java @@ -254,6 +254,7 @@ public class FourthEdition extends ExpansionSet { cards.add(new SetCardInfo("Mind Twist", 31, Rarity.RARE, mage.cards.m.MindTwist.class)); cards.add(new SetCardInfo("Mishra's Factory", 181, Rarity.UNCOMMON, mage.cards.m.MishrasFactory.class)); cards.add(new SetCardInfo("Mons's Goblin Raiders", 231, Rarity.COMMON, mage.cards.m.MonssGoblinRaiders.class)); + cards.add(new SetCardInfo("Morale", 288, Rarity.COMMON, mage.cards.m.Morale.class)); cards.add(new SetCardInfo("Mountain", 182, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(null, true))); cards.add(new SetCardInfo("Mountain", 183, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(null, true))); cards.add(new SetCardInfo("Mountain", 184, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(null, true))); @@ -325,6 +326,7 @@ public class FourthEdition extends ExpansionSet { cards.add(new SetCardInfo("Soul Net", 364, Rarity.UNCOMMON, mage.cards.s.SoulNet.class)); cards.add(new SetCardInfo("Spell Blast", 103, Rarity.COMMON, mage.cards.s.SpellBlast.class)); cards.add(new SetCardInfo("Spirit Link", 301, Rarity.UNCOMMON, mage.cards.s.SpiritLink.class)); + cards.add(new SetCardInfo("Spirit Shackle", 47, Rarity.UNCOMMON, mage.cards.s.SpiritShackle.class)); cards.add(new SetCardInfo("Stasis", 104, Rarity.RARE, mage.cards.s.Stasis.class)); cards.add(new SetCardInfo("Steal Artifact", 105, Rarity.UNCOMMON, mage.cards.s.StealArtifact.class)); cards.add(new SetCardInfo("Stone Giant", 241, Rarity.UNCOMMON, mage.cards.s.StoneGiant.class)); diff --git a/Mage.Sets/src/mage/sets/Homelands.java b/Mage.Sets/src/mage/sets/Homelands.java index 39f394bba35..ab98fecde2b 100644 --- a/Mage.Sets/src/mage/sets/Homelands.java +++ b/Mage.Sets/src/mage/sets/Homelands.java @@ -115,6 +115,7 @@ public class Homelands extends ExpansionSet { cards.add(new SetCardInfo("Folk of An-Havva", 58, Rarity.COMMON, FolkOfAnHavva.class, new CardGraphicInfo(null, true))); cards.add(new SetCardInfo("Folk of An-Havva", 59, Rarity.COMMON, FolkOfAnHavva.class, new CardGraphicInfo(null, true))); cards.add(new SetCardInfo("Forget", 32, Rarity.RARE, mage.cards.f.Forget.class)); + cards.add(new SetCardInfo("Ghost Hounds", 12, Rarity.UNCOMMON, mage.cards.g.GhostHounds.class)); cards.add(new SetCardInfo("Grandmother Sengir", 13, Rarity.RARE, mage.cards.g.GrandmotherSengir.class)); cards.add(new SetCardInfo("Headstone", 15, Rarity.COMMON, mage.cards.h.Headstone.class)); cards.add(new SetCardInfo("Hungry Mist", 60, Rarity.COMMON, mage.cards.h.HungryMist.class, new CardGraphicInfo(null, true))); diff --git a/Mage.Sets/src/mage/sets/IceAge.java b/Mage.Sets/src/mage/sets/IceAge.java index b8b5459f826..77637654872 100644 --- a/Mage.Sets/src/mage/sets/IceAge.java +++ b/Mage.Sets/src/mage/sets/IceAge.java @@ -277,6 +277,7 @@ public class IceAge extends ExpansionSet { cards.add(new SetCardInfo("Veldt", 358, Rarity.RARE, mage.cards.v.Veldt.class)); cards.add(new SetCardInfo("Vertigo", 222, Rarity.UNCOMMON, mage.cards.v.Vertigo.class)); cards.add(new SetCardInfo("Walking Wall", 321, Rarity.UNCOMMON, mage.cards.w.WalkingWall.class)); + cards.add(new SetCardInfo("Wall of Lava", 223, Rarity.UNCOMMON, mage.cards.w.WallOfLava.class)); cards.add(new SetCardInfo("Wall of Pine Needles", 162, Rarity.UNCOMMON, mage.cards.w.WallOfPineNeedles.class)); cards.add(new SetCardInfo("War Chariot", 323, Rarity.UNCOMMON, mage.cards.w.WarChariot.class)); cards.add(new SetCardInfo("Warning", 279, Rarity.COMMON, mage.cards.w.Warning.class)); diff --git a/Mage.Sets/src/mage/sets/Legends.java b/Mage.Sets/src/mage/sets/Legends.java index 0729bc30cae..5bb2f82516e 100644 --- a/Mage.Sets/src/mage/sets/Legends.java +++ b/Mage.Sets/src/mage/sets/Legends.java @@ -204,6 +204,7 @@ public class Legends extends ExpansionSet { cards.add(new SetCardInfo("Sol'kanar the Swamp King", 299, Rarity.RARE, mage.cards.s.SolkanarTheSwampKing.class)); cards.add(new SetCardInfo("Spinal Villain", 161, Rarity.RARE, mage.cards.s.SpinalVillain.class)); cards.add(new SetCardInfo("Spirit Link", 206, Rarity.UNCOMMON, mage.cards.s.SpiritLink.class)); + cards.add(new SetCardInfo("Spirit Shackle", 31, Rarity.COMMON, mage.cards.s.SpiritShackle.class)); cards.add(new SetCardInfo("Storm Seeker", 119, Rarity.UNCOMMON, mage.cards.s.StormSeeker.class)); cards.add(new SetCardInfo("Sunastian Falconer", 301, Rarity.UNCOMMON, mage.cards.s.SunastianFalconer.class)); cards.add(new SetCardInfo("Sylvan Library", 121, Rarity.UNCOMMON, mage.cards.s.SylvanLibrary.class)); @@ -233,7 +234,7 @@ public class Legends extends ExpansionSet { cards.add(new SetCardInfo("Wall of Earth", 166, Rarity.COMMON, mage.cards.w.WallOfEarth.class)); cards.add(new SetCardInfo("Wall of Heat", 167, Rarity.COMMON, mage.cards.w.WallOfHeat.class)); cards.add(new SetCardInfo("Wall of Light", 212, Rarity.UNCOMMON, mage.cards.w.WallOfLight.class)); - cards.add(new SetCardInfo("Wall of Putrid Flesh", 41, Rarity.UNCOMMON, mage.cards.w.WallOfPutridFlesh.class)); + cards.add(new SetCardInfo("Wall of Putrid Flesh", 41, Rarity.UNCOMMON, mage.cards.w.WallOfPutridFlesh.class)); cards.add(new SetCardInfo("Wall of Wonder", 85, Rarity.UNCOMMON, mage.cards.w.WallOfWonder.class)); cards.add(new SetCardInfo("Whirling Dervish", 125, Rarity.UNCOMMON, mage.cards.w.WhirlingDervish.class)); cards.add(new SetCardInfo("Willow Satyr", 126, Rarity.RARE, mage.cards.w.WillowSatyr.class)); diff --git a/Mage.Sets/src/mage/sets/MastersEditionIII.java b/Mage.Sets/src/mage/sets/MastersEditionIII.java index 1551119c2a6..ae8ce58ab70 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionIII.java +++ b/Mage.Sets/src/mage/sets/MastersEditionIII.java @@ -204,6 +204,7 @@ public class MastersEditionIII extends ExpansionSet { cards.add(new SetCardInfo("Sivitri Scarzam", 175, Rarity.COMMON, mage.cards.s.SivitriScarzam.class)); cards.add(new SetCardInfo("Slashing Tiger", 133, Rarity.COMMON, mage.cards.s.SlashingTiger.class)); cards.add(new SetCardInfo("Sol Grail", 201, Rarity.COMMON, mage.cards.s.SolGrail.class)); + cards.add(new SetCardInfo("Spirit Shackle", 74, Rarity.COMMON, mage.cards.s.SpiritShackle.class)); cards.add(new SetCardInfo("Spoils of Victory", 134, Rarity.COMMON, mage.cards.s.SpoilsOfVictory.class)); cards.add(new SetCardInfo("Stolen Grain", 75, Rarity.UNCOMMON, mage.cards.s.StolenGrain.class)); cards.add(new SetCardInfo("Strategic Planning", 51, Rarity.COMMON, mage.cards.s.StrategicPlanning.class)); diff --git a/Mage.Sets/src/mage/sets/TheDark.java b/Mage.Sets/src/mage/sets/TheDark.java index 5629aef5f15..a753868ffd5 100644 --- a/Mage.Sets/src/mage/sets/TheDark.java +++ b/Mage.Sets/src/mage/sets/TheDark.java @@ -63,7 +63,7 @@ public class TheDark extends ExpansionSet { cards.add(new SetCardInfo("Bog Rats", 4, Rarity.COMMON, mage.cards.b.BogRats.class)); cards.add(new SetCardInfo("Bone Flute", 94, Rarity.UNCOMMON, mage.cards.b.BoneFlute.class)); cards.add(new SetCardInfo("Book of Rass", 95, Rarity.UNCOMMON, mage.cards.b.BookOfRass.class)); - cards.add(new SetCardInfo("Brainwash", 76, Rarity.COMMON, mage.cards.b.Brainwash.class)); + cards.add(new SetCardInfo("Brainwash", 76, Rarity.COMMON, mage.cards.b.Brainwash.class)); cards.add(new SetCardInfo("Brothers of Fire", 58, Rarity.UNCOMMON, mage.cards.b.BrothersOfFire.class)); cards.add(new SetCardInfo("Carnivorous Plant", 38, Rarity.COMMON, mage.cards.c.CarnivorousPlant.class)); cards.add(new SetCardInfo("Cave People", 59, Rarity.UNCOMMON, mage.cards.c.CavePeople.class)); @@ -104,6 +104,7 @@ public class TheDark extends ExpansionSet { cards.add(new SetCardInfo("Marsh Viper", 44, Rarity.COMMON, mage.cards.m.MarshViper.class)); cards.add(new SetCardInfo("Maze of Ith", 114, Rarity.UNCOMMON, mage.cards.m.MazeOfIth.class)); cards.add(new SetCardInfo("Merfolk Assassin", 31, Rarity.UNCOMMON, mage.cards.m.MerfolkAssassin.class)); + cards.add(new SetCardInfo("Morale", 87, Rarity.COMMON, mage.cards.m.Morale.class)); cards.add(new SetCardInfo("Murk Dwellers", 11, Rarity.COMMON, mage.cards.m.MurkDwellers.class)); cards.add(new SetCardInfo("Niall Silvain", 45, Rarity.RARE, mage.cards.n.NiallSilvain.class)); cards.add(new SetCardInfo("Orc General", 72, Rarity.UNCOMMON, mage.cards.o.OrcGeneral.class)); @@ -119,7 +120,7 @@ public class TheDark extends ExpansionSet { cards.add(new SetCardInfo("Sisters of the Flame", 73, Rarity.UNCOMMON, mage.cards.s.SistersOfTheFlame.class)); cards.add(new SetCardInfo("Skull of Orm", 106, Rarity.UNCOMMON, mage.cards.s.SkullOfOrm.class)); cards.add(new SetCardInfo("Squire", 90, Rarity.COMMON, mage.cards.s.Squire.class)); - cards.add(new SetCardInfo("Standing Stones", 107, Rarity.UNCOMMON, mage.cards.s.StandingStones.class)); + cards.add(new SetCardInfo("Standing Stones", 107, Rarity.UNCOMMON, mage.cards.s.StandingStones.class)); cards.add(new SetCardInfo("Stone Calendar", 108, Rarity.RARE, mage.cards.s.StoneCalendar.class)); cards.add(new SetCardInfo("Sunken City", 35, Rarity.COMMON, mage.cards.s.SunkenCity.class)); cards.add(new SetCardInfo("Tivadar's Crusade", 91, Rarity.UNCOMMON, mage.cards.t.TivadarsCrusade.class)); diff --git a/Mage.Sets/src/mage/sets/Visions.java b/Mage.Sets/src/mage/sets/Visions.java index 868a648f504..25b49f8b709 100644 --- a/Mage.Sets/src/mage/sets/Visions.java +++ b/Mage.Sets/src/mage/sets/Visions.java @@ -58,6 +58,7 @@ public class Visions extends ExpansionSet { cards.add(new SetCardInfo("Archangel", 101, Rarity.RARE, mage.cards.a.Archangel.class)); cards.add(new SetCardInfo("Army Ants", 126, Rarity.UNCOMMON, mage.cards.a.ArmyAnts.class)); cards.add(new SetCardInfo("Betrayal", 26, Rarity.COMMON, mage.cards.b.Betrayal.class)); + cards.add(new SetCardInfo("Blanket of Night", 2, Rarity.UNCOMMON, mage.cards.b.BlanketOfNight.class)); cards.add(new SetCardInfo("Breezekeeper", 27, Rarity.COMMON, mage.cards.b.Breezekeeper.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/src/main/java/mage/abilities/effects/common/continuous/AddCardSubtypeAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardSubtypeAllEffect.java new file mode 100644 index 00000000000..459bbb25b99 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardSubtypeAllEffect.java @@ -0,0 +1,75 @@ +/* + * 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.abilities.effects.common.continuous; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterLandPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * @author Galatolol + */ + +public class AddCardSubtypeAllEffect extends ContinuousEffectImpl { + + private static FilterPermanent filter = new FilterLandPermanent(); + private static String addedSubtype; + + public AddCardSubtypeAllEffect(FilterPermanent _filter, String _addedSubtype, DependencyType _dependency) { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); + filter = _filter; + staticText = ""; + addedSubtype = _addedSubtype; + addDependencyType(_dependency); + } + + public AddCardSubtypeAllEffect(final AddCardSubtypeAllEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + if (perm != null && !perm.getSubtype(game).contains(addedSubtype)) { + perm.getSubtype(game).add(addedSubtype); + } + } + return true; + } + + @Override + public AddCardSubtypeAllEffect copy() { + return new AddCardSubtypeAllEffect(this); + } + +} \ No newline at end of file From 9cbe82299cbe925f95a76390330b8fb3b3e0264c Mon Sep 17 00:00:00 2001 From: Galatolol Date: Sun, 22 Jan 2017 11:40:52 +0100 Subject: [PATCH 26/44] Fixed AddCardSubtypeAllEffect --- .../effects/common/continuous/AddCardSubtypeAllEffect.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardSubtypeAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardSubtypeAllEffect.java index 459bbb25b99..d47f92f5cc9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardSubtypeAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardSubtypeAllEffect.java @@ -42,7 +42,7 @@ import mage.game.permanent.Permanent; public class AddCardSubtypeAllEffect extends ContinuousEffectImpl { - private static FilterPermanent filter = new FilterLandPermanent(); + private static FilterPermanent filter; private static String addedSubtype; public AddCardSubtypeAllEffect(FilterPermanent _filter, String _addedSubtype, DependencyType _dependency) { From fdd28cde4b35ac1b0d2c834535ae1e43c648f3da Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 22 Jan 2017 22:04:50 +0100 Subject: [PATCH 27/44] * Possibility Storm - Fixed a problem with split card moving. --- Mage.Sets/src/mage/cards/p/PossibilityStorm.java | 13 +++++-------- .../test/cards/triggers/PossibilityStormTest.java | 13 ++----------- Mage/src/main/java/mage/players/Player.java | 1 + Mage/src/main/java/mage/players/PlayerImpl.java | 12 ++++++++---- 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/Mage.Sets/src/mage/cards/p/PossibilityStorm.java b/Mage.Sets/src/mage/cards/p/PossibilityStorm.java index 30742acac95..8ebea656995 100644 --- a/Mage.Sets/src/mage/cards/p/PossibilityStorm.java +++ b/Mage.Sets/src/mage/cards/p/PossibilityStorm.java @@ -56,7 +56,7 @@ import mage.target.targetpointer.FixedTarget; public class PossibilityStorm extends CardImpl { public PossibilityStorm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}{R}"); // Whenever a player casts a spell from his or her hand, that player exiles it, then exiles cards from // the top of his or her library until he or she exiles a card that shares a card type with it. That @@ -133,14 +133,14 @@ class PossibilityStormEffect extends OneShotEffect { if (sourceObject != null && spell != null) { Player spellController = game.getPlayer(spell.getControllerId()); if (spellController != null - && spellController.moveCardToExileWithInfo(spell, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.STACK, true)) { + && spellController.moveCardsToExile(spell, source, game, true, source.getSourceId(), sourceObject.getIdName())) { if (spellController.getLibrary().size() > 0) { Library library = spellController.getLibrary(); Card card; do { - card = library.removeFromTop(game); + card = library.getFromTop(game); if (card != null) { - spellController.moveCardToExileWithInfo(card, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); + spellController.moveCardsToExile(card, source, game, true, source.getSourceId(), sourceObject.getIdName()); } } while (library.size() > 0 && card != null && !sharesType(card, spell.getCardType())); @@ -154,10 +154,7 @@ class PossibilityStormEffect extends OneShotEffect { ExileZone exile = game.getExile().getExileZone(source.getSourceId()); if (exile != null) { - while (exile.size() > 0) { - card = exile.getRandom(game); - spellController.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.EXILED, false, false); - } + spellController.putCardsOnBottomOfLibrary(exile, game, source, false); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/PossibilityStormTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/PossibilityStormTest.java index 84ef7030c2b..69403791c3a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/PossibilityStormTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/PossibilityStormTest.java @@ -27,10 +27,8 @@ */ package org.mage.test.cards.triggers; -import mage.cards.Card; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Assert; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -61,7 +59,7 @@ public class PossibilityStormTest extends CardTestPlayerBase { // the top of his or her library until he or she exiles a card that shares a card type with it. That // player may cast that card without paying its mana cost. Then he or she puts all cards exiled with // Possibility Storm on the bottom of his or her library in a random order. - addCard(Zone.BATTLEFIELD, playerA, "Possibility Storm", 2); + addCard(Zone.BATTLEFIELD, playerA, "Possibility Storm", 1); // {T}: Add {C} to your mana pool. // Morph {2} @@ -78,14 +76,7 @@ public class PossibilityStormTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Zoetic Cavern", 0); - boolean zoeticCavernInLibrary = false; - for (Card card : playerA.getLibrary().getCards(currentGame)) { - if (card.getName().equals("Zoetic Cavern")) { - zoeticCavernInLibrary = true; - } - } - Assert.assertEquals("Zoetic Cavern has to be in the library", true, zoeticCavernInLibrary); - + assertLibraryCount(playerA, "Zoetic Cavern", 1); assertPermanentCount(playerA, "Silvercoat Lion", 1); } diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index 0f9638e302a..e915ac498a2 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -506,6 +506,7 @@ public interface Player extends MageItem, Copyable { * @param cards - list of cards that have to be moved * @param game - game * @param anyOrder - true if player can determine the order of the cards + * else random order * @param source - source ability * @return */ diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 70308b01bbe..5208ed7ad28 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -825,8 +825,10 @@ public abstract class PlayerImpl implements Player, Serializable { if (!cardsToLibrary.isEmpty()) { Cards cards = new CardsImpl(cardsToLibrary); // prevent possible ConcurrentModificationException if (!anyOrder) { - for (UUID objectId : cards) { - moveObjectToLibrary(objectId, source == null ? null : source.getSourceId(), game, false, false); + while (!cards.isEmpty()) { + UUID cardId = cards.getRandom(game).getId(); + cards.remove(cardId); + moveObjectToLibrary(cardId, source == null ? null : source.getSourceId(), game, false, false); } } else { TargetCard target = new TargetCard(Zone.ALL, new FilterCard("card to put on the bottom of your library (last one chosen will be bottommost)")); @@ -864,8 +866,10 @@ public abstract class PlayerImpl implements Player, Serializable { Cards cards = new CardsImpl(cardsToLibrary); // prevent possible ConcurrentModificationException UUID sourceId = (source == null ? null : source.getSourceId()); if (!anyOrder) { - for (UUID cardId : cards) { - moveObjectToLibrary(cardId, sourceId, game, true, false); + while (!cards.isEmpty()) { + UUID cardId = cards.getRandom(game).getId(); + cards.remove(cardId); + moveObjectToLibrary(cardId, source == null ? null : source.getSourceId(), game, true, false); } } else { TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put on the top of your library (last one chosen will be topmost)")); From dad1a10eec6255ce07b126dde969e02f57f00ba4 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 22 Jan 2017 22:12:45 +0100 Subject: [PATCH 28/44] * Eternal Scourge - Fixed that also non card owner could cast from exile if controlled from other player before going to exile. --- Mage.Sets/src/mage/cards/e/EternalScourge.java | 5 +++-- Mage.Sets/src/mage/cards/f/FatalPush.java | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/cards/e/EternalScourge.java b/Mage.Sets/src/mage/cards/e/EternalScourge.java index 400375ae396..85e7fb3a751 100644 --- a/Mage.Sets/src/mage/cards/e/EternalScourge.java +++ b/Mage.Sets/src/mage/cards/e/EternalScourge.java @@ -53,7 +53,7 @@ import mage.game.events.GameEvent.EventType; public class EternalScourge extends CardImpl { public EternalScourge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}"); this.subtype.add("Eldrazi"); this.subtype.add("Horror"); this.power = new MageInt(3); @@ -101,13 +101,14 @@ class EternalScourgePlayEffect extends AsThoughEffectImpl { public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { if (sourceId.equals(source.getSourceId())) { Card card = game.getCard(source.getSourceId()); - if (card != null && card.getOwnerId().equals(source.getControllerId()) && game.getState().getZone(source.getSourceId()) == Zone.EXILED) { + if (card != null && card.getOwnerId().equals(affectedControllerId) && game.getState().getZone(source.getSourceId()) == Zone.EXILED) { return true; } } return false; } } + class EternalScourgeAbility extends TriggeredAbilityImpl { public EternalScourgeAbility() { diff --git a/Mage.Sets/src/mage/cards/f/FatalPush.java b/Mage.Sets/src/mage/cards/f/FatalPush.java index 33503498e84..9ff7c18c237 100644 --- a/Mage.Sets/src/mage/cards/f/FatalPush.java +++ b/Mage.Sets/src/mage/cards/f/FatalPush.java @@ -71,7 +71,7 @@ class FatalPushEffect extends OneShotEffect { FatalPushEffect() { super(Outcome.DestroyPermanent); - this.staticText = "Destroy target creature if it has converted mana cost 2 or less.
Revolt — Destroy that creature if it has converted mana cost 4 or less instead if a permanent you controlled left the battlefield this turn."; + this.staticText = "Destroy target creature if it has converted mana cost 2 or less.
Revolt — Destroy that creature if it has converted mana cost 4 or less instead if a permanent you controlled left the battlefield this turn"; } FatalPushEffect(final FatalPushEffect effect) { From 719f88b3c83e4392a42f37b0b7c290b54b3b0b53 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 22 Jan 2017 22:27:39 +0100 Subject: [PATCH 29/44] * Fixed possible IndexOutOfBoundsException during combat. --- Mage/src/main/java/mage/game/combat/CombatGroup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage/src/main/java/mage/game/combat/CombatGroup.java b/Mage/src/main/java/mage/game/combat/CombatGroup.java index 713929dcfe3..b18d6f76105 100644 --- a/Mage/src/main/java/mage/game/combat/CombatGroup.java +++ b/Mage/src/main/java/mage/game/combat/CombatGroup.java @@ -299,7 +299,7 @@ public class CombatGroup implements Serializable, Copyable { } if (damage > 0 && hasTrample(attacker)) { defenderDamage(attacker, damage, game); - } else { + } else if (!blockerOrder.isEmpty()) { // Assign the damge left to first blocker assigned.put(blockerOrder.get(0), assigned.get(blockerOrder.get(0)) + damage); } From 0014c7dcc5cc5f6948dc18c599471795a160b54e Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 22 Jan 2017 22:46:14 +0100 Subject: [PATCH 30/44] * Fixed some possible null pointer exceptions. --- Mage.Sets/src/mage/cards/i/InvaderParasite.java | 13 +++++++++---- .../mana/AnyColorLandsProduceManaAbility.java | 3 +++ Mage/src/main/java/mage/players/PlayerImpl.java | 9 +++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Mage.Sets/src/mage/cards/i/InvaderParasite.java b/Mage.Sets/src/mage/cards/i/InvaderParasite.java index 87754e3d489..9f9197a62b7 100644 --- a/Mage.Sets/src/mage/cards/i/InvaderParasite.java +++ b/Mage.Sets/src/mage/cards/i/InvaderParasite.java @@ -54,15 +54,18 @@ import mage.target.targetpointer.FixedTarget; public class InvaderParasite extends CardImpl { public InvaderParasite(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); this.subtype.add("Insect"); this.power = new MageInt(3); this.toughness = new MageInt(2); + // Imprint - When Invader Parasite enters the battlefield, exile target land. Ability ability = new EntersBattlefieldTriggeredAbility(new InvaderParasiteImprintEffect(), false); ability.addTarget(new TargetLandPermanent()); this.addAbility(ability); + + // Whenever a land with the same name as the exiled card enters the battlefield under an opponent's control, Invader Parasite deals 2 damage to that player. this.addAbility(new InvaderParasiteTriggeredAbility()); } @@ -77,6 +80,7 @@ public class InvaderParasite extends CardImpl { } class InvaderParasiteImprintEffect extends OneShotEffect { + InvaderParasiteImprintEffect() { super(Outcome.Exile); staticText = "exile target land"; @@ -104,6 +108,7 @@ class InvaderParasiteImprintEffect extends OneShotEffect { } class InvaderParasiteTriggeredAbility extends TriggeredAbilityImpl { + InvaderParasiteTriggeredAbility() { super(Zone.BATTLEFIELD, new DamageTargetEffect(2)); } @@ -125,12 +130,12 @@ class InvaderParasiteTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (game.getOpponents(this.controllerId).contains(event.getPlayerId())) { - Permanent p = game.getPermanent(event.getTargetId()); + Permanent targetPermanent = game.getPermanent(event.getTargetId()); Permanent sourcePermanent = game.getPermanent(getSourceId()); - if (p != null && sourcePermanent != null) { + if (targetPermanent != null && sourcePermanent != null) { if (sourcePermanent.getImprinted().size() > 0) { Card imprintedCard = game.getCard(sourcePermanent.getImprinted().get(0)); - if (p.getName().equals(imprintedCard.getName())) { + if (imprintedCard != null && targetPermanent.getName().equals(imprintedCard.getName())) { for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(event.getPlayerId())); } diff --git a/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java b/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java index 989b558f609..80812218084 100644 --- a/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java @@ -29,6 +29,8 @@ package mage.abilities.mana; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import mage.Mana; import mage.abilities.Abilities; import mage.abilities.Ability; @@ -161,6 +163,7 @@ class AnyColorLandsProduceManaEffect extends ManaEffect { } private Mana getManaTypes(Game game, Ability source) { + Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "needed to identify endless loop causing cards: {0}", source.getSourceObject(game).getName()); List lands = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); Mana types = new Mana(); for (Permanent land : lands) { diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 5208ed7ad28..4b6c31e4ad4 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -3293,6 +3293,9 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, Game game, Zone fromZone) { + if (card == null) { + return false; + } boolean result = false; // Zone fromZone = game.getState().getZone(card.getId()); if (card.moveToZone(Zone.GRAVEYARD, sourceId, game, fromZone != null ? fromZone == Zone.BATTLEFIELD : false)) { @@ -3317,6 +3320,9 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, Game game, Zone fromZone, boolean toTop, boolean withName) { + if (card == null) { + return false; + } boolean result = false; if (card.moveToZone(Zone.LIBRARY, sourceId, game, toTop)) { if (!game.isSimulation()) { @@ -3346,6 +3352,9 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId, Game game, Zone fromZone, boolean withName) { + if (card == null) { + return false; + } boolean result = false; if (card.moveToExile(exileId, exileName, sourceId, game)) { if (!game.isSimulation()) { From 326764c94333332b4feedb8c77d4714b51e76a27 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 22 Jan 2017 22:50:34 +0100 Subject: [PATCH 31/44] * Aid from the Cowl - Added a message to the log if the player puts the card back to the top of the library. --- Mage.Sets/src/mage/cards/a/AidFromTheCowl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Mage.Sets/src/mage/cards/a/AidFromTheCowl.java b/Mage.Sets/src/mage/cards/a/AidFromTheCowl.java index 81d8be69464..95e03ecdca5 100644 --- a/Mage.Sets/src/mage/cards/a/AidFromTheCowl.java +++ b/Mage.Sets/src/mage/cards/a/AidFromTheCowl.java @@ -110,6 +110,8 @@ class AidFromTheCowlEffect extends OneShotEffect { controller.moveCards(card, Zone.BATTLEFIELD, source, game); } else if (controller.chooseUse(Outcome.Neutral, "Put " + card.getIdName() + " on the bottom of your library?", source, game)) { controller.putCardsOnBottomOfLibrary(cards, game, source, false); + } else { + game.informPlayers(controller.getLogName() + " puts the revealed card back to the top of the library."); } } } From 682940eca696a4c21b1f2be25a6d4f86b4888ff0 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 22 Jan 2017 23:00:25 +0100 Subject: [PATCH 32/44] Added test. --- .../watchers/SpiritOfTheLabyrinthTest.java | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/watchers/SpiritOfTheLabyrinthTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/SpiritOfTheLabyrinthTest.java index 2dae2257e5e..8cf128f6aa9 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/watchers/SpiritOfTheLabyrinthTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/SpiritOfTheLabyrinthTest.java @@ -10,28 +10,50 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * @author BetaSteward */ public class SpiritOfTheLabyrinthTest extends CardTestPlayerBase { + /* * Spirit of the Labyrinth * Enchantment Creature — Spirit 3/1, 1W (2) * Each player can't draw more than one card each turn. * - */ - + */ + // test that only 1 card is drawn @Test public void testDrawCard() { addCard(Zone.BATTLEFIELD, playerA, "Island", 5); addCard(Zone.BATTLEFIELD, playerA, "Spirit of the Labyrinth"); addCard(Zone.HAND, playerA, "Brilliant Plan"); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Brilliant Plan"); - + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - - this.assertHandCount(playerA, 1); - - } - + this.assertHandCount(playerA, 1); + + } + + // test that only 1 card is drawn + @Test + public void testDrawCardHondenOfSeeingWinds() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.BATTLEFIELD, playerA, "Spirit of the Labyrinth"); + addCard(Zone.HAND, playerA, "Brilliant Plan"); + + // At the beginning of your upkeep, draw a card for each Shrine you control. + addCard(Zone.BATTLEFIELD, playerB, "Honden of Seeing Winds"); + // At the beginning of your upkeep, put a 1/1 colorless Spirit creature token onto the battlefield for each Shrine you control. + addCard(Zone.BATTLEFIELD, playerB, "Honden of Life's Web"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Brilliant Plan"); + + setStopAt(2, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPermanentCount(playerB, "Spirit", 2); + this.assertHandCount(playerA, 1); + this.assertHandCount(playerB, 1); + + } } From 9716ac35418be0c645dcc5fe9ee5337e2eb31cd9 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Mon, 23 Jan 2017 23:31:31 +0100 Subject: [PATCH 33/44] * Corrupted Zendikon - Fixed that the token was green instead of black. --- .../src/mage/cards/c/CorruptedZendikon.java | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/Mage.Sets/src/mage/cards/c/CorruptedZendikon.java b/Mage.Sets/src/mage/cards/c/CorruptedZendikon.java index 8dd44ba5c60..a9712413b6c 100644 --- a/Mage.Sets/src/mage/cards/c/CorruptedZendikon.java +++ b/Mage.Sets/src/mage/cards/c/CorruptedZendikon.java @@ -27,6 +27,8 @@ */ package mage.cards.c; +import java.util.UUID; +import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -37,12 +39,10 @@ import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.game.permanent.token.OozeToken; +import mage.game.permanent.token.Token; import mage.target.TargetPermanent; import mage.target.common.TargetLandPermanent; -import java.util.UUID; - /** * * @author jeffwadsworth @@ -54,17 +54,19 @@ public class CorruptedZendikon extends CardImpl { this.subtype.add("Aura"); // Enchant land - // Enchanted land is a 3/3 black Ooze creature. It's still a land. - // When enchanted land dies, return that card to its owner's hand. TargetPermanent auraTarget = new TargetLandPermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.PutCreatureInPlay)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); - Ability ability2 = new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesCreatureAttachedEffect(new OozeToken(3, 3), "Enchanted land is a 3/3 black Ooze creature. It's still a land.", Duration.WhileOnBattlefield)); + // Enchanted land is a 3/3 black Ooze creature. It's still a land. + Ability ability2 = new SimpleStaticAbility(Zone.BATTLEFIELD, + new BecomesCreatureAttachedEffect(new CorruptedZendikonOozeToken(), + "Enchanted land is a 3/3 black Ooze creature. It's still a land.", Duration.WhileOnBattlefield)); this.addAbility(ability2); + // When enchanted land dies, return that card to its owner's hand. Ability ability3 = new DiesAttachedTriggeredAbility(new ReturnToHandAttachedEffect(), "enchanted land", false); this.addAbility(ability3); } @@ -78,3 +80,16 @@ public class CorruptedZendikon extends CardImpl { return new CorruptedZendikon(this); } } + +class CorruptedZendikonOozeToken extends Token { + + public CorruptedZendikonOozeToken() { + super("Ooze", "3/3 black Ooze creature"); + cardType.add(CardType.CREATURE); + color.setBlack(true); + subtype.add("Ooze"); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + } + +} From 8d06c23602e04ce158f98c3e76188e84d6fbb9ca Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 24 Jan 2017 16:25:26 +0100 Subject: [PATCH 34/44] * Selvala, Explorer Returned - Fixed that library top cards were revealead without using the mana ability. Possible mana from this source is no longer calculated for possible mana pool. Tapping for man can no longer be undone.(#2191). --- .../mage/cards/s/SelvalaExplorerReturned.java | 11 +++++----- .../mage/cards/s/SelvalaHeartOfTheWilds.java | 2 +- Mage.Sets/src/mage/sets/EighthEdition.java | 22 ++++++++++--------- .../mana/ActivatedManaAbilityImpl.java | 5 +++++ .../abilities/mana/SimpleManaAbility.java | 17 +++++++++++++- 5 files changed, 40 insertions(+), 17 deletions(-) diff --git a/Mage.Sets/src/mage/cards/s/SelvalaExplorerReturned.java b/Mage.Sets/src/mage/cards/s/SelvalaExplorerReturned.java index 86c622c4aa2..3020d82c760 100644 --- a/Mage.Sets/src/mage/cards/s/SelvalaExplorerReturned.java +++ b/Mage.Sets/src/mage/cards/s/SelvalaExplorerReturned.java @@ -36,6 +36,7 @@ import mage.abilities.dynamicvalue.common.ParleyCount; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardAllEffect; import mage.abilities.effects.common.ManaEffect; +import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.abilities.mana.SimpleManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -60,13 +61,13 @@ public class SelvalaExplorerReturned extends CardImpl { this.toughness = new MageInt(4); // Parley - {T}: Each player reveals the top card of his or her library. For each nonland card revealed this way, add {G} to your mana pool and you gain 1 life. Then each player draws a card. - Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new SelvalaExplorerReturnedEffect(), new TapSourceCost()); - - ability.setAbilityWord(AbilityWord.PARLEY); + ActivatedManaAbilityImpl manaAbility = new SimpleManaAbility(Zone.BATTLEFIELD, new SelvalaExplorerReturnedEffect(), new TapSourceCost(), false); + manaAbility.setUndoPossible(false); + manaAbility.setAbilityWord(AbilityWord.PARLEY); Effect effect = new DrawCardAllEffect(1); effect.setText("Then each player draws a card"); - ability.addEffect(effect); - this.addAbility(ability); + manaAbility.addEffect(effect); + this.addAbility(manaAbility); } public SelvalaExplorerReturned(final SelvalaExplorerReturned card) { diff --git a/Mage.Sets/src/mage/cards/s/SelvalaHeartOfTheWilds.java b/Mage.Sets/src/mage/cards/s/SelvalaHeartOfTheWilds.java index f61d61c9b53..54f495df6d7 100644 --- a/Mage.Sets/src/mage/cards/s/SelvalaHeartOfTheWilds.java +++ b/Mage.Sets/src/mage/cards/s/SelvalaHeartOfTheWilds.java @@ -63,7 +63,7 @@ public class SelvalaHeartOfTheWilds extends CardImpl { filter.add(new GreatestPowerPredicate()); } - private static final String rule = "Whenever another creature enters the battlefield, its controller may draw a card if its power is greater than each other creature's power"; + private static final String rule = "Whenever another creature enters the battlefield, its controller may draw a card if its power is greater than each other creature's power."; public SelvalaHeartOfTheWilds(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{G}"); diff --git a/Mage.Sets/src/mage/sets/EighthEdition.java b/Mage.Sets/src/mage/sets/EighthEdition.java index 17e5ec1d2b8..4b710f875e8 100644 --- a/Mage.Sets/src/mage/sets/EighthEdition.java +++ b/Mage.Sets/src/mage/sets/EighthEdition.java @@ -1,11 +1,11 @@ package mage.sets; +import mage.cards.CardGraphicInfo; +import mage.cards.ExpansionSet; import mage.cards.o.OrcishSpy; import mage.cards.r.RukhEgg; -import mage.constants.SetType; -import mage.cards.ExpansionSet; import mage.constants.Rarity; -import mage.cards.CardGraphicInfo; +import mage.constants.SetType; public class EighthEdition extends ExpansionSet { @@ -100,7 +100,6 @@ public class EighthEdition extends ExpansionSet { cards.add(new SetCardInfo("Drudge Skeletons", 129, Rarity.COMMON, mage.cards.d.DrudgeSkeletons.class)); cards.add(new SetCardInfo("Dusk Imp", 130, Rarity.COMMON, mage.cards.d.DuskImp.class)); cards.add(new SetCardInfo("Dwarven Demolition Team", 184, Rarity.UNCOMMON, mage.cards.d.DwarvenDemolitionTeam.class)); - cards.add(new SetCardInfo("Eager Cadet", 1, Rarity.COMMON, mage.cards.e.EagerCadet.class)); cards.add(new SetCardInfo("Eastern Paladin", 131, Rarity.RARE, mage.cards.e.EasternPaladin.class)); cards.add(new SetCardInfo("Elfhame Palace", 324, Rarity.UNCOMMON, mage.cards.e.ElfhamePalace.class)); cards.add(new SetCardInfo("Elite Archers", 18, Rarity.RARE, mage.cards.e.EliteArchers.class)); @@ -111,7 +110,6 @@ public class EighthEdition extends ExpansionSet { cards.add(new SetCardInfo("Elvish Piper", 244, Rarity.RARE, mage.cards.e.ElvishPiper.class)); cards.add(new SetCardInfo("Elvish Scrapper", 245, Rarity.UNCOMMON, mage.cards.e.ElvishScrapper.class)); cards.add(new SetCardInfo("Emperor Crocodile", 246, Rarity.RARE, mage.cards.e.EmperorCrocodile.class)); - cards.add(new SetCardInfo("Enormous Baloth", 6, Rarity.UNCOMMON, mage.cards.e.EnormousBaloth.class)); cards.add(new SetCardInfo("Enrage", 185, Rarity.UNCOMMON, mage.cards.e.Enrage.class)); cards.add(new SetCardInfo("Ensnaring Bridge", 300, Rarity.RARE, mage.cards.e.EnsnaringBridge.class)); cards.add(new SetCardInfo("Evacuation", 76, Rarity.RARE, mage.cards.e.Evacuation.class)); @@ -282,7 +280,6 @@ public class EighthEdition extends ExpansionSet { cards.add(new SetCardInfo("Sanctimony", 42, Rarity.UNCOMMON, mage.cards.s.Sanctimony.class)); cards.add(new SetCardInfo("Savannah Lions", 43, Rarity.RARE, mage.cards.s.SavannahLions.class)); cards.add(new SetCardInfo("Scathe Zombies", 160, Rarity.COMMON, mage.cards.s.ScatheZombies.class)); - cards.add(new SetCardInfo("Sea Eagle", 4, Rarity.COMMON, mage.cards.s.SeaEagle.class)); cards.add(new SetCardInfo("Sea Monster", 99, Rarity.COMMON, mage.cards.s.SeaMonster.class)); cards.add(new SetCardInfo("Searing Wind", 218, Rarity.RARE, mage.cards.s.SearingWind.class)); cards.add(new SetCardInfo("Seasoned Marshal", 44, Rarity.UNCOMMON, mage.cards.s.SeasonedMarshal.class)); @@ -297,7 +294,6 @@ public class EighthEdition extends ExpansionSet { cards.add(new SetCardInfo("Shivan Oasis", 326, Rarity.UNCOMMON, mage.cards.s.ShivanOasis.class)); cards.add(new SetCardInfo("Shock", 222, Rarity.COMMON, mage.cards.s.Shock.class)); cards.add(new SetCardInfo("Shock Troops", 223, Rarity.COMMON, mage.cards.s.ShockTroops.class)); - cards.add(new SetCardInfo("Silverback Ape", 7, Rarity.UNCOMMON, mage.cards.s.SilverbackApe.class)); cards.add(new SetCardInfo("Sizzle", 224, Rarity.COMMON, mage.cards.s.Sizzle.class)); cards.add(new SetCardInfo("Skull of Orm", 313, Rarity.RARE, mage.cards.s.SkullOfOrm.class)); cards.add(new SetCardInfo("Slay", 164, Rarity.UNCOMMON, mage.cards.s.Slay.class)); @@ -352,14 +348,12 @@ public class EighthEdition extends ExpansionSet { cards.add(new SetCardInfo("Urza's Power Plant", 329, Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class)); cards.add(new SetCardInfo("Urza's Tower", 330, Rarity.COMMON, mage.cards.u.UrzasTower.class)); cards.add(new SetCardInfo("Vampiric Spirit", 170, Rarity.RARE, mage.cards.v.VampiricSpirit.class)); - cards.add(new SetCardInfo("Venerable Monk", 55, Rarity.COMMON, mage.cards.v.VenerableMonk.class)); - cards.add(new SetCardInfo("Vengeance", 2, Rarity.UNCOMMON, mage.cards.v.Vengeance.class)); + cards.add(new SetCardInfo("Venerable Monk", 55, Rarity.COMMON, mage.cards.v.VenerableMonk.class)); cards.add(new SetCardInfo("Verduran Enchantress", 285, Rarity.RARE, mage.cards.v.VerduranEnchantress.class)); cards.add(new SetCardInfo("Vernal Bloom", 286, Rarity.RARE, mage.cards.v.VernalBloom.class)); cards.add(new SetCardInfo("Viashino Sandstalker", 230, Rarity.UNCOMMON, mage.cards.v.ViashinoSandstalker.class)); cards.add(new SetCardInfo("Vicious Hunger", 171, Rarity.COMMON, mage.cards.v.ViciousHunger.class)); cards.add(new SetCardInfo("Vine Trellis", 287, Rarity.COMMON, mage.cards.v.VineTrellis.class)); - cards.add(new SetCardInfo("Vizzerdrix", 5, Rarity.RARE, mage.cards.v.Vizzerdrix.class)); cards.add(new SetCardInfo("Volcanic Hammer", 231, Rarity.COMMON, mage.cards.v.VolcanicHammer.class)); cards.add(new SetCardInfo("Wall of Air", 113, Rarity.UNCOMMON, mage.cards.w.WallOfAir.class)); cards.add(new SetCardInfo("Wall of Spears", 320, Rarity.UNCOMMON, mage.cards.w.WallOfSpears.class)); @@ -377,6 +371,14 @@ public class EighthEdition extends ExpansionSet { cards.add(new SetCardInfo("Yavimaya Enchantress", 290, Rarity.UNCOMMON, mage.cards.y.YavimayaEnchantress.class)); cards.add(new SetCardInfo("Zombify", 174, Rarity.UNCOMMON, mage.cards.z.Zombify.class)); cards.add(new SetCardInfo("Zur's Weirding", 116, Rarity.RARE, mage.cards.z.ZursWeirding.class)); + // 8ed Edition Box Set (we need to create own set) + // cards.add(new SetCardInfo("Eager Cadet", 1, Rarity.COMMON, mage.cards.e.EagerCadet.class)); + // cards.add(new SetCardInfo("Vengeance", 2, Rarity.UNCOMMON, mage.cards.v.Vengeance.class)); + // cards.add(new SetCardInfo("Sea Eagle", 4, Rarity.COMMON, mage.cards.s.SeaEagle.class)); + // cards.add(new SetCardInfo("Vizzerdrix", 5, Rarity.RARE, mage.cards.v.Vizzerdrix.class)); + // cards.add(new SetCardInfo("Enormous Baloth", 6, Rarity.UNCOMMON, mage.cards.e.EnormousBaloth.class)); + // cards.add(new SetCardInfo("Silverback Ape", 7, Rarity.UNCOMMON, mage.cards.s.SilverbackApe.class)); + } } diff --git a/Mage/src/main/java/mage/abilities/mana/ActivatedManaAbilityImpl.java b/Mage/src/main/java/mage/abilities/mana/ActivatedManaAbilityImpl.java index 4a146d9c815..1c7b4d68746 100644 --- a/Mage/src/main/java/mage/abilities/mana/ActivatedManaAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/mana/ActivatedManaAbilityImpl.java @@ -98,6 +98,11 @@ public abstract class ActivatedManaAbilityImpl extends ActivatedAbilityImpl impl return netMana.size() > 0; } + /** + * Is it allowed to undo the mana creation. + * It's e.g. not allowed if some game revealing information is related (like reveal the top card of the library) + * @return + */ public boolean isUndoPossible() { return undoPossible; } diff --git a/Mage/src/main/java/mage/abilities/mana/SimpleManaAbility.java b/Mage/src/main/java/mage/abilities/mana/SimpleManaAbility.java index 6f78fabdce7..4ff06bd4e63 100644 --- a/Mage/src/main/java/mage/abilities/mana/SimpleManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/SimpleManaAbility.java @@ -43,17 +43,32 @@ import mage.game.Game; */ public class SimpleManaAbility extends ActivatedManaAbilityImpl { + private boolean predictable; + public SimpleManaAbility(Zone zone, ManaEffect effect, Cost cost) { + this(zone, effect, cost, true); + } + /** + * + * @param zone + * @param effect + * @param cost + * @param predictable set to false if definig the mana type or amount needs to reveal information and can't be predicted + */ + public SimpleManaAbility(Zone zone, ManaEffect effect, Cost cost, boolean predictable) { super(zone, effect, cost); + this.predictable = predictable; } public SimpleManaAbility(Zone zone, Mana mana, Cost cost) { super(zone, new BasicManaEffect(mana), cost); this.netMana.add(mana.copy()); + this.predictable = true; } public SimpleManaAbility(final SimpleManaAbility ability) { super(ability); + this.predictable = ability.predictable; } @Override @@ -63,7 +78,7 @@ public class SimpleManaAbility extends ActivatedManaAbilityImpl { @Override public List getNetMana(Game game) { - if (netMana.isEmpty()) { + if (netMana.isEmpty() && predictable) { for (Effect effect: getEffects()) { if (effect instanceof ManaEffect) { Mana effectMana =((ManaEffect)effect).getMana(game, this); From cec9d00a5934a4df5aa36026c9421947cffbbc20 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 24 Jan 2017 23:08:47 +0100 Subject: [PATCH 35/44] * Fixed that non creature spells with morph could not be countered with Remove if cast with morph. --- .../main/java/mage/abilities/keyword/MorphAbility.java | 10 ++++------ Mage/src/main/java/mage/game/stack/Spell.java | 9 ++++++++- Mage/src/main/java/mage/players/PlayerImpl.java | 4 +++- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java b/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java index 2738a548469..7ea7f48f7e1 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java @@ -100,7 +100,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost protected static final String ABILITY_KEYWORD = "Morph"; protected static final String ABILITY_KEYWORD_MEGA = "Megamorph"; protected static final String REMINDER_TEXT = "(You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.)"; - protected static final String REMINDER_TEXT_MEGA = "(You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its megamorph cost and put a +1/+1 counter on it.)"; + protected static final String REMINDER_TEXT_MEGA = "(You may cast this card face down as a 2/2 creature for {3}. Turn it face up any time for its megamorph cost and put a +1/+1 counter on it.)"; protected String ruleText; protected AlternativeCost2Impl alternateCosts = new AlternativeCost2Impl(ABILITY_KEYWORD, REMINDER_TEXT, new GenericManaCost(3)); protected Costs morphCosts; @@ -194,7 +194,8 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost @Override public boolean isAvailable(Ability source, Game game) { - return true; + return game.isMainPhase() && game.getActivePlayerId().equals(source.getControllerId()) + && (game.getStack().isEmpty() || (game.getStack().size() == 1 && game.getStack().getFirst().getSourceId().equals(source.getSourceId()))); } @Override @@ -282,10 +283,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost @Override public String getCastMessageSuffix(Game game) { - StringBuilder sb = new StringBuilder(); - int position = 0; - sb.append(alternateCosts.getCastSuffixMessage(position)); - return sb.toString(); + return alternateCosts.getCastSuffixMessage(0); } @Override diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index 57a0fb74f9c..bd421709e68 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -432,6 +432,13 @@ public class Spell extends StackObjImpl implements Card { @Override public String getLogName() { + if (faceDown) { + if (getCardType().contains(CardType.CREATURE)) { + return "face down creature spell"; + } else { + return "face down spell"; + } + } return GameLog.getColoredObjectIdName(card); } @@ -451,7 +458,7 @@ public class Spell extends StackObjImpl implements Card { @Override public List getCardType() { - if (this.getSpellAbility().getSpellAbilityType().equals(SpellAbilityType.FACE_DOWN_CREATURE)) { + if (faceDown) { List cardTypes = new ArrayList<>(); cardTypes.add(CardType.CREATURE); return cardTypes; diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 4b6c31e4ad4..0b84f713b1a 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -2768,7 +2768,9 @@ public abstract class PlayerImpl implements Player, Serializable { case STATIC: if (card.getCardType().contains(CardType.LAND) && ability instanceof AlternativeSourceCosts) { if (canLandPlayAlternateSourceCostsAbility(card, available, ability, game)) { // e.g. Land with Morph - playable.add(card.getId()); + if (game.canPlaySorcery(getId())) { + playable.add(card.getId()); + } break Abilities; } } From e2388374658311f09e245cd39b02e2891cfcfebc Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 24 Jan 2017 23:17:14 +0100 Subject: [PATCH 36/44] Powerstone Minefield some minor changes. --- Mage.Sets/src/mage/cards/p/PowerstoneMinefield.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Mage.Sets/src/mage/cards/p/PowerstoneMinefield.java b/Mage.Sets/src/mage/cards/p/PowerstoneMinefield.java index 97dc6b032b5..a86873d9659 100644 --- a/Mage.Sets/src/mage/cards/p/PowerstoneMinefield.java +++ b/Mage.Sets/src/mage/cards/p/PowerstoneMinefield.java @@ -27,6 +27,7 @@ */ package mage.cards.p; +import java.util.UUID; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; @@ -41,8 +42,6 @@ import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; -import java.util.UUID; - /** * * @author vereena42 @@ -51,7 +50,6 @@ public class PowerstoneMinefield extends CardImpl { public PowerstoneMinefield(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{W}"); - // Whenever a creature attacks or blocks, Powerstone Minefield deals 2 damage to it. this.addAbility(new PowerstoneMinefieldTriggeredAbility()); @@ -86,11 +84,10 @@ class PowerstoneMinefieldTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - UUID sourceId = event.getSourceId(); - Permanent permanent = game.getPermanent(sourceId); + Permanent permanent = game.getPermanent(event.getSourceId()); if (filter.match(permanent, getSourceId(), getControllerId(), game)) { for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(sourceId)); + effect.setTargetPointer(new FixedTarget(permanent, game)); } return true; } @@ -99,7 +96,7 @@ class PowerstoneMinefieldTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever a creature attacks or blocks, Powerstone Minefield deals 2 damage to it."; + return "Whenever a creature attacks or blocks, {this} deals 2 damage to it."; } @Override From dd2a1b8b94a3a09f05cf1b54551c7a4a7edbe618 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Tue, 24 Jan 2017 23:28:19 +0100 Subject: [PATCH 37/44] Hivestone, Muraganda Petroglyphs some minor updates. --- Mage.Sets/src/mage/cards/h/Hivestone.java | 58 +++++-------------- .../mage/cards/m/MuragandaPetroglyphs.java | 29 +++++----- 2 files changed, 31 insertions(+), 56 deletions(-) diff --git a/Mage.Sets/src/mage/cards/h/Hivestone.java b/Mage.Sets/src/mage/cards/h/Hivestone.java index 1738625eaf8..2f5d24e4a4b 100644 --- a/Mage.Sets/src/mage/cards/h/Hivestone.java +++ b/Mage.Sets/src/mage/cards/h/Hivestone.java @@ -1,30 +1,37 @@ package mage.cards.h; -import mage.abilities.Ability; +import java.util.ArrayList; +import java.util.UUID; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BecomesSubtypeAllEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; - -import java.util.List; -import java.util.UUID; +import mage.filter.predicate.permanent.ControllerPredicate; /** * Created by Alexsandr0x. */ public class Hivestone extends CardImpl { + private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + } + public Hivestone(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // Creatures you control are Slivers in addition to their other creature types. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CreaturesAreSliversEffect())); + ArrayList subTypes = new ArrayList<>(); + subTypes.add("Slivers"); + Effect effect = new BecomesSubtypeAllEffect(Duration.WhileOnBattlefield, subTypes, filter, false); + effect.setText("Creatures you control are Slivers in addition to their other creature types"); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); } public Hivestone(final Hivestone card) { @@ -37,36 +44,3 @@ public class Hivestone extends CardImpl { } } - -class CreaturesAreSliversEffect extends ContinuousEffectImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - - - public CreaturesAreSliversEffect() { - super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Neutral); - staticText = "Creatures you control are Slivers in addition to their other creature types."; - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game); - for (Permanent perm : permanents) { - List cardSubType = perm.getSubtype(game); - if (!cardSubType.contains("Sliver") && perm.getOwnerId().equals(player.getId())) { - cardSubType.add("Sliver"); - } - } - return true; - } - - @Override - public mage.cards.h.CreaturesAreSliversEffect copy() { - return new mage.cards.h.CreaturesAreSliversEffect(this); - } - - private CreaturesAreSliversEffect(mage.cards.h.CreaturesAreSliversEffect effect) { - super(effect); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java b/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java index ae27cf86d92..78181d7245d 100644 --- a/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java +++ b/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java @@ -28,7 +28,6 @@ package mage.cards.m; import java.util.UUID; - import mage.MageObject; import mage.abilities.Abilities; import mage.abilities.Ability; @@ -51,14 +50,17 @@ import mage.game.Game; */ public class MuragandaPetroglyphs extends CardImpl { - private static final FilterCreaturePermanent filterNoAbilities = new FilterCreaturePermanent( - "Creatures with no ability"); + private static final FilterCreaturePermanent filterNoAbilities + = new FilterCreaturePermanent("Creatures with no ability"); + + static { + filterNoAbilities.add(new NoAbilityPredicate()); + } public MuragandaPetroglyphs(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); this.expansionSetCode = "FUT"; - filterNoAbilities.add(new NoAbilityPredicate()); // Creatures with no abilities get +2/+2. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect( 2, 2, Duration.WhileOnBattlefield, filterNoAbilities, false))); @@ -80,24 +82,23 @@ class NoAbilityPredicate implements Predicate { public boolean apply(MageObject input, Game game) { boolean isFaceDown = false; Abilities abilities; - if (input instanceof Card){ - abilities = ((Card)input).getAbilities(game); - - isFaceDown = ((Card)input).isFaceDown(game); + if (input instanceof Card) { + abilities = ((Card) input).getAbilities(game); + isFaceDown = ((Card) input).isFaceDown(game); } else { abilities = input.getAbilities(); } if (isFaceDown) { - for (Ability ability : abilities){ - if(!ability.getSourceId().equals(input.getId())) { + for (Ability ability : abilities) { + if (!ability.getSourceId().equals(input.getId())) { return false; } } return true; } - for (Ability ability : abilities){ - if (ability.getClass() != SpellAbility.class){ + for (Ability ability : abilities) { + if (ability.getClass() != SpellAbility.class) { return false; } @@ -109,4 +110,4 @@ class NoAbilityPredicate implements Predicate { public String toString() { return "with no abilities"; } -} \ No newline at end of file +} From fc6dba3da0f6112e8f1bb9868fd9ecef3da33b86 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 25 Jan 2017 00:13:51 +0100 Subject: [PATCH 38/44] Added "MTGO Legacy Cube January 2017" to the server xml. --- Mage.Server/config/config.xml | 1 + Mage.Server/release/config/config.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index fd41c97a47c..1192fab3840 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -107,6 +107,7 @@ + diff --git a/Mage.Server/release/config/config.xml b/Mage.Server/release/config/config.xml index 0f2c1d167eb..e488bf20e9e 100644 --- a/Mage.Server/release/config/config.xml +++ b/Mage.Server/release/config/config.xml @@ -104,6 +104,7 @@ + From 082210a4bdcce5a0d712f15e933e355185c0bbb2 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 25 Jan 2017 00:14:05 +0100 Subject: [PATCH 39/44] Xmage 1.4.21V1 --- Mage.Common/src/mage/utils/MageVersion.java | 2 +- Mage/src/main/java/mage/cards/repository/CardRepository.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Common/src/mage/utils/MageVersion.java b/Mage.Common/src/mage/utils/MageVersion.java index 33185a3fd3e..adf31bb5b63 100644 --- a/Mage.Common/src/mage/utils/MageVersion.java +++ b/Mage.Common/src/mage/utils/MageVersion.java @@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable { public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MINOR = 4; public final static int MAGE_VERSION_PATCH = 21; - public final static String MAGE_VERSION_MINOR_PATCH = "V0"; + public final static String MAGE_VERSION_MINOR_PATCH = "V1"; public final static String MAGE_VERSION_INFO = ""; private final int major; diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index 41d39928c75..06620498952 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -60,7 +60,7 @@ public enum CardRepository { // raise this if db structure was changed private static final long CARD_DB_VERSION = 50; // raise this if new cards were added to the server - private static final long CARD_CONTENT_VERSION = 68; + private static final long CARD_CONTENT_VERSION = 69; private final TreeSet landTypes = new TreeSet(); private Dao cardDao; private Set classNames; From 7fdb04477518f24e8be3f1ffe335999c503d47ba Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 25 Jan 2017 16:05:12 +0100 Subject: [PATCH 40/44] * Added one more test for Gonti, Lord of Luxury, --- .../control/GontiLordOfLuxuryEffectTest.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/control/GontiLordOfLuxuryEffectTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/control/GontiLordOfLuxuryEffectTest.java index ebc2c88a037..f5975fe686d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/control/GontiLordOfLuxuryEffectTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/control/GontiLordOfLuxuryEffectTest.java @@ -79,5 +79,51 @@ public class GontiLordOfLuxuryEffectTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Rashmi, Eternities Crafter", 1); } + /** + * Opponent using Gonti, Lord of Luxury took Mirari's Wake out of my library and cast it. + * I cast Cyclonic Rift on Mirari's Wake to put it back in my hand and was unable to recast Mirari's Wake. + */ + @Test + public void testCanBeCastAgainCyclonicRift() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 9); + // Deathtouch + // When Gonti, Lord of Luxury enters the battlefield, look at the top four cards of target opponent's library, exile one of them face down, + // then put the rest on the bottom of that library in a random order. For as long as that card remains exiled, + // you may look at it, you may cast it, and you may spend mana as though it were mana of any type to cast it. + addCard(Zone.HAND, playerA, "Gonti, Lord of Luxury", 1); // Creature 2/3 {2}{B}{B} + + // Creatures you control get +1/+1. + // Whenever you tap a land for mana, add one mana to your mana pool of any type that land produced. + addCard(Zone.LIBRARY, playerB, "Mirari's Wake"); // Enchantment {3}{G}{W} + skipInitShuffling(); + + addCard(Zone.BATTLEFIELD, playerB, "Island", 2); + addCard(Zone.BATTLEFIELD, playerB, "Forest", 2); + addCard(Zone.BATTLEFIELD, playerB, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + // Return target nonland permanent you don't control to its owner's hand. + // Overload {6}{U} (You may cast this spell for its overload cost. If you do, change its text by replacing all instances of "target" with "each.") + addCard(Zone.HAND, playerB, "Cyclonic Rift", 1); // Intant {1}{U} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gonti, Lord of Luxury"); + addTarget(playerA, playerB); + setChoice(playerA, "Mirari's Wake"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Mirari's Wake"); + castSpell(1, PhaseStep.END_TURN, playerB, "Cyclonic Rift", "Mirari's Wake"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Mirari's Wake"); + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Gonti, Lord of Luxury", 1); + assertPowerToughness(playerA, "Gonti, Lord of Luxury", 2, 3); + assertGraveyardCount(playerB, "Cyclonic Rift", 1); + + assertPermanentCount(playerB, "Mirari's Wake", 1); + assertPowerToughness(playerB, "Silvercoat Lion", 3, 3); + + } + } From a4b44d12971837750b16bc9d1adb0055884eeabb Mon Sep 17 00:00:00 2001 From: fireshoes Date: Wed, 25 Jan 2017 10:28:44 -0600 Subject: [PATCH 41/44] Added upcoming FNM promos: Aether Hub, Servo Exhibition, and Unlicensed Disintegration --- Mage.Sets/src/mage/sets/FridayNightMagic.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Mage.Sets/src/mage/sets/FridayNightMagic.java b/Mage.Sets/src/mage/sets/FridayNightMagic.java index 69fe4f78abf..0ca33510089 100644 --- a/Mage.Sets/src/mage/sets/FridayNightMagic.java +++ b/Mage.Sets/src/mage/sets/FridayNightMagic.java @@ -52,6 +52,7 @@ public class FridayNightMagic extends ExpansionSet { cards.add(new SetCardInfo("Abzan Beastmaster", 180, Rarity.UNCOMMON, mage.cards.a.AbzanBeastmaster.class)); cards.add(new SetCardInfo("Accumulated Knowledge", 51, Rarity.COMMON, mage.cards.a.AccumulatedKnowledge.class)); cards.add(new SetCardInfo("Acidic Slime", 145, Rarity.UNCOMMON, mage.cards.a.AcidicSlime.class)); + cards.add(new SetCardInfo("Aether Hub", 205, Rarity.SPECIAL, mage.cards.a.AetherHub.class)); cards.add(new SetCardInfo("Albino Troll", 20, Rarity.UNCOMMON, mage.cards.a.AlbinoTroll.class)); cards.add(new SetCardInfo("Anathemancer", 122, Rarity.UNCOMMON, mage.cards.a.Anathemancer.class)); cards.add(new SetCardInfo("Ancient Grudge", 144, Rarity.COMMON, mage.cards.a.AncientGrudge.class)); @@ -206,6 +207,7 @@ public class FridayNightMagic extends ExpansionSet { cards.add(new SetCardInfo("Searing Spear", 152, Rarity.COMMON, mage.cards.s.SearingSpear.class)); cards.add(new SetCardInfo("Serrated Arrows", 101, Rarity.UNCOMMON, mage.cards.s.SerratedArrows.class)); cards.add(new SetCardInfo("Serum Visions", 183, Rarity.COMMON, mage.cards.s.SerumVisions.class)); + cards.add(new SetCardInfo("Servo Exhibition", 203, Rarity.SPECIAL, mage.cards.s.ServoExhibition.class)); cards.add(new SetCardInfo("Shock", 6, Rarity.COMMON, mage.cards.s.Shock.class)); cards.add(new SetCardInfo("Shrapnel Blast", 103, Rarity.UNCOMMON, mage.cards.s.ShrapnelBlast.class)); cards.add(new SetCardInfo("Silver Knight", 46, Rarity.UNCOMMON, mage.cards.s.SilverKnight.class)); @@ -236,6 +238,7 @@ public class FridayNightMagic extends ExpansionSet { cards.add(new SetCardInfo("Tormod's Crypt", 93, Rarity.UNCOMMON, mage.cards.t.TormodsCrypt.class)); cards.add(new SetCardInfo("Treetop Village", 50, Rarity.UNCOMMON, mage.cards.t.TreetopVillage.class)); cards.add(new SetCardInfo("Ultimate Price", 185, Rarity.UNCOMMON, mage.cards.u.UltimatePrice.class)); + cards.add(new SetCardInfo("Unlicensed Disintegration", 204, Rarity.SPECIAL, mage.cards.u.UnlicensedDisintegration.class)); cards.add(new SetCardInfo("Volcanic Geyser", 4, Rarity.UNCOMMON, mage.cards.v.VolcanicGeyser.class)); cards.add(new SetCardInfo("Wall of Blossoms", 23, Rarity.UNCOMMON, mage.cards.w.WallOfBlossoms.class)); cards.add(new SetCardInfo("Wall of Omens", 130, Rarity.UNCOMMON, mage.cards.w.WallOfOmens.class)); From f41d81f8e4d4336edf9f9a3ca34d37febacc34bd Mon Sep 17 00:00:00 2001 From: spjspj Date: Fri, 27 Jan 2017 12:38:31 +1100 Subject: [PATCH 42/44] Modify the profanity filter to push it back to client side only. --- .../java/mage/client/chat/ChatPanelBasic.java | 77 ++++++++++++++++++- .../mage/client/dialog/PreferencesDialog.java | 1 + .../main/java/mage/server/ChatManager.java | 12 --- Utils/gen-card.pl | 2 +- 4 files changed, 75 insertions(+), 17 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java b/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java index 26f0ab1a0f9..939f1579216 100644 --- a/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java +++ b/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java @@ -38,9 +38,12 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.event.KeyEvent; import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.swing.JTextField; import mage.client.MageFrame; import mage.client.SessionHandler; +import mage.client.dialog.PreferencesDialog; import mage.client.util.GUISizeHelper; import mage.view.ChatMessage.MessageColor; import mage.view.ChatMessage.MessageType; @@ -184,6 +187,39 @@ public class ChatPanelBasic extends javax.swing.JPanel { } } + Pattern profanityPattern = Pattern.compile(".*(1ab1a|1d1ot|13ch|13p3r|13sb1ans|13sbo|13s13|13sb1an|13sbo|13sy|1nbr3d|1nc3st|1njun|1ub3|\\Wbj|\\Wcum|\\Wdum|\\Wfag|\\Wfap|\\Wfuk|\\Wj1s|\\Wp3do|\\Wp33|\\Wpoo\\W|\\Wt1t|aho13|an1l1ngu|ana1|anus|ar3o1a|ar3o13|ary1an|ashat|asho13|asmast3r|asmunch|asw1p3|b1atch|b1gt1t|b1mbo|b1ow|b1tch|ba1ls|bab3|bang|barf|bastard|bawdy|b3an3r|b3ard3dc1am|b3ast1al1ty|b3atch|b3at3r|b3av3r|b3otch|b3yotch|bo1nk|bod1ly|bon3d|bon3r|bon3|boob|boot13|booty|bow31|br3ast|bugg3r|bukak3|bung|busty|butt|c11t|caca|cahon3|cam31to3|carp3tmunch3r|cawk|c3rv1x|ch1nc|ch1nk|chod3|co1tal|cockb1ock|cockho1st3r|cocknock3r|cocksmok3r|cocksuck3r|cock|condom|coon|corksuck3r|crabs|cums1ut|cumshot|cumsta1n|cun1l1ngus|cuntfac3|cunthunt3r|cunt|d1ck|d1k3|d1ldo|d1mw1t|d1ngl3|d1psh1p|dago|dam1t|damn1t|damn3d|damn|dawg13styl3|dog13styl3|dogysty13|dong|dop3y|douch3|drunk|dumas|dumbas|dumy|dyk3|3jacu1at3|3n1arg3m3nt|3r3ct1on|3r3ct|3rot1c|3xtacy|3xtasy|f.ck|f1osy|f1st3d|f1st1ng|f1sty|fa1gt|fa1g|fack|fag1t|fag3d|fagot|fag|fcuk|f31at1o|f31at3|f31ch1ng|f31ch3r|f31ch|f31tch3r|f31tch|foad|fobar|fond13|for3sk1n|fu.k|fudg3pack3r|fuk|g1ans|g1golo|ganja|ghay|gh3y|go1d3nshow3r|gonad|gook|gr1ngo|h1tl3r|handjob|hardon|hokah|hok3r|homo|honky|hoor|hootch|hoot3r|horny|hump1ng|hump3d|hump|hym3n|j1sm|j1s3d|j1sm|j1s|jackas|jackho13|jackof|j3rk3d|j3rkof|j3rk|junk13|junky|k1an|k1k3|k1nky|knob3nd|kyk3|mams|masa|mast3rba|masturba|max1|m3ns3s|m3nstruat|mfuck1ng|mofo|moron|moth3rf|mthrf|muff|n1gl|n1g|n1mrod|n1ny|n1pl3|nak3d|napa1m|napy|nas1|n3gro|noky|nympho|op1at3|op1um|ora1y|ora1|org13s|organ|orgasm|orgy|ovary|ovum|p1lowb1t3r|p1mp|p1nko|p1s3d|p1ssof|p1ss|pak1|pant13|panty|past13|pasty|p3ck3r|p3doph1l|p33p33|p3n1al|p3n1l3|p3n1s|p3n3trat1on|p3n3trat3|p3rv3rs1on|p3yot3|pha11c|phuck|po1ack|po1ock|poontang|poon|poop|porno|porn|pr1ck|pr1g|pron|pub1|pub3|punkas|punky|puss1|pussy|puto|qu1cky|qu1ck13|qu1m|qu3af|qu3ro|qu3rs|qu3r|r1mjob|r1tard|racy|rap1st|rap3d|rap3r|rap3|raunch|r31ch|r3cta1|r3ctum|r3ctus|r3tard|r3tar|rtard|rumpram3r|rump|s1av3|s13as|s1ut|sack|sad1s|scag|scant1ly|sch1ong|sch1so|scr3w|scrog|scrot|scrud|scum|s3aman|s3am3n|s3duc3|s3m3n|s3xua1|sh1t|skag|skank|sm3gma|smut|sn1p3r|snatch|sodom|sp1ck|sp1c|sp1k|sp3rm|spunk|st3amy|stfu|ston3d|str1p|strok3|stup1d|suck|sumofab1atch|t1nkl3|t1tfuck|tampon|tard|t3abag1ng|t3at|t3st1|t3st3|t3urd|thrust|tramp|trans|trashy|twat|ug1y|unw3d|ur1n3a|ut3rus|vag1na|vu1gar|vu1va|w1g3r|wang|wank3r|wank|w31n3r|w31rdo|w3dg13|w3n13|w3tback|w3w3|wh1t3y|wh1s|whor3|womb).*"); + Pattern profanity2Pattern = Pattern.compile(".*(1ab1a|1d1ot|13ch|13p3r|13sb1ans|13sbo|13s13|13sb1an|13sbo|13sy|1nbr3d|1nc3st|1njun|1ub3|\\Wbj|\\Wcum|\\Wdum|\\Wfag|\\Wfap|\\Wfuk|\\Wj1s|\\Wp3do|\\Wp3|\\Wpo\\W|\\Wt1t|aho13|an1l1ngu|ana1|anus|ar3o1a|ar3o13|ary1an|ashat|asho13|asmast3r|asmunch|asw1p3|b1atch|b1gt1t|b1mbo|b1ow|b1tch|ba1ls|bab3|bang|barf|bastard|bawdy|b3an3r|b3ard3dc1am|b3ast1al1ty|b3atch|b3at3r|b3av3r|b3otch|b3yotch|bo1nk|bod1ly|bon3d|bon3r|bon3|bob|bot13|boty|bow31|br3ast|bug3r|bukak3|bung|busty|but|c1t|caca|cahon3|cam31to3|carp3tmunch3r|cawk|c3rv1x|ch1nc|ch1nk|chod3|co1tal|cockb1ock|cockho1st3r|cocknock3r|cocksmok3r|cocksuck3r|cock|condom|con|corksuck3r|crabs|cums1ut|cumshot|cumsta1n|cun1l1ngus|cuntfac3|cunthunt3r|cunt|d1ck|d1k3|d1ldo|d1mw1t|d1ngl3|d1psh1p|dago|dam1t|damn1t|damn3d|damn|dawg13styl3|dog13styl3|dogysty13|dong|dop3y|douch3|drunk|dumas|dumbas|dumy|dyk3|3jacu1at3|3n1arg3m3nt|3r3ct1on|3r3ct|3rot1c|3xtacy|3xtasy|f.ck|f1osy|f1st3d|f1st1ng|f1sty|fa1gt|fa1g|fack|fag1t|fag3d|fagot|fag|fcuk|f31at1o|f31at3|f31ch1ng|f31ch3r|f31ch|f31tch3r|f31tch|foad|fobar|fond13|for3sk1n|fu.k|fudg3pack3r|fuk|g1ans|g1golo|ganja|ghay|gh3y|go1d3nshow3r|gonad|gr1ngo|h1tl3r|handjob|hardon|hokah|hok3r|homo|honky|hor|hotch|hot3r|horny|hump1ng|hump3d|hump|hym3n|j1sm|j1s3d|j1sm|j1s|jackas|jackho13|jackof|j3rk3d|j3rkof|j3rk|junk13|junky|k1an|k1k3|k1nky|knob3nd|kyk3|mams|masa|mast3rba|masturba|max1|m3ns3s|m3nstruat|mfuck1ng|mofo|moron|moth3rf|mthrf|muf|n1gl|n1g|n1mrod|n1ny|n1pl3|nak3d|napa1m|napy|nas1|n3gro|noky|nympho|op1at3|op1um|ora1y|ora1|org13s|organ|orgasm|orgy|ovary|ovum|p1lowb1t3r|p1mp|p1nko|p1s3d|p1sof|p1s|pak1|pant13|panty|past13|pasty|p3ck3r|p3doph1l|p3p3|p3n1al|p3n1l3|p3n1s|p3n3trat1on|p3n3trat3|p3rv3rs1on|p3yot3|pha1c|phuck|po1ack|po1ock|pontang|pon|pop|porno|porn|pr1ck|pr1g|pron|pub1|pub3|punkas|punky|pus1|pusy|puto|qu1cky|qu1ck13|qu1m|qu3af|qu3ro|qu3rs|qu3r|r1mjob|r1tard|racy|rap1st|rap3d|rap3r|rap3|raunch|r31ch|r3cta1|r3ctum|r3ctus|r3tard|r3tar|rtard|rumpram3r|rump|s1av3|s13as|s1ut|sack|sad1s|scag|scant1ly|sch1ong|sch1so|scr3w|scrog|scrot|scrud|scum|s3aman|s3am3n|s3duc3|s3m3n|s3xua1|sh1t|skag|skank|sm3gma|smut|sn1p3r|snatch|sodom|sp1ck|sp1c|sp1k|sp3rm|spunk|st3amy|stfu|ston3d|str1p|strok3|stup1d|suck|sumofab1atch|t1nkl3|t1tfuck|tampon|tard|t3abag1ng|t3at|t3st1|t3st3|t3urd|thrust|tramp|trans|trashy|twat|ug1y|unw3d|ur1n3a|ut3rus|vag1na|vu1gar|vu1va|w1g3r|wang|wank3r|wank|w31n3r|w31rdo|w3dg13|w3n13|w3tback|w3w3|wh1t3y|wh1s|whor3|womb).*"); + + private boolean containsSwearing(String message, String level) { + String orig = message; + message = message.replaceAll("\\W", "."); + message = "." + message + "."; + + message = message.toLowerCase(); + message = message.replaceAll("(.)(\\1{2,})", "$1"); + message = message.replaceAll("[@]", "a"); + message = message.replaceAll("[il]", "1"); + message = message.replaceAll("[e]", "3"); + message = message.replaceAll("[0]", "o"); + message = message.replaceAll("[5z]", "s"); + + Matcher matchPattern = profanityPattern.matcher(message); + if (matchPattern.find()) { + System.out.println("message: Matched profanity:" + message); + return true; + } + + if (level.equals("2")) { + message = message.replaceAll("\\.", ""); + matchPattern = profanity2Pattern.matcher(message); + if (matchPattern.find()) { + System.out.println("message: Matched profanity (level2):" + message); + return true; + } + } + return false; + } + /** * Display message in the chat. Use different colors for timestamp, username * and message. @@ -194,6 +230,8 @@ public class ChatPanelBasic extends javax.swing.JPanel { * @param messageType * @param color Preferred color. Not used. */ + Pattern cardNamePattern = Pattern.compile(".*.*"); + public void receiveMessage(String username, String message, String time, MessageType messageType, MessageColor color) { StringBuilder text = new StringBuilder(); if (time != null) { @@ -227,11 +265,42 @@ public class ChatPanelBasic extends javax.swing.JPanel { if (color.equals(MessageColor.YELLOW)) { textColor = "Yellow"; } - if (username != null && !username.isEmpty()) { - text.append(getColoredText(userColor, username + userSeparator)); + if (messageType == MessageType.WHISPER) { + if (username.equalsIgnoreCase("Whisper from " + SessionHandler.getUserName())) { + if (message.toLowerCase().startsWith("profanity 0")) { + PreferencesDialog.saveValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "0"); + } else if (message.toLowerCase().startsWith("profanity 1")) { + PreferencesDialog.saveValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "1"); + } else if (message.toLowerCase().startsWith("profanity 2")) { + PreferencesDialog.saveValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "2"); + } + } + } + + Matcher matchPattern = cardNamePattern.matcher(message); + String messageToTest = message; + while (matchPattern.find()) { + messageToTest = message.replaceFirst("", ""); + } + + if (messageType == MessageType.USER_INFO || messageType == MessageType.GAME || messageType == MessageType.STATUS + || PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "0").equals("0") + || !PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "0").equals("0") && !containsSwearing(messageToTest, PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "0"))) { + if (username != null && !username.isEmpty()) { + text.append(getColoredText(userColor, username + userSeparator)); + } + text.append(getColoredText(textColor, ManaSymbols.replaceSymbolsWithHTML(message, ManaSymbols.Type.CHAT))); + this.txtConversation.append(text.toString()); + } else if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "0").equals("1")) { + if (username != null && !username.isEmpty()) { + text.append(getColoredText("black", username + userSeparator)); + } + text.append(getColoredText(textColor, ManaSymbols.replaceSymbolsWithHTML("" + message + " Profanity detected. Type: /w " + SessionHandler.getUserName() + " profanity 0' to turn the filter off", ManaSymbols.Type.CHAT))); + this.txtConversation.append(text.toString()); + } else if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_USE_PROFANITY_FILTER, "0").equals("2")) { + text.append(getColoredText(textColor, ManaSymbols.replaceSymbolsWithHTML("" + username + ": Profanity detected. To make it less strict, type: /w " + SessionHandler.getUserName() + " profanity 1", ManaSymbols.Type.CHAT))); + this.txtConversation.append(text.toString()); } - text.append(getColoredText(textColor, ManaSymbols.replaceSymbolsWithHTML(message, ManaSymbols.Type.CHAT))); - this.txtConversation.append(text.toString()); } protected String getColoredText(String color, String text) { diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index da61f41dfb0..4423038e08b 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -98,6 +98,7 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_GAME_SHOW_STORM_COUNTER = "gameShowStormCounter"; public static final String KEY_GAME_CONFIRM_EMPTY_MANA_POOL = "gameConfirmEmptyManaPool"; public static final String KEY_GAME_ASK_MOVE_TO_GRAVE_ORDER = "gameAskMoveToGraveORder"; + public static final String KEY_GAME_USE_PROFANITY_FILTER = "gameUseProfanityFilter"; public static final String KEY_GUI_TABLE_FONT_SIZE = "guiTableFontSize"; public static final String KEY_GUI_CHAT_FONT_SIZE = "guiChatFontSize"; diff --git a/Mage.Server/src/main/java/mage/server/ChatManager.java b/Mage.Server/src/main/java/mage/server/ChatManager.java index fe8305bdc8d..8c6903ff35a 100644 --- a/Mage.Server/src/main/java/mage/server/ChatManager.java +++ b/Mage.Server/src/main/java/mage/server/ChatManager.java @@ -110,13 +110,6 @@ public class ChatManager { this.broadcast(chatId, userName, message, color, withTime, messageType, null); } - private boolean containsSwearing(String message) { - if (message != null && message.toLowerCase().matches("^.*(anal|asshole|balls|bastard|bitch|blowjob|cock|crap|cunt|cum|damn|dick|dildo|douche|fag|fuck|idiot|moron|penis|piss|prick|pussy|rape|rapist|sex|screw|shit|slut|vagina).*$")) { - return true; - } - return false; - } - final Pattern cardNamePattern = Pattern.compile("\\[(.*?)\\]"); public void broadcast(UUID chatId, String userName, String message, MessageColor color, boolean withTime, MessageType messageType, SoundToPlay soundToPlay) { @@ -170,11 +163,6 @@ public class ChatManager { } userMessages.put(userName, message); - if (containsSwearing(messageToCheck)) { - String informUser = "Your message appears to contain profanity"; - chatSessions.get(chatId).broadcastInfoToUser(user, informUser); - return; - } } if (messageType == MessageType.TALK) { diff --git a/Utils/gen-card.pl b/Utils/gen-card.pl index 44bf93cadaa..16e6e71efe0 100755 --- a/Utils/gen-card.pl +++ b/Utils/gen-card.pl @@ -110,7 +110,7 @@ if (!exists $cards{$cardName}) { # Check if card is already implemented my $fileName = "../Mage.Sets/src/mage/cards/".substr($cardName, 0, 1)."/".toCamelCase($cardName).".java"; if(-e $fileName) { - die "$cardName is already implemented.\n"; + die "$cardName is already implemented.\n$fileName\n"; } # Generate lines to corresponding sets From 70453f1ac3b6125766af8e7d4c692f17e549d928 Mon Sep 17 00:00:00 2001 From: spjspj Date: Fri, 27 Jan 2017 18:19:45 +1100 Subject: [PATCH 43/44] Modify the profanity filter to push it back to client side only. --- .../java/mage/client/chat/ChatPanelBasic.java | 21 ++++++++++++------- .../client/remote/CallbackClientImpl.java | 3 ++- .../main/java/mage/server/ChatManager.java | 2 ++ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java b/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java index 939f1579216..aef5b49ca8a 100644 --- a/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java +++ b/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java @@ -187,33 +187,38 @@ public class ChatPanelBasic extends javax.swing.JPanel { } } - Pattern profanityPattern = Pattern.compile(".*(1ab1a|1d1ot|13ch|13p3r|13sb1ans|13sbo|13s13|13sb1an|13sbo|13sy|1nbr3d|1nc3st|1njun|1ub3|\\Wbj|\\Wcum|\\Wdum|\\Wfag|\\Wfap|\\Wfuk|\\Wj1s|\\Wp3do|\\Wp33|\\Wpoo\\W|\\Wt1t|aho13|an1l1ngu|ana1|anus|ar3o1a|ar3o13|ary1an|ashat|asho13|asmast3r|asmunch|asw1p3|b1atch|b1gt1t|b1mbo|b1ow|b1tch|ba1ls|bab3|bang|barf|bastard|bawdy|b3an3r|b3ard3dc1am|b3ast1al1ty|b3atch|b3at3r|b3av3r|b3otch|b3yotch|bo1nk|bod1ly|bon3d|bon3r|bon3|boob|boot13|booty|bow31|br3ast|bugg3r|bukak3|bung|busty|butt|c11t|caca|cahon3|cam31to3|carp3tmunch3r|cawk|c3rv1x|ch1nc|ch1nk|chod3|co1tal|cockb1ock|cockho1st3r|cocknock3r|cocksmok3r|cocksuck3r|cock|condom|coon|corksuck3r|crabs|cums1ut|cumshot|cumsta1n|cun1l1ngus|cuntfac3|cunthunt3r|cunt|d1ck|d1k3|d1ldo|d1mw1t|d1ngl3|d1psh1p|dago|dam1t|damn1t|damn3d|damn|dawg13styl3|dog13styl3|dogysty13|dong|dop3y|douch3|drunk|dumas|dumbas|dumy|dyk3|3jacu1at3|3n1arg3m3nt|3r3ct1on|3r3ct|3rot1c|3xtacy|3xtasy|f.ck|f1osy|f1st3d|f1st1ng|f1sty|fa1gt|fa1g|fack|fag1t|fag3d|fagot|fag|fcuk|f31at1o|f31at3|f31ch1ng|f31ch3r|f31ch|f31tch3r|f31tch|foad|fobar|fond13|for3sk1n|fu.k|fudg3pack3r|fuk|g1ans|g1golo|ganja|ghay|gh3y|go1d3nshow3r|gonad|gook|gr1ngo|h1tl3r|handjob|hardon|hokah|hok3r|homo|honky|hoor|hootch|hoot3r|horny|hump1ng|hump3d|hump|hym3n|j1sm|j1s3d|j1sm|j1s|jackas|jackho13|jackof|j3rk3d|j3rkof|j3rk|junk13|junky|k1an|k1k3|k1nky|knob3nd|kyk3|mams|masa|mast3rba|masturba|max1|m3ns3s|m3nstruat|mfuck1ng|mofo|moron|moth3rf|mthrf|muff|n1gl|n1g|n1mrod|n1ny|n1pl3|nak3d|napa1m|napy|nas1|n3gro|noky|nympho|op1at3|op1um|ora1y|ora1|org13s|organ|orgasm|orgy|ovary|ovum|p1lowb1t3r|p1mp|p1nko|p1s3d|p1ssof|p1ss|pak1|pant13|panty|past13|pasty|p3ck3r|p3doph1l|p33p33|p3n1al|p3n1l3|p3n1s|p3n3trat1on|p3n3trat3|p3rv3rs1on|p3yot3|pha11c|phuck|po1ack|po1ock|poontang|poon|poop|porno|porn|pr1ck|pr1g|pron|pub1|pub3|punkas|punky|puss1|pussy|puto|qu1cky|qu1ck13|qu1m|qu3af|qu3ro|qu3rs|qu3r|r1mjob|r1tard|racy|rap1st|rap3d|rap3r|rap3|raunch|r31ch|r3cta1|r3ctum|r3ctus|r3tard|r3tar|rtard|rumpram3r|rump|s1av3|s13as|s1ut|sack|sad1s|scag|scant1ly|sch1ong|sch1so|scr3w|scrog|scrot|scrud|scum|s3aman|s3am3n|s3duc3|s3m3n|s3xua1|sh1t|skag|skank|sm3gma|smut|sn1p3r|snatch|sodom|sp1ck|sp1c|sp1k|sp3rm|spunk|st3amy|stfu|ston3d|str1p|strok3|stup1d|suck|sumofab1atch|t1nkl3|t1tfuck|tampon|tard|t3abag1ng|t3at|t3st1|t3st3|t3urd|thrust|tramp|trans|trashy|twat|ug1y|unw3d|ur1n3a|ut3rus|vag1na|vu1gar|vu1va|w1g3r|wang|wank3r|wank|w31n3r|w31rdo|w3dg13|w3n13|w3tback|w3w3|wh1t3y|wh1s|whor3|womb).*"); - Pattern profanity2Pattern = Pattern.compile(".*(1ab1a|1d1ot|13ch|13p3r|13sb1ans|13sbo|13s13|13sb1an|13sbo|13sy|1nbr3d|1nc3st|1njun|1ub3|\\Wbj|\\Wcum|\\Wdum|\\Wfag|\\Wfap|\\Wfuk|\\Wj1s|\\Wp3do|\\Wp3|\\Wpo\\W|\\Wt1t|aho13|an1l1ngu|ana1|anus|ar3o1a|ar3o13|ary1an|ashat|asho13|asmast3r|asmunch|asw1p3|b1atch|b1gt1t|b1mbo|b1ow|b1tch|ba1ls|bab3|bang|barf|bastard|bawdy|b3an3r|b3ard3dc1am|b3ast1al1ty|b3atch|b3at3r|b3av3r|b3otch|b3yotch|bo1nk|bod1ly|bon3d|bon3r|bon3|bob|bot13|boty|bow31|br3ast|bug3r|bukak3|bung|busty|but|c1t|caca|cahon3|cam31to3|carp3tmunch3r|cawk|c3rv1x|ch1nc|ch1nk|chod3|co1tal|cockb1ock|cockho1st3r|cocknock3r|cocksmok3r|cocksuck3r|cock|condom|con|corksuck3r|crabs|cums1ut|cumshot|cumsta1n|cun1l1ngus|cuntfac3|cunthunt3r|cunt|d1ck|d1k3|d1ldo|d1mw1t|d1ngl3|d1psh1p|dago|dam1t|damn1t|damn3d|damn|dawg13styl3|dog13styl3|dogysty13|dong|dop3y|douch3|drunk|dumas|dumbas|dumy|dyk3|3jacu1at3|3n1arg3m3nt|3r3ct1on|3r3ct|3rot1c|3xtacy|3xtasy|f.ck|f1osy|f1st3d|f1st1ng|f1sty|fa1gt|fa1g|fack|fag1t|fag3d|fagot|fag|fcuk|f31at1o|f31at3|f31ch1ng|f31ch3r|f31ch|f31tch3r|f31tch|foad|fobar|fond13|for3sk1n|fu.k|fudg3pack3r|fuk|g1ans|g1golo|ganja|ghay|gh3y|go1d3nshow3r|gonad|gr1ngo|h1tl3r|handjob|hardon|hokah|hok3r|homo|honky|hor|hotch|hot3r|horny|hump1ng|hump3d|hump|hym3n|j1sm|j1s3d|j1sm|j1s|jackas|jackho13|jackof|j3rk3d|j3rkof|j3rk|junk13|junky|k1an|k1k3|k1nky|knob3nd|kyk3|mams|masa|mast3rba|masturba|max1|m3ns3s|m3nstruat|mfuck1ng|mofo|moron|moth3rf|mthrf|muf|n1gl|n1g|n1mrod|n1ny|n1pl3|nak3d|napa1m|napy|nas1|n3gro|noky|nympho|op1at3|op1um|ora1y|ora1|org13s|organ|orgasm|orgy|ovary|ovum|p1lowb1t3r|p1mp|p1nko|p1s3d|p1sof|p1s|pak1|pant13|panty|past13|pasty|p3ck3r|p3doph1l|p3p3|p3n1al|p3n1l3|p3n1s|p3n3trat1on|p3n3trat3|p3rv3rs1on|p3yot3|pha1c|phuck|po1ack|po1ock|pontang|pon|pop|porno|porn|pr1ck|pr1g|pron|pub1|pub3|punkas|punky|pus1|pusy|puto|qu1cky|qu1ck13|qu1m|qu3af|qu3ro|qu3rs|qu3r|r1mjob|r1tard|racy|rap1st|rap3d|rap3r|rap3|raunch|r31ch|r3cta1|r3ctum|r3ctus|r3tard|r3tar|rtard|rumpram3r|rump|s1av3|s13as|s1ut|sack|sad1s|scag|scant1ly|sch1ong|sch1so|scr3w|scrog|scrot|scrud|scum|s3aman|s3am3n|s3duc3|s3m3n|s3xua1|sh1t|skag|skank|sm3gma|smut|sn1p3r|snatch|sodom|sp1ck|sp1c|sp1k|sp3rm|spunk|st3amy|stfu|ston3d|str1p|strok3|stup1d|suck|sumofab1atch|t1nkl3|t1tfuck|tampon|tard|t3abag1ng|t3at|t3st1|t3st3|t3urd|thrust|tramp|trans|trashy|twat|ug1y|unw3d|ur1n3a|ut3rus|vag1na|vu1gar|vu1va|w1g3r|wang|wank3r|wank|w31n3r|w31rdo|w3dg13|w3n13|w3tback|w3w3|wh1t3y|wh1s|whor3|womb).*"); - + Pattern profanityPattern = Pattern.compile(".*(1ab1a|1d1ot|13ch|13p3r|13sb1ans|13sbo|13s13|13sb1an|13sbo|13sy|1nbr3d|1nc3st|1njun|1ub3|\\Wbj|\\Wcum|\\Wdum|\\Wfag|\\Wfap|\\W[sf]uk|\\Wj1s|\\Wp3do|\\Wp33|\\Wpoo\\W|\\Wt1t|aho13|an1ngu|ana1|anus|ar3o1a|ar3o13|ary1an|axyx|axyxhat|axyxho13|axyxmast3r|axyxmunch|axyxw1p3|b1atch|b1gt1t|b1mbo|b1ow|b1tch|ba1s|bab3|bang|barf|bastard|bawdy|b3an3r|b3ard3dc1am|b3ast1a1ty|b3atch|b3at3r|b3av3r|b3otch|b3yotch|bo1nk|bod1y|bon3d|bon3r|bon3|bob|bot13|boty|bow31|br3ast|bug3r|bukak3|bung|busty|butt|c1t|caca|cahon3|cam31to3|carp3tmunch3r|cawk|c3rv1x|ch1nc|ch1nk|chod3|co1ta1|cockb1ock|cockho1st3r|cocknock3r|cocksmok3r|cocksuck3r|cock|condom|con|corksuck3r|crabs|cums1ut|cumshot|cumsta1n|cnt|cun1ngus|cuntfac3|cunthunt3r|cunt|d1ck|d1k3|d1do|d1mw1t|d1ng13|d1psh1p|dago|dam1t|damn1t|damn3d|damn|dawg13sty13|dog13sty13|dogysty13|dong|dop3y|douch3|drunk|dumb|dumas|dum|dumbas|dumy|dyk3|3jacu1at3|3n1arg3m3nt|3r3ct1on|3r3ct|3rot1c|3xtacy|3xtasy|[sf].ck|f1osy|f1st3d|f1st1ng|f1sty|fa1gt|fa1g|fack|fag1t|fag3d|fagot|fag|[sf]cuk|f31at1o|f31at3|f31ch1ng|f31ch3r|f31ch|f31tch3r|f31tch|foad|fobar|fond13|for3sk1n|fu.k|fudg3pack3r|[sf]uk|g1ans|g1go1o|ganja|ghay|gh3y|go1d3nshow3r|gonad|gok|gr1ngo|h1t13r|handjob|hardon|hokah|hok3r|homo|honky|hor|hotch|hot3r|horny|hump1ng|hump3d|hump|hym3n|j1sm|j1s3d|j1sm|j1s|jackas|jackho13|jackof|j3rk3d|j3rkof|j3rk|junk13|junky|k1an|k1k3|k1nky|knob3nd|kyk3|mams|masa|mast3rba|masturba|max1|m3ns3s|m3nstruat|m[sf]uck1ng|mofo|moron|moth3rf|mthrf|muf|n1g1|n1g|n1mrod|n1ny|n1p13|nak3d|napa1m|napy|nas1|n3gro|noky|nympho|op1at3|op1um|ora1y|ora1|org13s|organ|orgasm|orgy|ovary|ovum|p1owb1t3r|p1mp|p1nko|p1s3d|p1sof|p1s|pak1|pant13|panty|past13|pasty|p3ck3r|p3doph1|p3p3|p3n1a1|p3n13|p3n1s|p3n3trat1on|p3n3trat3|p3rv3rs1on|p3yot3|pha1c|phuck|po1ack|po1ock|pontang|pon|pop|porno|porn|pr1ck|pr1g|pron|pub1|pub3|punkas|punky|pus1|pusy|puto|qu1cky|qu1ck13|qu1m|qu3af|qu3ro|qu3rs|qu3r|r1mjob|r1tard|racy|rap1st|rap3d|rap3r|rap3|raunch|r31ch|r3cta1|r3ctum|r3ctus|r3tard|r3tar|rtard|rumpram3r|rump|s1av3|s13as|s1ut|sack|sad1s|scag|sch1ong|sch1so|scr3w|scrog|scrot|scrud|scum|s3aman|s3am3n|s3duc3|s3m3n|s3xua1|sh1t|skag|skank|sm3gma|smut|sn1p3r|snatch|sodom|sp1ck|sp1c|sp1k|sp3rm|spunk|st3amy|stfu|ston3d|str1p|strok3|stup1d|suck|sumofab1atch|t1nk13|t1t[sf]uck|tampon|tard|t3abag1ng|t3at|t3st1|t3st3|t3urd|thrust|tramp|trans|trashy|twat|ug1y|unw3d|ur1n3a|ut3rus|vag1na|vu1gar|vu1va|w1g3r|wang|wank3r|wank|w31n3r|w31rdo|w3dg13|w3n13|w3tback|w3w3|wh1t3y|wh1s|whor3|womb).*"); + Pattern profanity2Pattern = Pattern.compile(".*(1ab1a|1d1ot|13ch|13p3r|13sb1ans|13sbo|13s13|13sb1an|13sbo|13sy|1nbr3d|1nc3st|1njun|1ub3|\\Wbj|\\Wcum|\\Wdum|\\Wfag|\\Wfap|\\W[sf]uk|\\Wj1s|\\Wp3do|\\Wp3|\\Wpo\\W|\\Wt1t|aho13|an1ngu|ana1|anus|ar3o1a|ar3o13|ary1an|axyx|axyxhat|axyxho13|axyxmast3r|axyxmunch|axyxw1p3|b1atch|b1gt1t|b1mbo|b1ow|b1tch|ba1s|bab3|bang|barf|bastard|bawdy|b3an3r|b3ard3dc1am|b3ast1a1ty|b3atch|b3at3r|b3av3r|b3otch|b3yotch|bo1nk|bod1y|bon3d|bon3r|bon3|bob|bot13|boty|bow31|br3ast|bug3r|bukak3|bung|busty|but|c1t|caca|cahon3|cam31to3|carp3tmunch3r|cawk|c3rv1x|ch1nc|ch1nk|chod3|co1ta1|cockb1ock|cockho1st3r|cocknock3r|cocksmok3r|cocksuck3r|cock|condom|con|corksuck3r|crabs|cums1ut|cumshot|cumsta1n|cnt|cun1ngus|cuntfac3|cunthunt3r|cunt|d1ck|d1k3|d1do|d1mw1t|d1ng13|d1psh1p|dago|dam1t|damn1t|damn3d|damn|dawg13sty13|dog13sty13|dogysty13|dong|dop3y|douch3|drunk|dumb|dum|dumas|dumbas|dumy|dyk3|3jacu1at3|3n1arg3m3nt|3r3ct1on|3r3ct|3rot1c|3xtacy|3xtasy|[sf].ck|f1osy|f1st3d|f1st1ng|f1sty|fa1gt|fa1g|fack|fag1t|fag3d|fagot|fag|[sf]cuk|f31at1o|f31at3|f31ch1ng|f31ch3r|f31ch|f31tch3r|f31tch|foad|fobar|fond13|for3sk1n|fu.k|fudg3pack3r|[sf]uk|g1ans|g1go1o|ganja|ghay|gh3y|go1d3nshow3r|gonad|gr1ngo|h1t13r|handjob|hardon|hokah|hok3r|homo|honky|hor|hotch|hot3r|horny|hump1ng|hump3d|hump|hym3n|j1sm|j1s3d|j1sm|j1s|jackas|jackho13|jackof|j3rk3d|j3rkof|j3rk|junk13|junky|k1an|k1k3|k1nky|knob3nd|kyk3|mams|masa|mast3rba|masturba|max1|m3ns3s|m3nstruat|m[sf]uck1ng|mofo|moron|moth3rf|mthrf|muf|n1g1|n1g|n1mrod|n1ny|n1p13|nak3d|napa1m|napy|nas1|n3gro|noky|nympho|op1at3|op1um|ora1y|ora1|org13s|organ|orgasm|orgy|ovary|ovum|p1owb1t3r|p1mp|p1nko|p1s3d|p1sof|p1s|pak1|pant13|panty|past13|pasty|p3ck3r|p3doph1|p3p3|p3n1a1|p3n13|p3n1s|p3n3trat1on|p3n3trat3|p3rv3rs1on|p3yot3|pha1c|phuck|po1ack|po1ock|pontang|pon|pop|porno|porn|pr1ck|pr1g|pron|pub1|pub3|punkas|punky|pus1|pusy|puto|qu1cky|qu1ck13|qu1m|qu3af|qu3ro|qu3rs|qu3r|r1mjob|r1tard|racy|rap1st|rap3d|rap3r|rap3|raunch|r31ch|r3cta1|r3ctum|r3ctus|r3tard|r3tar|rtard|rumpram3r|rump|s1av3|s13as|s1ut|sack|sad1s|scag|sch1ong|sch1so|scr3w|scrog|scrot|scrud|scum|s3aman|s3am3n|s3duc3|s3m3n|s3xua1|sh1t|skag|skank|sm3gma|smut|sn1p3r|snatch|sodom|sp1ck|sp1c|sp1k|sp3rm|spunk|st3amy|stfu|ston3d|str1p|strok3|stup1d|suck|sumofab1atch|t1nk13|t1t[sf]uck|tampon|tard|t3abag1ng|t3at|t3st1|t3st3|t3urd|thrust|tramp|trans|trashy|twat|ug1y|unw3d|ur1n3a|ut3rus|vag1na|vu1gar|vu1va|w1g3r|wang|wank3r|wank|w31n3r|w31rdo|w3dg13|w3n13|w3tback|w3w3|wh1t3y|wh1s|whor3|womb).*"); + private boolean containsSwearing(String message, String level) { - String orig = message; - message = message.replaceAll("\\W", "."); + + if (level.equals("0")) { + return false; + } message = "." + message + "."; message = message.toLowerCase(); - message = message.replaceAll("(.)(\\1{2,})", "$1"); + message = message.replaceAll("[a@]([s5]+)", "axyx"); + message = message.replaceAll("(.)(\\1{1,})", "$1"); message = message.replaceAll("[@]", "a"); message = message.replaceAll("[il]", "1"); message = message.replaceAll("[e]", "3"); message = message.replaceAll("[0]", "o"); message = message.replaceAll("[5z]", "s"); + message = message.replaceAll("\\W", "."); + message = message.replaceAll("(.)(\\1{1,})", "$1"); + message = message.replaceAll("\\.", ""); Matcher matchPattern = profanityPattern.matcher(message); if (matchPattern.find()) { - System.out.println("message: Matched profanity:" + message); return true; } if (level.equals("2")) { message = message.replaceAll("\\.", ""); + message = "." + message + "."; matchPattern = profanity2Pattern.matcher(message); if (matchPattern.find()) { - System.out.println("message: Matched profanity (level2):" + message); return true; } } diff --git a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java index a5b8bcd5571..c2bd89eb958 100644 --- a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java +++ b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java @@ -421,7 +421,8 @@ public class CallbackClientImpl implements CallbackClient { case TABLES: usedPanel.receiveMessage("", new StringBuilder("Download card images by using the \"Images\" menu to the top right .") .append("
Download icons and symbols by using the \"Symbols\" menu to the top right.") - .append("
\\list - Show a list of available chat commands.").toString(), + .append("
\\list - Show a list of available chat commands.") + .append("
Type \\w yourUserName profanity 0 (or 1 or 2) to turn off/on the profanity filter").toString(), null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE); break; diff --git a/Mage.Server/src/main/java/mage/server/ChatManager.java b/Mage.Server/src/main/java/mage/server/ChatManager.java index 8c6903ff35a..cb08e771824 100644 --- a/Mage.Server/src/main/java/mage/server/ChatManager.java +++ b/Mage.Server/src/main/java/mage/server/ChatManager.java @@ -195,6 +195,7 @@ public class ChatManager { String command = message.substring(1).trim().toUpperCase(Locale.ENGLISH); if (doError) { message += new StringBuilder("
Invalid User Command '" + message + "'.").append(COMMANDS_LIST).toString(); + message += "
Type \\w " + user.getName() + " profanity 0 (or 1 or 2) to use/not use the profanity filter"; chatSessions.get(chatId).broadcastInfoToUser(user, message); return true; } @@ -230,6 +231,7 @@ public class ChatManager { } if (command.equals("L") || command.equals("LIST")) { message += COMMANDS_LIST; + message += "
Type \\w " + user.getName() + " profanity 0 (or 1 or 2) to use/not use the profanity filter"; chatSessions.get(chatId).broadcastInfoToUser(user, message); return true; } From 8ebed087a560dcaf14810699c998879d8326fc46 Mon Sep 17 00:00:00 2001 From: spjspj Date: Sat, 28 Jan 2017 12:28:11 +1100 Subject: [PATCH 44/44] Modify the profanity filter to push it back to client side only. --- .../src/main/java/mage/client/chat/ChatPanelBasic.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java b/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java index aef5b49ca8a..c370581d9a1 100644 --- a/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java +++ b/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java @@ -187,8 +187,8 @@ public class ChatPanelBasic extends javax.swing.JPanel { } } - Pattern profanityPattern = Pattern.compile(".*(1ab1a|1d1ot|13ch|13p3r|13sb1ans|13sbo|13s13|13sb1an|13sbo|13sy|1nbr3d|1nc3st|1njun|1ub3|\\Wbj|\\Wcum|\\Wdum|\\Wfag|\\Wfap|\\W[sf]uk|\\Wj1s|\\Wp3do|\\Wp33|\\Wpoo\\W|\\Wt1t|aho13|an1ngu|ana1|anus|ar3o1a|ar3o13|ary1an|axyx|axyxhat|axyxho13|axyxmast3r|axyxmunch|axyxw1p3|b1atch|b1gt1t|b1mbo|b1ow|b1tch|ba1s|bab3|bang|barf|bastard|bawdy|b3an3r|b3ard3dc1am|b3ast1a1ty|b3atch|b3at3r|b3av3r|b3otch|b3yotch|bo1nk|bod1y|bon3d|bon3r|bon3|bob|bot13|boty|bow31|br3ast|bug3r|bukak3|bung|busty|butt|c1t|caca|cahon3|cam31to3|carp3tmunch3r|cawk|c3rv1x|ch1nc|ch1nk|chod3|co1ta1|cockb1ock|cockho1st3r|cocknock3r|cocksmok3r|cocksuck3r|cock|condom|con|corksuck3r|crabs|cums1ut|cumshot|cumsta1n|cnt|cun1ngus|cuntfac3|cunthunt3r|cunt|d1ck|d1k3|d1do|d1mw1t|d1ng13|d1psh1p|dago|dam1t|damn1t|damn3d|damn|dawg13sty13|dog13sty13|dogysty13|dong|dop3y|douch3|drunk|dumb|dumas|dum|dumbas|dumy|dyk3|3jacu1at3|3n1arg3m3nt|3r3ct1on|3r3ct|3rot1c|3xtacy|3xtasy|[sf].ck|f1osy|f1st3d|f1st1ng|f1sty|fa1gt|fa1g|fack|fag1t|fag3d|fagot|fag|[sf]cuk|f31at1o|f31at3|f31ch1ng|f31ch3r|f31ch|f31tch3r|f31tch|foad|fobar|fond13|for3sk1n|fu.k|fudg3pack3r|[sf]uk|g1ans|g1go1o|ganja|ghay|gh3y|go1d3nshow3r|gonad|gok|gr1ngo|h1t13r|handjob|hardon|hokah|hok3r|homo|honky|hor|hotch|hot3r|horny|hump1ng|hump3d|hump|hym3n|j1sm|j1s3d|j1sm|j1s|jackas|jackho13|jackof|j3rk3d|j3rkof|j3rk|junk13|junky|k1an|k1k3|k1nky|knob3nd|kyk3|mams|masa|mast3rba|masturba|max1|m3ns3s|m3nstruat|m[sf]uck1ng|mofo|moron|moth3rf|mthrf|muf|n1g1|n1g|n1mrod|n1ny|n1p13|nak3d|napa1m|napy|nas1|n3gro|noky|nympho|op1at3|op1um|ora1y|ora1|org13s|organ|orgasm|orgy|ovary|ovum|p1owb1t3r|p1mp|p1nko|p1s3d|p1sof|p1s|pak1|pant13|panty|past13|pasty|p3ck3r|p3doph1|p3p3|p3n1a1|p3n13|p3n1s|p3n3trat1on|p3n3trat3|p3rv3rs1on|p3yot3|pha1c|phuck|po1ack|po1ock|pontang|pon|pop|porno|porn|pr1ck|pr1g|pron|pub1|pub3|punkas|punky|pus1|pusy|puto|qu1cky|qu1ck13|qu1m|qu3af|qu3ro|qu3rs|qu3r|r1mjob|r1tard|racy|rap1st|rap3d|rap3r|rap3|raunch|r31ch|r3cta1|r3ctum|r3ctus|r3tard|r3tar|rtard|rumpram3r|rump|s1av3|s13as|s1ut|sack|sad1s|scag|sch1ong|sch1so|scr3w|scrog|scrot|scrud|scum|s3aman|s3am3n|s3duc3|s3m3n|s3xua1|sh1t|skag|skank|sm3gma|smut|sn1p3r|snatch|sodom|sp1ck|sp1c|sp1k|sp3rm|spunk|st3amy|stfu|ston3d|str1p|strok3|stup1d|suck|sumofab1atch|t1nk13|t1t[sf]uck|tampon|tard|t3abag1ng|t3at|t3st1|t3st3|t3urd|thrust|tramp|trans|trashy|twat|ug1y|unw3d|ur1n3a|ut3rus|vag1na|vu1gar|vu1va|w1g3r|wang|wank3r|wank|w31n3r|w31rdo|w3dg13|w3n13|w3tback|w3w3|wh1t3y|wh1s|whor3|womb).*"); - Pattern profanity2Pattern = Pattern.compile(".*(1ab1a|1d1ot|13ch|13p3r|13sb1ans|13sbo|13s13|13sb1an|13sbo|13sy|1nbr3d|1nc3st|1njun|1ub3|\\Wbj|\\Wcum|\\Wdum|\\Wfag|\\Wfap|\\W[sf]uk|\\Wj1s|\\Wp3do|\\Wp3|\\Wpo\\W|\\Wt1t|aho13|an1ngu|ana1|anus|ar3o1a|ar3o13|ary1an|axyx|axyxhat|axyxho13|axyxmast3r|axyxmunch|axyxw1p3|b1atch|b1gt1t|b1mbo|b1ow|b1tch|ba1s|bab3|bang|barf|bastard|bawdy|b3an3r|b3ard3dc1am|b3ast1a1ty|b3atch|b3at3r|b3av3r|b3otch|b3yotch|bo1nk|bod1y|bon3d|bon3r|bon3|bob|bot13|boty|bow31|br3ast|bug3r|bukak3|bung|busty|but|c1t|caca|cahon3|cam31to3|carp3tmunch3r|cawk|c3rv1x|ch1nc|ch1nk|chod3|co1ta1|cockb1ock|cockho1st3r|cocknock3r|cocksmok3r|cocksuck3r|cock|condom|con|corksuck3r|crabs|cums1ut|cumshot|cumsta1n|cnt|cun1ngus|cuntfac3|cunthunt3r|cunt|d1ck|d1k3|d1do|d1mw1t|d1ng13|d1psh1p|dago|dam1t|damn1t|damn3d|damn|dawg13sty13|dog13sty13|dogysty13|dong|dop3y|douch3|drunk|dumb|dum|dumas|dumbas|dumy|dyk3|3jacu1at3|3n1arg3m3nt|3r3ct1on|3r3ct|3rot1c|3xtacy|3xtasy|[sf].ck|f1osy|f1st3d|f1st1ng|f1sty|fa1gt|fa1g|fack|fag1t|fag3d|fagot|fag|[sf]cuk|f31at1o|f31at3|f31ch1ng|f31ch3r|f31ch|f31tch3r|f31tch|foad|fobar|fond13|for3sk1n|fu.k|fudg3pack3r|[sf]uk|g1ans|g1go1o|ganja|ghay|gh3y|go1d3nshow3r|gonad|gr1ngo|h1t13r|handjob|hardon|hokah|hok3r|homo|honky|hor|hotch|hot3r|horny|hump1ng|hump3d|hump|hym3n|j1sm|j1s3d|j1sm|j1s|jackas|jackho13|jackof|j3rk3d|j3rkof|j3rk|junk13|junky|k1an|k1k3|k1nky|knob3nd|kyk3|mams|masa|mast3rba|masturba|max1|m3ns3s|m3nstruat|m[sf]uck1ng|mofo|moron|moth3rf|mthrf|muf|n1g1|n1g|n1mrod|n1ny|n1p13|nak3d|napa1m|napy|nas1|n3gro|noky|nympho|op1at3|op1um|ora1y|ora1|org13s|organ|orgasm|orgy|ovary|ovum|p1owb1t3r|p1mp|p1nko|p1s3d|p1sof|p1s|pak1|pant13|panty|past13|pasty|p3ck3r|p3doph1|p3p3|p3n1a1|p3n13|p3n1s|p3n3trat1on|p3n3trat3|p3rv3rs1on|p3yot3|pha1c|phuck|po1ack|po1ock|pontang|pon|pop|porno|porn|pr1ck|pr1g|pron|pub1|pub3|punkas|punky|pus1|pusy|puto|qu1cky|qu1ck13|qu1m|qu3af|qu3ro|qu3rs|qu3r|r1mjob|r1tard|racy|rap1st|rap3d|rap3r|rap3|raunch|r31ch|r3cta1|r3ctum|r3ctus|r3tard|r3tar|rtard|rumpram3r|rump|s1av3|s13as|s1ut|sack|sad1s|scag|sch1ong|sch1so|scr3w|scrog|scrot|scrud|scum|s3aman|s3am3n|s3duc3|s3m3n|s3xua1|sh1t|skag|skank|sm3gma|smut|sn1p3r|snatch|sodom|sp1ck|sp1c|sp1k|sp3rm|spunk|st3amy|stfu|ston3d|str1p|strok3|stup1d|suck|sumofab1atch|t1nk13|t1t[sf]uck|tampon|tard|t3abag1ng|t3at|t3st1|t3st3|t3urd|thrust|tramp|trans|trashy|twat|ug1y|unw3d|ur1n3a|ut3rus|vag1na|vu1gar|vu1va|w1g3r|wang|wank3r|wank|w31n3r|w31rdo|w3dg13|w3n13|w3tback|w3w3|wh1t3y|wh1s|whor3|womb).*"); + Pattern profanityPattern = Pattern.compile(".*(1ab1a|1d1ot|13p3r|13sb1ans|13sbo|13s13|13sb1an|13sbo|13sy|1nbr3d|1nc3st|1njun|1ub3|\\Wbj|\\Wcum|\\Wdum|\\Wfag|\\Wfap|\\W[sf]uk|\\Wj1s|\\Wp3do|\\Wp33|\\Wpoo\\W|\\Wt1t|aho13|an1ngu|ana1|anus|ar3o1a|ar3o13|ary1an|axyx|axyxhat|axyxho13|axyxmast3r|axyxmunch|axyxw1p3|b1atch|b1gt1t|b1mbo|b1ow|b1tch|ba1s|bab3|bang|barf|bastard|bawdy|b3an3r|b3ard3dc1am|b3ast1a1ty|b3atch|b3at3r|b3av3r|b3otch|b3yotch|bo1nk|bod1y|bon3d|bon3r|bon3|bob|bot13|boty|bow31|br3ast|bug3r|bukak3|bung|busty|buxyx|c1t|caca|cahon3|cam31to3|carp3tmunch3r|cawk|c3rv1x|ch1nc|ch1nk|chod3|co1ta1|cockb1ock|cockho1st3r|cocknock3r|cocksmok3r|cocksuck3r|cock|condom|corksuck3r|crabs|cums1ut|cumshot|cumsta1n|cnt|cun1ngus|cuntfac3|cunthunt3r|cunt|d1ck|d1k3|d1do|d1mw1t|d1ng13|d1psh1p|dago|dam1t|damn1t|damn3d|damn|dawg13sty13|dog13sty13|dogysty13|dong|dop3y|douch3|drunk|dumb|dumas|dum|dumbas|dumy|dyk3|3jacu1at3|3n1arg3m3nt|3r3ct1on|3r3ct|3rot1c|3xtacy|3xtasy|f.ck|f1osy|f1st3d|f1st1ng|f1sty|fa1gt|fa1g|fack|fag1t|fag3d|fagot|fag|[sf]cuk|f31at1o|f31at3|f31ch1ng|f31ch3r|f31ch|f31tch3r|f31tch|foad|fobar|fond13|for3sk1n|fu.k|fudg3pack3r|[sf]uk|g1ans|g1go1o|ganja|ghay|gh3y|go1d3nshow3r|gonad|gok|gr1ngo|h1t13r|handjob|hardon|hokah|hok3r|homo|honky|hor|hotch|hot3r|horny|hump1ng|hump3d|hump|hym3n|j1sm|j1s3d|j1sm|j1s|jackas|jackho13|jackof|j3rk3d|j3rkof|j3rk|junk13|junky|k1an|k1k3|k1nky|knob3nd|kyk3|mams|masa|mast3rba|masturba|max1|m3ns3s|m3nstruat|m[sf]uck1ng|mofo|moron|moth3rf|mthrf|muf|n1ger|n1ga|n1mrod|n1ny|n1p13|nak3d|napa1m|napy|nas1|n3gro|noky|nympho|op1at3|op1um|ora1y|ora1|org13s|organ|orgasm|orgy|ovary|ovum|p1owb1t3r|p1mp|p1nko|p1s3d|p1sof|p1s|pak1|pant13|panty|past13|pasty|p3ck3r|p3doph1|p3p3|p3n1a1|p3n13|p3n1s|p3n3trat1on|p3n3trat3|p3rv3rs1on|p3yot3|pha1c|phuck|po1ack|po1ock|pontang|pop|pr1ck|pr1g|pron|pub1|pub3|punkas|punky|pus1|pusy|puto|qu1cky|qu1ck13|qu1m|qu3af|qu3ro|qu3rs|qu3r|r1mjob|r1tard|racy|rap1st|rap3d|rap3r|rap3|raunch|r31ch|r3cta1|r3ctum|r3ctus|r3tard|r3tar|rtard|rumpram3r|rump|s1av3|s13as|s1ut|sack|sad1s|scag|sch1ong|sch1so|scr3w|scrog|scrot|scrud|scum|s3aman|s3am3n|s3duc3|s3m3n|s3xua1|sh1t|skag|skank|sm3gma|smut|sn1p3r|snatch|sodom|sp1ck|sp1c|sp1k|sp3rm|spunk|st3amy|stfu|ston3d|str1p|strok3|stup1d|suck|sumofab1atch|t1nk13|t1t[sf]uck|tampon|tard|t3abag1ng|t3at|t3st1|t3st3|t3urd|thrust|tramp|trans|trashy|twat|ug1y|unw3d|ur1n3a|ut3rus|vag1na|vu1gar|vu1va|w1g3r|wang|wank3r|wank|w31n3r|w31rdo|w3dg13|w3n13|w3tback|w3w3|wh1t3y|wh1s|whor3).*"); + Pattern profanity2Pattern = Pattern.compile(".*(1ab1a|1d1ot|13p3r|13sb1ans|13sbo|13s13|13sb1an|13sbo|13sy|1nbr3d|1nc3st|1njun|1ub3|\\Wbj|\\Wcum|\\Wdum|\\Wfag|\\Wfap|\\W[sf]uk|\\Wj1s|\\Wp3do|\\Wp3|\\Wpo\\W|\\Wt1t|aho13|an1ngu|ana1|anus|ar3o1a|ar3o13|ary1an|axyx|axyxhat|axyxho13|axyxmast3r|axyxmunch|axyxw1p3|b1atch|b1gt1t|b1mbo|b1ow|b1tch|ba1s|bab3|bang|barf|bastard|bawdy|b3an3r|b3ard3dc1am|b3ast1a1ty|b3atch|b3at3r|b3av3r|b3otch|b3yotch|bo1nk|bod1y|bon3d|bon3r|bon3|bob|bot13|boty|bow31|br3ast|bug3r|bukak3|bung|busty|buxyx|c1t|caca|cahon3|cam31to3|carp3tmunch3r|cawk|c3rv1x|ch1nc|ch1nk|chod3|co1ta1|cockb1ock|cockho1st3r|cocknock3r|cocksmok3r|cocksuck3r|cock|condom|corksuck3r|crabs|cums1ut|cumshot|cumsta1n|cnt|cun1ngus|cuntfac3|cunthunt3r|cunt|d1ck|d1k3|d1do|d1mw1t|d1ng13|d1psh1p|dago|dam1t|damn1t|damn3d|damn|dawg13sty13|dog13sty13|dogysty13|dong|dop3y|douch3|drunk|dumb|dum|dumas|dumbas|dumy|dyk3|3jacu1at3|3n1arg3m3nt|3r3ct1on|3r3ct|3rot1c|3xtacy|3xtasy|f.ck|f1osy|f1st3d|f1st1ng|f1sty|fa1gt|fa1g|fack|fag1t|fag3d|fagot|fag|[sf]cuk|f31at1o|f31at3|f31ch1ng|f31ch3r|f31ch|f31tch3r|f31tch|foad|fobar|fond13|for3sk1n|fu.k|fudg3pack3r|[sf]uk|g1ans|g1go1o|ganja|ghay|gh3y|go1d3nshow3r|gonad|gr1ngo|h1t13r|handjob|hardon|hokah|hok3r|homo|honky|hor|hotch|hot3r|horny|hump1ng|hump3d|hump|hym3n|j1sm|j1s3d|j1sm|j1s|jackas|jackho13|jackof|j3rk3d|j3rkof|j3rk|junk13|junky|k1an|k1k3|k1nky|knob3nd|kyk3|mams|masa|mast3rba|masturba|max1|m3ns3s|m3nstruat|m[sf]uck1ng|mofo|moron|moth3rf|mthrf|muf|n1ga|n1ger|n1mrod|n1ny|n1p13|nak3d|napa1m|napy|nas1|n3gro|noky|nympho|op1at3|op1um|ora1y|ora1|org13s|organ|orgasm|orgy|ovary|ovum|p1owb1t3r|p1mp|p1nko|p1s3d|p1sof|p1s|pak1|pant13|panty|past13|pasty|p3ck3r|p3doph1|p3p3|p3n1a1|p3n13|p3n1s|p3n3trat1on|p3n3trat3|p3rv3rs1on|p3yot3|pha1c|phuck|po1ack|po1ock|pontang|pop|porno|porn|pr1ck|pr1g|pron|pub1|pub3|punkas|punky|pus1|pusy|puto|qu1cky|qu1ck13|qu1m|qu3af|qu3ro|qu3rs|qu3r|r1mjob|r1tard|racy|rap1st|rap3d|rap3r|rap3|raunch|r31ch|r3cta1|r3ctum|r3ctus|r3tard|r3tar|rtard|rumpram3r|rump|s1av3|s13as|s1ut|sack|sad1s|scag|sch1ong|sch1so|scr3w|scrog|scrot|scrud|scum|s3aman|s3am3n|s3duc3|s3m3n|s3xua1|sh1t|skag|skank|sm3gma|smut|sn1p3r|snatch|sodom|sp1ck|sp1c|sp1k|sp3rm|spunk|st3amy|stfu|ston3d|str1p|strok3|stup1d|suck|sumofab1atch|t1nk13|t1t[sf]uck|tampon|tard|t3abag1ng|t3at|t3st1|t3st3|t3urd|thrust|tramp|trans|trashy|twat|ug1y|unw3d|ur1n3a|ut3rus|vag1na|vu1gar|vu1va|w1g3r|wang|wank3r|wank|w31n3r|w31rdo|w3dg13|w3n13|w3tback|w3w3|wh1t3y|wh1s|whor3).*"); private boolean containsSwearing(String message, String level) { @@ -198,7 +198,8 @@ public class ChatPanelBasic extends javax.swing.JPanel { message = "." + message + "."; message = message.toLowerCase(); - message = message.replaceAll("[a@]([s5]+)", "axyx"); + message = message.replaceAll("[a@]([s5][s5]+)", "axyx"); + message = message.replaceAll("b.([t\\+][t\\+]+)", "buxyx"); message = message.replaceAll("(.)(\\1{1,})", "$1"); message = message.replaceAll("[@]", "a"); message = message.replaceAll("[il]", "1");