This commit is contained in:
Goudt 2017-02-04 22:16:40 +01:00
commit b36583356c
32 changed files with 893 additions and 144 deletions

View file

@ -1,5 +1,6 @@
XMage.de 1 (Europe/Germany) fast :xmage.de:17171
woogerworks (North America/USA) :xmage.woogerworks.com:17171
xmage.lukeskywalk.com (North America) :xmage.lukeskywalk.com:17171
XMageBr. (South America/Brazil) :magic.ncs3sistemas.com.br:17171
XMage.tahiti :xmage.tahiti.one:443
Seedds Server (Asia) :115.29.203.80:17171

View file

@ -44,7 +44,6 @@ import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.zip.GZIPOutputStream;
import mage.MageException;
import mage.abilities.Ability;
import mage.cards.Card;
@ -313,10 +312,10 @@ public class GameController implements GameCallback {
logger.fatal("- userId: " + userId);
return;
}
if (!user.isPresent()) {
logger.fatal("User not found : "+userId);
return;
}
if (!user.isPresent()) {
logger.fatal("User not found : " + userId);
return;
}
Player player = game.getPlayer(playerId);
if (player == null) {
logger.fatal("Player not found - playerId: " + playerId);
@ -350,8 +349,9 @@ public class GameController implements GameCallback {
private void sendInfoAboutPlayersNotJoinedYet() {
for (Player player : game.getPlayers().values()) {
if (!player.hasLeft() && player.isHuman()) {
User user = getUserByPlayerId(player.getId()).get();
if (user != null) {
Optional<User> requestedUser = getUserByPlayerId(player.getId());
if (requestedUser.isPresent()) {
User user = requestedUser.get();
if (!user.isConnected()) {
if (gameSessions.get(player.getId()) == null) {
// join the game because player has not joined are was removed because of disconnect

View file

@ -27,6 +27,10 @@
*/
package mage.server.game;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import mage.cards.Cards;
import mage.choices.Choice;
import mage.constants.ManaType;
@ -41,11 +45,6 @@ import mage.server.util.ThreadExecutor;
import mage.view.*;
import org.apache.log4j.Logger;
import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -92,39 +91,39 @@ public class GameSessionPlayer extends GameSessionWatcher {
public void chooseAbility(final AbilityPickerView abilities) {
if (!killed) {
UserManager.getInstance().getUser(userId).ifPresent(user ->
user.fireCallback(new ClientCallback("gameChooseAbility", game.getId(), abilities)));
UserManager.getInstance().getUser(userId).ifPresent(user
-> user.fireCallback(new ClientCallback("gameChooseAbility", game.getId(), abilities)));
}
}
public void choosePile(final String message, final CardsView pile1, final CardsView pile2) {
if (!killed) {
UserManager.getInstance().getUser(userId).ifPresent(user ->
user.fireCallback(new ClientCallback("gameChoosePile", game.getId(), new GameClientMessage(message, pile1, pile2))));
UserManager.getInstance().getUser(userId).ifPresent(user
-> user.fireCallback(new ClientCallback("gameChoosePile", game.getId(), new GameClientMessage(message, pile1, pile2))));
}
}
public void chooseChoice(final Choice choice) {
if (!killed) {
UserManager.getInstance().getUser(userId).ifPresent(user ->
user.fireCallback(new ClientCallback("gameChooseChoice", game.getId(), new GameClientMessage(choice))));
UserManager.getInstance().getUser(userId).ifPresent(user
-> user.fireCallback(new ClientCallback("gameChooseChoice", game.getId(), new GameClientMessage(choice))));
}
}
public void playMana(final String message, final Map<String, Serializable> options) {
if (!killed) {
UserManager.getInstance().getUser(userId).ifPresent(user ->
user.fireCallback(new ClientCallback("gamePlayMana", game.getId(), new GameClientMessage(getGameView(), message, options))));
UserManager.getInstance().getUser(userId).ifPresent(user
-> user.fireCallback(new ClientCallback("gamePlayMana", game.getId(), new GameClientMessage(getGameView(), message, options))));
}
}
public void playXMana(final String message) {
if (!killed) {
UserManager.getInstance().getUser(userId).ifPresent(user ->
user.fireCallback(new ClientCallback("gamePlayXMana", game.getId(), new GameClientMessage(getGameView(), message))));
UserManager.getInstance().getUser(userId).ifPresent(user
-> user.fireCallback(new ClientCallback("gamePlayXMana", game.getId(), new GameClientMessage(getGameView(), message))));
}
}
@ -149,7 +148,7 @@ public class GameSessionPlayer extends GameSessionWatcher {
if (!killed) {
Optional<User> requestingUser = UserManager.getInstance().getUser(requestingUserId);
Optional<User> requestedUser = UserManager.getInstance().getUser(userId);
if (!requestedUser.isPresent() && !requestingUser.isPresent()) {
if (requestedUser.isPresent() && requestingUser.isPresent()) {
String message;
switch (numberTurns) {
case 0:
@ -180,7 +179,7 @@ public class GameSessionPlayer extends GameSessionWatcher {
UserRequestMessage userRequestMessage = new UserRequestMessage(
"User request",
"Allow user <b>" + watcher.get().getName() + "</b> for this match to see your hand cards?<br>"
+ "(You can revoke this every time using related popup menu item of your battlefield.)");
+ "(You can revoke this every time using related popup menu item of your battlefield.)");
userRequestMessage.setRelatedUser(watcherId, watcher.get().getName());
userRequestMessage.setGameId(game.getId());
userRequestMessage.setButton1("Accept", PlayerAction.ADD_PERMISSION_TO_SEE_HAND_CARDS);

View file

@ -40,6 +40,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.filter.common.FilterCreaturePermanent;
/**
*
@ -58,7 +59,7 @@ public class AnkleShanker extends CardImpl {
// Haste
this.addAbility(HasteAbility.getInstance());
// Whenever Ankle Shanker attacks, creatures you control gain first strike and deathtouch until end of turn.
Effect effect = new GainAbilityControlledEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn);
Effect effect = new GainAbilityControlledEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn, new FilterCreaturePermanent("Creatures"));
effect.setText("creatures you control gain first strike");
Ability ability = new AttacksTriggeredAbility(effect, false);
effect = new GainAbilityControlledEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn);

View file

@ -25,15 +25,14 @@
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.a;
import java.util.UUID;
import mage.constants.CardType;
import mage.abilities.keyword.CascadeAbility;
import mage.abilities.keyword.ExaltedAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
/**
*
@ -41,17 +40,17 @@ import mage.cards.CardSetInfo;
*/
public class ArdentPlea extends CardImpl {
public ArdentPlea (UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}{U}");
public ArdentPlea(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{U}");
// Exalted (Whenever a creature you control attacks alone, that creature gets +1/+1 until end of turn.)
this.addAbility(new ExaltedAbility());
// Cascade (When you cast this spell, exile cards from the top of your library until you exile a nonland card that costs less. You may cast it without paying its mana cost. Put the exiled cards on the bottom in a random order.)
this.addAbility(new CascadeAbility());
}
public ArdentPlea (final ArdentPlea card) {
public ArdentPlea(final ArdentPlea card) {
super(card);
}

View file

@ -0,0 +1,81 @@
/*
* 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.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.FlashAbility;
import mage.constants.AttachmentType;
import mage.constants.Zone;
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 Buoyancy extends CardImpl {
public Buoyancy(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}");
this.subtype.add("Aura");
// Flash
this.addAbility(FlashAbility.getInstance());
// 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);
// Enchanted creature has flying.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA)));
}
public Buoyancy(final Buoyancy card) {
super(card);
}
@Override
public Buoyancy copy() {
return new Buoyancy(this);
}
}

View file

@ -45,22 +45,22 @@ import mage.target.common.TargetCreaturePermanent;
*/
public class DeathRattle extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent();
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nongreen creature");
static {
filter.add(Predicates.not(new ColorPredicate(ObjectColor.GREEN)));
}
public DeathRattle(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{5}{B}");
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{5}{B}");
// Delve
this.addAbility(new DelveAbility());
// Destroy target nongreen creature. It can't be regenerated.
this.getSpellAbility().addEffect(new DestroyTargetEffect(true));
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
}
public DeathRattle(final DeathRattle card) {

View file

@ -27,22 +27,23 @@
*/
package mage.cards.d;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageObject;
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.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentToken;
import mage.game.permanent.token.ClueArtifactToken;
import mage.game.permanent.token.Token;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
@ -53,7 +54,7 @@ import mage.target.common.TargetCreaturePermanent;
public class DeclarationInStone extends CardImpl {
public DeclarationInStone(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{W}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}");
// Exile target creature and all other creatures its controller controls with the same name as that creature.
// That player investigates for each nontoken creature exiled this way.
@ -73,12 +74,6 @@ public class DeclarationInStone extends CardImpl {
class DeclarationInStoneEffect extends OneShotEffect {
private static final FilterCreaturePermanent creaturesOnly = new FilterCreaturePermanent();
private static final FilterCreaturePermanent nonTokenFilter = new FilterCreaturePermanent("nontoken creature");
static{
nonTokenFilter.add(Predicates.not(new TokenPredicate()));
}
public DeclarationInStoneEffect() {
super(Outcome.Exile);
staticText = "Exile target creature and all other creatures its controller controls with the same name as that creature. That player investigates for each nontoken creature exiled this way.";
@ -90,39 +85,34 @@ class DeclarationInStoneEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
UUID exileId = source.getSourceId();
Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (targetPermanent != null) {
UUID controllerPermanentId = targetPermanent.getControllerId();
Player you = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source.getSourceId());
if (sourceObject != null && exileId != null && you != null) {
int exiledCount = 0;
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source.getSourceId());
if (sourceObject != null && controller != null) {
Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (targetPermanent != null) {
Set<Card> cardsToExile = new HashSet<>();
int nonTokenCount = 0;
if (targetPermanent.getName().isEmpty()) { // face down creature
you.moveCardToExileWithInfo(targetPermanent, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true);
exiledCount = 1; // will always be 1 with a face down creature (has no name)
cardsToExile.add(targetPermanent);
if (!(targetPermanent instanceof PermanentToken)) {
nonTokenCount++;
}
} else {
String name = targetPermanent.getName();
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(controllerPermanentId)) {
if (permanent != null && permanent.getName().equals(name)) {
// only exile creatures (reported bug on awakened lands targetted exiling all other lands of same name)
if (creaturesOnly.match(permanent, game)) {
you.moveCardToExileWithInfo(permanent, null, "", source.getSourceId(), game, Zone.BATTLEFIELD, true);
}
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), targetPermanent.getControllerId(), game)) {
if (!permanent.getId().equals(targetPermanent.getId())
&& permanent.getName().equals(targetPermanent.getName())) {
cardsToExile.add(permanent);
// exiled count only matters for non-tokens
if (nonTokenFilter.match(permanent, game)) {
exiledCount++;
if (!(permanent instanceof PermanentToken)) {
nonTokenCount++;
}
}
}
}
if (exiledCount > 0) {
Token token = new ClueArtifactToken();
token.putOntoBattlefield(exiledCount, game, source.getSourceId(), controllerPermanentId, false, false);
controller.moveCards(cardsToExile, Zone.EXILED, source, game);
game.applyEffects();
if (nonTokenCount > 0) {
new ClueArtifactToken().putOntoBattlefield(nonTokenCount, game, source.getSourceId(), targetPermanent.getControllerId(), false, false);
}
return true;
}
@ -135,4 +125,4 @@ class DeclarationInStoneEffect extends OneShotEffect {
public DeclarationInStoneEffect copy() {
return new DeclarationInStoneEffect(this);
}
}
}

View file

@ -28,14 +28,13 @@
package mage.cards.e;
import java.util.UUID;
import mage.constants.CardType;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapTargetCost;
import mage.abilities.effects.common.UntapTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterControlledPermanent;
@ -43,8 +42,8 @@ import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.filter.predicate.mageobject.SupertypePredicate;
import mage.filter.predicate.permanent.TappedPredicate;
import mage.target.TargetPermanent;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetControlledPermanent;
/**
* @author Loki
@ -61,12 +60,11 @@ public class Earthcraft extends CardImpl {
}
public Earthcraft(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{G}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}");
// Tap an untapped creature you control: Untap target basic land.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new UntapTargetEffect(), new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filterCreature, true)));
ability.addTarget(new TargetControlledPermanent(filterLand));
ability.addTarget(new TargetPermanent(filterLand));
this.addAbility(ability);
}

View file

@ -0,0 +1,71 @@
/*
* 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.f;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.EnchantedSourceCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Zone;
/**
*
* @author Galatolol
*/
public class FledglingOsprey extends CardImpl {
public FledglingOsprey(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}");
this.subtype.add("Bird");
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// Fledgling Osprey has flying as long as it's enchanted.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield),
new EnchantedSourceCondition(),
"{this} has flying as long as it's enchanted")));
}
public FledglingOsprey(final FledglingOsprey card) {
super(card);
}
@Override
public FledglingOsprey copy() {
return new FledglingOsprey(this);
}
}

View file

@ -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.f;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Zone;
/**
*
* @author Galatolol
*/
public class FlowstoneThopter extends CardImpl {
public FlowstoneThopter(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{7}");
this.subtype.add("Thopter");
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// {1}: Flowstone Thopter gets +1/-1 and gains flying until end of turn.
Effect effect = new BoostSourceEffect(1, -1, Duration.EndOfTurn);
effect.setText("{this} gets +1/-1");
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}"));
effect = new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn);
effect.setText("and gains flying until end of turn.");
ability.addEffect(effect);
this.addAbility(ability);
}
public FlowstoneThopter(final FlowstoneThopter card) {
super(card);
}
@Override
public FlowstoneThopter copy() {
return new FlowstoneThopter(this);
}
}

View file

@ -0,0 +1,64 @@
/*
* 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.f;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.StaticFilters;
import mage.target.TargetPlayer;
/**
*
* @author Galatolol
*/
public class FuriousAssault extends CardImpl {
public FuriousAssault(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}");
// Whenever you cast a creature spell, Furious Assault deals 1 damage to target player.
Ability ability = new SpellCastControllerTriggeredAbility(new DamageTargetEffect(1), StaticFilters.FILTER_SPELL_A_CREATURE, false);
ability.addTarget(new TargetPlayer());
this.addAbility(ability);
}
public FuriousAssault(final FuriousAssault card) {
super(card);
}
@Override
public FuriousAssault copy() {
return new FuriousAssault(this);
}
}

View file

@ -0,0 +1,100 @@
/*
* 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.n;
import java.util.UUID;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.common.GainLifeEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
/**
*
* @author Galatolol
*/
public class NobleStand extends CardImpl {
public NobleStand(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{W}");
// Whenever a creature you control blocks, you gain 2 life.
this.addAbility(new NobleStandAbility());
}
public NobleStand(final NobleStand card) {
super(card);
}
@Override
public NobleStand copy() {
return new NobleStand(this);
}
}
class NobleStandAbility extends TriggeredAbilityImpl {
public NobleStandAbility() {
super(Zone.BATTLEFIELD, new GainLifeEffect(2));
}
public NobleStandAbility(final mage.cards.n.NobleStandAbility ability) {
super(ability);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent();
filter.add(Predicates.not(new TokenPredicate()));
Permanent permanent = (Permanent) game.getPermanent(event.getSourceId());
return permanent != null && filter.match(permanent, sourceId, controllerId, game);
}
@Override
public String getRule() {
return "Whenever a creature you control blocks, you gain 2 life.";
}
@Override
public mage.cards.n.NobleStandAbility copy() {
return new mage.cards.n.NobleStandAbility(this);
}
}

View file

@ -0,0 +1,74 @@
/*
* 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.o;
import java.util.UUID;
import mage.abilities.common.TapForManaAllTriggeredAbility;
import mage.abilities.common.TapForManaAllTriggeredManaAbility;
import mage.abilities.effects.common.AddManaOfAnyTypeProducedEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SetTargetPointer;
import mage.filter.common.FilterLandPermanent;
/**
*
* @author elliott-king
*/
public class Overabundance extends CardImpl {
public Overabundance(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{G}");
// Whenever a player taps a land for mana, that player adds one mana to his or her mana pool of any type that land produced, and Overabundance deals 1 damage to him or her.
this.addAbility(new TapForManaAllTriggeredManaAbility(
new AddManaOfAnyTypeProducedEffect(),
new FilterLandPermanent( "a player taps a land"),
SetTargetPointer.PERMANENT
));
this.addAbility(new TapForManaAllTriggeredAbility(
new DamageTargetEffect(1, true, "that player"),
new FilterLandPermanent("a player taps a land"),
SetTargetPointer.PLAYER
));
}
public Overabundance(final Overabundance card) {
super(card);
}
@Override
public Overabundance copy() {
return new Overabundance(this);
}
}

View file

@ -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,12 +20,11 @@
* 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.o;
import java.util.UUID;
@ -51,8 +50,8 @@ import mage.game.permanent.Permanent;
public class OverwhelmingStampede extends CardImpl {
public OverwhelmingStampede(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{G}{G}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}{G}");
// Until end of turn, creatures you control gain trample and get +X/+X, where X is the greatest power among creatures you control.
this.getSpellAbility().addEffect(new OverwhelmingStampedeInitEffect());
}
@ -68,30 +67,30 @@ public class OverwhelmingStampede extends CardImpl {
}
class OverwhelmingStampedeInitEffect extends OneShotEffect {
public OverwhelmingStampedeInitEffect() {
super(Outcome.BoostCreature);
this.staticText = "Until end of turn, creatures you control gain trample and get +X/+X, where X is the greatest power among creatures you control";
}
public OverwhelmingStampedeInitEffect(final OverwhelmingStampedeInitEffect effect) {
super(effect);
}
@Override
public OverwhelmingStampedeInitEffect copy() {
return new OverwhelmingStampedeInitEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
int maxPower = 0;
for (Permanent perm: game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) {
for (Permanent perm : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), game)) {
if (perm.getPower().getValue() > maxPower) {
maxPower = perm.getPower().getValue();
}
}
ContinuousEffect effect = new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.EndOfStep, new FilterCreaturePermanent());
ContinuousEffect effect = new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, new FilterCreaturePermanent());
game.addEffect(effect, source);
if (maxPower != 0) {
effect = new BoostControlledEffect(maxPower, maxPower, Duration.EndOfTurn);

View file

@ -0,0 +1,83 @@
/*
* 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.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.CounterTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.filter.FilterSpell;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.target.TargetSpell;
/**
*
* @author anonymous
*/
public class StrongholdMachinist extends CardImpl {
private static final FilterSpell filter = new FilterSpell("noncreature spell");
static {
filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE)));
}
public StrongholdMachinist(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}");
this.subtype.add("Human");
this.subtype.add("Spellshaper");
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// {U}{U}, {tap}, Discard a card: Counter target noncreature spell.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new ManaCostsImpl("{U}{U}"));
ability.addCost(new TapSourceCost());
ability.addCost(new DiscardCardCost());
ability.addTarget(new TargetSpell(filter));
this.addAbility(ability);
}
public StrongholdMachinist(final StrongholdMachinist card) {
super(card);
}
@Override
public StrongholdMachinist copy() {
return new StrongholdMachinist(this);
}
}

View file

@ -74,7 +74,7 @@ public class TezzeretTheSchemer extends CardImpl {
// -2: Target creature gets +X/-X until end of turn, where X is the number of artifacts you control.
DynamicValue count = new PermanentsOnBattlefieldCount(new FilterControlledArtifactPermanent("artifacts you control"));
Effect effect = new BoostTargetEffect(count, new SignInversionDynamicValue(count), Duration.EndOfTurn);
Effect effect = new BoostTargetEffect(count, new SignInversionDynamicValue(count), Duration.EndOfTurn, true);
effect.setText("Target creature gets +X/-X until end of turn, where X is the number of artifacts you control");
Ability ability = new LoyaltyAbility(effect, -2);
ability.addTarget(new TargetCreaturePermanent());

View file

@ -0,0 +1,85 @@
/*
* 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.v;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.MorphAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.filter.common.FilterAttackingOrBlockingCreature;
import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.target.common.TargetCreaturePermanent;
/**
*
* @author Galatolol
*/
public class VenomspoutBrackus extends CardImpl {
private static final FilterAttackingOrBlockingCreature filter = new FilterAttackingOrBlockingCreature(
"attacking or blocking creature with flying");
static {
filter.add(new AbilityPredicate(FlyingAbility.class));
}
public VenomspoutBrackus(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{G}");
this.subtype.add("Beast");
this.power = new MageInt(5);
this.toughness = new MageInt(5);
// {1}{G}, {tap}: Venomspout Brackus deals 5 damage to target attacking or blocking creature with flying.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl("{1}{G}"));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetCreaturePermanent(filter));
this.addAbility(ability);
// Morph {3}{G}{G}
this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{G}{G}")));
}
public VenomspoutBrackus(final VenomspoutBrackus card) {
super(card);
}
@Override
public VenomspoutBrackus copy() {
return new VenomspoutBrackus(this);
}
}

View file

@ -206,6 +206,7 @@ public class Invasion extends ExpansionSet {
cards.add(new SetCardInfo("Opt", 64, Rarity.COMMON, mage.cards.o.Opt.class));
cards.add(new SetCardInfo("Ordered Migration", 258, Rarity.UNCOMMON, mage.cards.o.OrderedMigration.class));
cards.add(new SetCardInfo("Orim's Touch", 23, Rarity.COMMON, mage.cards.o.OrimsTouch.class));
cards.add(new SetCardInfo("Overabundance", 259, Rarity.RARE, mage.cards.o.Overabundance.class));
cards.add(new SetCardInfo("Overload", 157, Rarity.COMMON, mage.cards.o.Overload.class));
cards.add(new SetCardInfo("Pain // Suffering", 294, Rarity.UNCOMMON, mage.cards.p.PainSuffering.class));
cards.add(new SetCardInfo("Phantasmal Terrain", 65, Rarity.COMMON, mage.cards.p.PhantasmalTerrain.class));

View file

@ -71,6 +71,7 @@ public class MercadianMasques extends ExpansionSet {
cards.add(new SetCardInfo("Bog Witch", 118, Rarity.COMMON, mage.cards.b.BogWitch.class));
cards.add(new SetCardInfo("Brainstorm", 61, Rarity.COMMON, mage.cards.b.Brainstorm.class));
cards.add(new SetCardInfo("Bribery", 62, Rarity.RARE, mage.cards.b.Bribery.class));
cards.add(new SetCardInfo("Buoyancy", 63, Rarity.COMMON, mage.cards.b.Buoyancy.class));
cards.add(new SetCardInfo("Cackling Witch", 119, Rarity.UNCOMMON, mage.cards.c.CacklingWitch.class));
cards.add(new SetCardInfo("Cateran Brute", 120, Rarity.COMMON, mage.cards.c.CateranBrute.class));
cards.add(new SetCardInfo("Cateran Enforcer", 121, Rarity.UNCOMMON, mage.cards.c.CateranEnforcer.class));
@ -139,6 +140,7 @@ public class MercadianMasques extends ExpansionSet {
cards.add(new SetCardInfo("Fountain of Cho", 317, Rarity.UNCOMMON, mage.cards.f.FountainOfCho.class));
cards.add(new SetCardInfo("Fountain Watch", 19, Rarity.RARE, mage.cards.f.FountainWatch.class));
cards.add(new SetCardInfo("Fresh Volunteers", 20, Rarity.COMMON, mage.cards.f.FreshVolunteers.class));
cards.add(new SetCardInfo("Furious Assault", 191, Rarity.COMMON, mage.cards.f.FuriousAssault.class));
cards.add(new SetCardInfo("Gerrard's Irregulars", 192, Rarity.COMMON, mage.cards.g.GerrardsIrregulars.class));
cards.add(new SetCardInfo("Ghoul's Feast", 137, Rarity.UNCOMMON, mage.cards.g.GhoulsFeast.class));
cards.add(new SetCardInfo("Giant Caterpillar", 249, Rarity.COMMON, mage.cards.g.GiantCaterpillar.class));

View file

@ -81,6 +81,7 @@ public class Nemesis extends ExpansionSet {
cards.add(new SetCardInfo("Flowstone Crusher", 81, Rarity.COMMON, mage.cards.f.FlowstoneCrusher.class));
cards.add(new SetCardInfo("Flowstone Overseer", 82, Rarity.RARE, mage.cards.f.FlowstoneOverseer.class));
cards.add(new SetCardInfo("Flowstone Slide", 83, Rarity.RARE, mage.cards.f.FlowstoneSlide.class));
cards.add(new SetCardInfo("Flowstone Thopter", 132, Rarity.UNCOMMON, mage.cards.f.FlowstoneThopter.class));
cards.add(new SetCardInfo("Flowstone Wall", 86, Rarity.COMMON, mage.cards.f.FlowstoneWall.class));
cards.add(new SetCardInfo("Infiltrate", 33, Rarity.COMMON, mage.cards.i.Infiltrate.class));
cards.add(new SetCardInfo("Jolting Merfolk", 34, Rarity.UNCOMMON, mage.cards.j.JoltingMerfolk.class));
@ -96,6 +97,7 @@ public class Nemesis extends ExpansionSet {
cards.add(new SetCardInfo("Mogg Salvage", 94, Rarity.UNCOMMON, mage.cards.m.MoggSalvage.class));
cards.add(new SetCardInfo("Murderous Betrayal", 61, Rarity.RARE, mage.cards.m.MurderousBetrayal.class));
cards.add(new SetCardInfo("Netter en-Dal", 13, Rarity.COMMON, mage.cards.n.NetterEnDal.class));
cards.add(new SetCardInfo("Noble Stand", 14, Rarity.UNCOMMON, mage.cards.n.NobleStand.class));
cards.add(new SetCardInfo("Off Balance", 15, Rarity.COMMON, mage.cards.o.OffBalance.class));
cards.add(new SetCardInfo("Oracle's Attendants", 16, Rarity.RARE, mage.cards.o.OraclesAttendants.class));
cards.add(new SetCardInfo("Oraxid", 35, Rarity.COMMON, mage.cards.o.Oraxid.class));
@ -142,6 +144,7 @@ public class Nemesis extends ExpansionSet {
cards.add(new SetCardInfo("Stampede Driver", 122, Rarity.UNCOMMON, mage.cards.s.StampedeDriver.class));
cards.add(new SetCardInfo("Stronghold Discipline", 73, Rarity.COMMON, mage.cards.s.StrongholdDiscipline.class));
cards.add(new SetCardInfo("Stronghold Gambit", 100, Rarity.RARE, mage.cards.s.StrongholdGambit.class));
cards.add(new SetCardInfo("Stronghold Machinist", 46, Rarity.UNCOMMON, mage.cards.s.StrongholdMachinist.class));
cards.add(new SetCardInfo("Stronghold Zeppelin", 47, Rarity.UNCOMMON, mage.cards.s.StrongholdZeppelin.class));
cards.add(new SetCardInfo("Submerge", 48, Rarity.UNCOMMON, mage.cards.s.Submerge.class));
cards.add(new SetCardInfo("Tangle Wire", 139, Rarity.RARE, mage.cards.t.TangleWire.class));

View file

@ -53,10 +53,9 @@ public class Onslaught extends ExpansionSet {
cards.add(new SetCardInfo("Blackmail", 127, Rarity.UNCOMMON, mage.cards.b.Blackmail.class));
cards.add(new SetCardInfo("Blatant Thievery", 71, Rarity.RARE, mage.cards.b.BlatantThievery.class));
cards.add(new SetCardInfo("Blistering Firecat", 189, Rarity.RARE, mage.cards.b.BlisteringFirecat.class));
cards.add(new SetCardInfo("Bloodline Shaman", 249, Rarity.UNCOMMON, mage.cards.b.BloodlineShaman.class));
cards.add(new SetCardInfo("Bloodstained Mire", 313, Rarity.RARE, mage.cards.b.BloodstainedMire.class, new CardGraphicInfo(new ObjectColor("RB"), null,
false)));
cards.add(new SetCardInfo("Bloodline Shaman", 249, Rarity.UNCOMMON, mage.cards.b.BloodlineShaman.class));
cards.add(new SetCardInfo("Bloodline Shaman", 249, Rarity.UNCOMMON, mage.cards.b.BloodlineShaman.class));
cards.add(new SetCardInfo("Bloodstained Mire", 313, Rarity.RARE, mage.cards.b.BloodstainedMire.class, new CardGraphicInfo(new ObjectColor("RB"), null,false)));
cards.add(new SetCardInfo("Bloodline Shaman", 249, Rarity.UNCOMMON, mage.cards.b.BloodlineShaman.class));
cards.add(new SetCardInfo("Boneknitter", 128, Rarity.UNCOMMON, mage.cards.b.Boneknitter.class));
cards.add(new SetCardInfo("Brightstone Ritual", 191, Rarity.COMMON, mage.cards.b.BrightstoneRitual.class));
cards.add(new SetCardInfo("Broodhatch Nantuko", 250, Rarity.UNCOMMON, mage.cards.b.BroodhatchNantuko.class));
@ -289,6 +288,7 @@ public class Onslaught extends ExpansionSet {
cards.add(new SetCardInfo("True Believer", 57, Rarity.RARE, mage.cards.t.TrueBeliever.class));
cards.add(new SetCardInfo("Undead Gladiator", 178, Rarity.RARE, mage.cards.u.UndeadGladiator.class));
cards.add(new SetCardInfo("Unholy Grotto", 327, Rarity.RARE, mage.cards.u.UnholyGrotto.class));
cards.add(new SetCardInfo("Venomspout Brackus", 295, Rarity.UNCOMMON, mage.cards.v.VenomspoutBrackus.class));
cards.add(new SetCardInfo("Visara the Dreadful", 179, Rarity.RARE, mage.cards.v.VisaraTheDreadful.class));
cards.add(new SetCardInfo("Vitality Charm", 296, Rarity.COMMON, mage.cards.v.VitalityCharm.class));
cards.add(new SetCardInfo("Voice of the Woods", 297, Rarity.RARE, mage.cards.v.VoiceOfTheWoods.class));
@ -301,17 +301,17 @@ public class Onslaught extends ExpansionSet {
cards.add(new SetCardInfo("Wellwisher", 300, Rarity.COMMON, mage.cards.w.Wellwisher.class));
cards.add(new SetCardInfo("Wheel and Deal", 121, Rarity.RARE, mage.cards.w.WheelAndDeal.class));
cards.add(new SetCardInfo("Whipcorder", 60, Rarity.UNCOMMON, mage.cards.w.Whipcorder.class));
cards.add(new SetCardInfo("Windswept Heath", 328, Rarity.RARE, mage.cards.w.WindsweptHeath.class, new CardGraphicInfo(new ObjectColor("GW"), null,
false)));
cards.add(new SetCardInfo("Bloodline Shaman", 249, Rarity.UNCOMMON, mage.cards.b.BloodlineShaman.class));
cards.add(new SetCardInfo("Windswept Heath", 328, Rarity.RARE, mage.cards.w.WindsweptHeath.class, new CardGraphicInfo(new ObjectColor("GW"), null, false)));
cards.add(new SetCardInfo("Bloodline Shaman", 249, Rarity.UNCOMMON, mage.cards.b.BloodlineShaman.class));
cards.add(new SetCardInfo("Venomspout Brackus", 295, Rarity.UNCOMMON, mage.cards.v.VenomspoutBrackus.class));
cards.add(new SetCardInfo("Wirewood Elf", 301, Rarity.COMMON, mage.cards.w.WirewoodElf.class));
cards.add(new SetCardInfo("Wirewood Herald", 302, Rarity.COMMON, mage.cards.w.WirewoodHerald.class));
cards.add(new SetCardInfo("Wirewood Lodge", 329, Rarity.RARE, mage.cards.w.WirewoodLodge.class));
cards.add(new SetCardInfo("Wirewood Pride", 303, Rarity.COMMON, mage.cards.w.WirewoodPride.class));
cards.add(new SetCardInfo("Wirewood Savage", 304, Rarity.COMMON, mage.cards.w.WirewoodSavage.class));
cards.add(new SetCardInfo("Wooded Foothills", 330, Rarity.RARE, mage.cards.w.WoodedFoothills.class, new CardGraphicInfo(new ObjectColor("RG"), null,
false)));
cards.add(new SetCardInfo("Bloodline Shaman", 249, Rarity.UNCOMMON, mage.cards.b.BloodlineShaman.class));
cards.add(new SetCardInfo("Wooded Foothills", 330, Rarity.RARE, mage.cards.w.WoodedFoothills.class, new CardGraphicInfo(new ObjectColor("RG"), null, false)));
cards.add(new SetCardInfo("Bloodline Shaman", 249, Rarity.UNCOMMON, mage.cards.b.BloodlineShaman.class));
cards.add(new SetCardInfo("Venomspout Brackus", 295, Rarity.UNCOMMON, mage.cards.v.VenomspoutBrackus.class));
cards.add(new SetCardInfo("Words of War", 244, Rarity.RARE, mage.cards.w.WordsOfWar.class));
cards.add(new SetCardInfo("Words of Wind", 122, Rarity.RARE, mage.cards.w.WordsOfWind.class));
cards.add(new SetCardInfo("Words of Worship", 61, Rarity.RARE, mage.cards.w.WordsOfWorship.class));

View file

@ -88,6 +88,7 @@ public class UrzasDestiny extends ExpansionSet {
cards.add(new SetCardInfo("False Prophet", 6, Rarity.RARE, mage.cards.f.FalseProphet.class));
cards.add(new SetCardInfo("Field Surgeon", 8, Rarity.COMMON, mage.cards.f.FieldSurgeon.class));
cards.add(new SetCardInfo("Flame Jet", 81, Rarity.COMMON, mage.cards.f.FlameJet.class));
cards.add(new SetCardInfo("Fledgling Osprey", 33, Rarity.COMMON, mage.cards.f.FledglingOsprey.class));
cards.add(new SetCardInfo("Flicker", 9, Rarity.RARE, mage.cards.f.Flicker.class));
cards.add(new SetCardInfo("Fodder Cannon", 131, Rarity.UNCOMMON, mage.cards.f.FodderCannon.class));
cards.add(new SetCardInfo("Gamekeeper", 106, Rarity.UNCOMMON, mage.cards.g.Gamekeeper.class));

View file

@ -171,27 +171,70 @@ public class CascadeTest extends CardTestPlayerBase {
public void testHaveToPayAdditionalCosts() {
playerA.getLibrary().clear();
// Choose one - You draw five cards and you lose 5 life;
// or put an X/X black Demon creature token with flying onto the battlefield, where X is the number of cards in your hand as the token enters the battlefield.
// Choose one -
// - You draw five cards and you lose 5 life;
// - put an X/X black Demon creature token with flying onto the battlefield, where X is the number of cards in your hand as the token enters the battlefield.
// Entwine {4} (Choose both if you pay the entwine cost.)
addCard(Zone.LIBRARY, playerA, "Promise of Power", 1);
// addCard(Zone.LIBRARY, playerA, "Silvercoat Lion", 2);
addCard(Zone.LIBRARY, playerA, "Mountain", 5);
// addCard(Zone.LIBRARY, playerA, "Silvercoat Lion", 2);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
// Cascade
// Cascade (When you cast this spell, exile cards from the top of your library until you exile a nonland card that costs less.
// You may cast it without paying its mana cost. Put the exiled cards on the bottom in a random order.)
addCard(Zone.HAND, playerA, "Enlisted Wurm"); // Creature {4}{G}{W} 5/5
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Enlisted Wurm");
setChoice(playerA, "Yes"); // Use cascade on Promise of Power
setChoice(playerA, "No"); // Pay no Entwine
setModeChoice(playerA, "1");
setStopAt(1, PhaseStep.END_TURN);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Enlisted Wurm", 1);
assertLife(playerA, 15);
assertHandCount(playerA, 5);
assertPermanentCount(playerA, "Demon", 0);
assertPermanentCount(playerA, "Enlisted Wurm", 1);
}
/**
* Cascade dont work with split cards.
*
* For example: Ardent Plea + Breaking/Entering
*/
@Test
public void testWithSplitSpell() {
playerA.getLibrary().clear();
// Breaking - Target player puts the top eight cards of his or her library into his or her graveyard.
// Entering - Put a creature card from a graveyard onto the battlefield under your control. It gains haste until end of turn.
// Fuse (You may cast one or both halves of this card from your hand.)
addCard(Zone.LIBRARY, playerA, "Breaking // Entering", 1); // Sorcery {U}{B} // {4}{U}{B}
// addCard(Zone.LIBRARY, playerA, "Silvercoat Lion", 2);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
// Exalted (Whenever a creature you control attacks alone, that creature gets +1/+1 until end of turn.)
// Cascade (When you cast this spell, exile cards from the top of your library until you exile a nonland card that costs less. You may cast it without paying its mana cost. Put the exiled cards on the bottom in a random order.)
addCard(Zone.HAND, playerA, "Ardent Plea"); // Enchantment {1}{W}{U}
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ardent Plea");
setChoice(playerA, "Yes");
addTarget(playerA, playerB);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Ardent Plea", 1);
assertGraveyardCount(playerA, "Breaking // Entering", 1);
assertGraveyardCount(playerB, 8);
}
}

View file

@ -79,9 +79,11 @@ 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.
* 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() {
@ -124,6 +126,48 @@ public class GontiLordOfLuxuryEffectTest extends CardTestPlayerBase {
assertPowerToughness(playerB, "Silvercoat Lion", 3, 3);
}
/**
* I noticed in a game that when you cast Lingering Souls off of Gonti, Lord
* of Luxury and then the lingering souls goes to the graveyard it cannot be
* flashed back. The gonti was my opponent's and the lingering souls was
* mine for reference.
*/
@Test
public void testCanBeCastLaterWithFlashBack() {
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 7);
// 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}
// Create two 1/1 white Spirit creature tokens with flying.
// Flashback {1}{B}
addCard(Zone.LIBRARY, playerB, "Lingering Souls"); // Sorcery {2}{W}
skipInitShuffling();
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Gonti, Lord of Luxury");
addTarget(playerA, playerB);
setChoice(playerA, "Lingering Souls");
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lingering Souls");
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Flashback");
setStopAt(2, PhaseStep.BEGIN_COMBAT);
execute();
assertPermanentCount(playerA, "Gonti, Lord of Luxury", 1);
assertPowerToughness(playerA, "Gonti, Lord of Luxury", 2, 3);
assertPermanentCount(playerA, "Spirit", 2);
assertPermanentCount(playerB, "Spirit", 2);
assertExileCount("Lingering Souls", 1);
}
}

View file

@ -30,7 +30,6 @@ package mage.abilities;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.MageObject;
import mage.MageObjectReference;
import mage.Mana;
@ -39,6 +38,7 @@ import mage.abilities.costs.AlternativeSourceCosts;
import mage.abilities.costs.Cost;
import mage.abilities.costs.Costs;
import mage.abilities.costs.CostsImpl;
import mage.abilities.costs.OptionalAdditionalModeSourceCosts;
import mage.abilities.costs.OptionalAdditionalSourceCosts;
import mage.abilities.costs.VariableCost;
import mage.abilities.costs.common.TapSourceCost;
@ -50,8 +50,8 @@ import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect;
import mage.abilities.effects.Effects;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.BasicManaEffect;
import mage.abilities.effects.common.DynamicManaEffect;
import mage.abilities.effects.common.ManaEffect;
import mage.abilities.keyword.FlashbackAbility;
import mage.abilities.mana.ActivatedManaAbilityImpl;
import mage.cards.Card;
@ -284,6 +284,9 @@ public abstract class AbilityImpl implements Ability {
this.getManaCostsToPay().clear();
}
}
if (modes.getAdditionalCost() != null) {
((OptionalAdditionalModeSourceCosts) modes.getAdditionalCost()).addOptionalAdditionalModeCosts(this, game);
}
// 20130201 - 601.2b
// If the spell has alternative or additional costs that will be paid as it's being cast such
// as buyback, kicker, or convoke costs (see rules 117.8 and 117.9), the player announces his
@ -415,8 +418,8 @@ public abstract class AbilityImpl implements Ability {
Effect effect = getEffects().get(0);
if (effect instanceof DynamicManaEffect) {
mana = ((DynamicManaEffect) effect).getMana(game, this);
} else if (effect instanceof BasicManaEffect) {
mana = ((BasicManaEffect) effect).getMana(game, this);
} else if (effect instanceof ManaEffect) {
mana = ((ManaEffect) effect).getMana(game, this);
}
if (mana != null && mana.getAny() == 0) { // if mana == null or Any > 0 the event has to be fired in the mana effect to know which mana was produced
ManaEvent event = new ManaEvent(GameEvent.EventType.TAPPED_FOR_MANA, sourceId, sourceId, controllerId, mana);

View file

@ -56,6 +56,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
private boolean eachModeMoreThanOnce; // each mode can be selected multiple times during one choice
private boolean eachModeOnlyOnce; // state if each mode can be chosen only once as long as the source object exists
private final LinkedHashMap<UUID, Mode> duplicateModes = new LinkedHashMap<>();
private OptionalAdditionalModeSourceCosts optionalAdditionalModeSourceCosts = null; // only set if costs have to be paid
public Modes() {
this.currentMode = new Mode();
@ -87,6 +88,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
this.modeChooser = modes.modeChooser;
this.eachModeOnlyOnce = modes.eachModeOnlyOnce;
this.eachModeMoreThanOnce = modes.eachModeMoreThanOnce;
this.optionalAdditionalModeSourceCosts = modes.optionalAdditionalModeSourceCosts;
}
public Modes copy() {
@ -186,7 +188,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
if (card != null) {
for (Ability modeModifyingAbility : card.getAbilities()) {
if (modeModifyingAbility instanceof OptionalAdditionalModeSourceCosts) {
((OptionalAdditionalModeSourceCosts) modeModifyingAbility).addOptionalAdditionalModeCosts(source, game);
((OptionalAdditionalModeSourceCosts) modeModifyingAbility).changeModes(source, game);
}
}
}
@ -385,4 +387,12 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
this.eachModeMoreThanOnce = eachModeMoreThanOnce;
}
public OptionalAdditionalModeSourceCosts getAdditionalCost() {
return optionalAdditionalModeSourceCosts;
}
public void setAdditionalCost(OptionalAdditionalModeSourceCosts optionalAdditionalModeSourceCosts) {
this.optionalAdditionalModeSourceCosts = optionalAdditionalModeSourceCosts;
}
}

View file

@ -34,9 +34,11 @@ import mage.game.Game;
*
* @author LevelX2
*/
public interface OptionalAdditionalModeSourceCosts {
void addOptionalAdditionalModeCosts(Ability ability, Game game);
void changeModes(Ability ability, Game game);
String getCastMessageSuffix();
}

View file

@ -33,6 +33,7 @@ import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.cards.SplitCard;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
@ -120,14 +121,13 @@ class CascadeEffect extends OneShotEffect {
break;
}
controller.moveCardsToExile(card, source, game, true, exile.getId(), exile.getName());
} while (controller.isInGame() && card.getCardType().contains(CardType.LAND) || card.getConvertedManaCost() >= sourceCost);
} while (controller.isInGame() && (card.getCardType().contains(CardType.LAND) || !cardThatCostsLess(sourceCost, card, game)));
controller.getLibrary().reset(); // set back empty draw state if that caused an empty draw
if (card != null) {
if (controller.chooseUse(outcome, "Use cascade effect on " + card.getLogName() + "?", source, game)) {
if (controller.cast(card.getSpellAbility(), game, true)) {
exile.remove(card.getId());
}
controller.cast(card.getSpellAbility(), game, true);
}
}
// Move the remaining cards to the buttom of the library in a random order
@ -148,4 +148,12 @@ class CascadeEffect extends OneShotEffect {
return new CascadeEffect(this);
}
private boolean cardThatCostsLess(int value, Card card, Game game) {
if (card instanceof SplitCard) {
return ((SplitCard) card).getLeftHalfCard().getConvertedManaCost() < value
|| ((SplitCard) card).getRightHalfCard().getConvertedManaCost() < value;
} else {
return card.getConvertedManaCost() < value;
}
}
}

View file

@ -105,22 +105,17 @@ public class EntwineAbility extends StaticAbility implements OptionalAdditionalM
}
@Override
public void addOptionalAdditionalModeCosts(Ability ability, Game game) {
public void changeModes(Ability ability, Game game) {
if (ability instanceof SpellAbility) {
Player player = game.getPlayer(controllerId);
if (player != null) {
this.resetCosts();
if (additionalCost != null) {
if (player.chooseUse(Outcome.Benefit, "Pay " + additionalCost.getText(false) + " ?", ability, game)) {
if (additionalCost.canPay(ability, ability.getSourceId(), ability.getControllerId(), game)
&& player.chooseUse(Outcome.Benefit, "Pay " + additionalCost.getText(false) + " ?", ability, game)) {
additionalCost.activate();
for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext();) {
Cost cost = (Cost) it.next();
if (cost instanceof ManaCostsImpl) {
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
} else {
ability.getCosts().add(cost.copy());
}
}
ability.getModes().setAdditionalCost(this);
ability.getModes().setMinModes(2);
ability.getModes().setMaxModes(2);
}
@ -129,6 +124,20 @@ public class EntwineAbility extends StaticAbility implements OptionalAdditionalM
}
}
@Override
public void addOptionalAdditionalModeCosts(Ability ability, Game game) {
if (additionalCost.isActivated()) {
for (Iterator it = ((Costs) additionalCost).iterator(); it.hasNext();) {
Cost cost = (Cost) it.next();
if (cost instanceof ManaCostsImpl) {
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
} else {
ability.getCosts().add(cost.copy());
}
}
}
}
@Override
public String getRule() {
StringBuilder sb = new StringBuilder();

View file

@ -275,7 +275,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
@Override
public Abilities<Ability> getAbilities(Game game) {
Abilities<Ability> otherAbilities = game.getState().getAllOtherAbilities(objectId);
if (otherAbilities == null) {
if (otherAbilities == null || otherAbilities.isEmpty()) {
return abilities;
}
Abilities<Ability> all = new AbilitiesImpl<>();

View file

@ -30,11 +30,16 @@ package mage.cards.repository;
import com.j256.ormlite.field.DataType;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility;
import mage.cards.Card;
import mage.cards.CardGraphicInfo;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.FrameStyle;
@ -45,11 +50,6 @@ import mage.constants.Rarity;
import mage.constants.SpellAbilityType;
import org.apache.log4j.Logger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
*
* @author North
@ -205,7 +205,7 @@ public class CardInfo {
}
public Card getCard() {
return CardImpl.createCard(className, new CardSetInfo(name, setCode, cardNumber, rarity));
return CardImpl.createCard(className, new CardSetInfo(name, setCode, cardNumber, rarity, new CardGraphicInfo(FrameStyle.valueOf(frameStyle), variousArt)));
}
public Card getMockCard() {
@ -216,7 +216,9 @@ public class CardInfo {
}
}
public boolean usesVariousArt() { return variousArt; }
public boolean usesVariousArt() {
return variousArt;
}
public ObjectColor getColor() {
ObjectColor color = new ObjectColor();